[
  {
    "path": ".gitattributes",
    "content": "# Auto detect text files and perform LF normalization\n* text=auto\n\n# Custom for Visual Studio\n*.cs     diff=csharp\n\n# Standard to msysgit\n*.doc\t diff=astextplain\n*.DOC\t diff=astextplain\n*.docx diff=astextplain\n*.DOCX diff=astextplain\n*.dot  diff=astextplain\n*.DOT  diff=astextplain\n*.pdf  diff=astextplain\n*.PDF\t diff=astextplain\n*.rtf\t diff=astextplain\n*.RTF\t diff=astextplain\n"
  },
  {
    "path": ".github/FUNDING.yml",
    "content": "patreon: Rinnegatamante\n"
  },
  {
    "path": ".gitignore",
    "content": "# Windows image file caches\nThumbs.db\nehthumbs.db\n\n# Folder config file\nDesktop.ini\n\n# Recycle Bin used on file shares\n$RECYCLE.BIN/\n\n# Windows Installer files\n*.cab\n*.msi\n*.msm\n*.msp\n\n# Windows shortcuts\n*.lnk\n\n# =========================\n# Operating System Files\n# =========================\n\n# OSX\n# =========================\n\n.DS_Store\n.AppleDouble\n.LSOverride\n\n# Thumbnails\n._*\n\n# Files that might appear on external disk\n.Spotlight-V100\n.Trashes\n\n# Directories potentially created on remote AFP share\n.AppleDB\n.AppleDesktop\nNetwork Trash Folder\nTemporary Items\n.apdisk\n\n# c object files and other build files\n*.o\n*.elf\nbuild/eboot.bin\nbuild/sce_sys/param.sfo\nbuildeboot.bin\nparam.sfo\n*.velf\n*.vpk\n\n\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  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\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions 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 convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU 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\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<http://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<http://www.gnu.org/philosophy/why-not-lgpl.html>.\n"
  },
  {
    "path": "Makefile",
    "content": "TARGET\t\t:= vitaQuake\nTITLE\t\t:= QUAK00001\nGIT_VERSION := $(shell git describe --abbrev=6 --dirty --always --tags)\nSHADERS     := shaders\n\nLIBS = -lvitaGL -lvitashark -lSceShaccCgExt -ltaihen_stub -lvorbisfile -lvorbis -logg \\\n\t-lspeexdsp -lmpg123 -lScePspnetAdhoc_stub -lSceShaccCg_stub -lSceKernelDmacMgr_stub \\\n\t-lc -lSceCommonDialog_stub -lSceAudio_stub -lSceLibKernel_stub -lmathneon \\\n\t-lSceNet_stub -lSceNetCtl_stub -lpng -lSceDisplay_stub -lSceGxm_stub \\\n\t-Wl,--whole-archive -lSceSysmodule_stub -Wl,--no-whole-archive \\\n\t-lSceCtrl_stub -lSceTouch_stub -lSceMotion_stub -lm -lSceAppMgr_stub \\\n\t-lSceAppUtil_stub -lScePgf_stub -ljpeg -lSceRtc_stub -lScePower_stub -lcurl -lssl -lcrypto -lz\n\nCOMMON_OBJS =\tsource/chase.o \\\n\tsource/cl_demo.o \\\n\tsource/cl_input.o \\\n\tsource/cl_main.o \\\n\tsource/cl_parse.o \\\n\tsource/cl_tent.o \\\n\tsource/chase.o \\\n\tsource/cmd.o \\\n\tsource/common.o \\\n\tsource/console.o \\\n\tsource/crc.o \\\n\tsource/cvar.o \\\n\tsource/host.o \\\n\tsource/host_cmd.o \\\n\tsource/image.o \\\n\tsource/keys.o \\\n\tsource/mathlib.o \\\n\tsource/menu.o \\\n\tsource/net_dgrm.o \\\n\tsource/net_loop.o \\\n\tsource/net_main.o \\\n\tsource/net_vcr.o \\\n\tsource/pr_cmds.o \\\n\tsource/pr_edict.o \\\n\tsource/pr_exec.o \\\n\tsource/r_part.o \\\n\tsource/sbar.o \\\n\tsource/sv_main.o \\\n\tsource/sv_move.o \\\n\tsource/sv_phys.o \\\n\tsource/sv_user.o \\\n\tsource/view.o \\\n\tsource/wad.o \\\n\tsource/world.o \\\n\tsource/zone.o \\\n\tsource/sys_psp2.o \\\n\tsource/gl_draw.o \\\n\tsource/gl_mesh.o \\\n\tsource/gl_model.o \\\n\tsource/gl_refrag.o \\\n\tsource/gl_rlight.o \\\n\tsource/gl_rmain.o \\\n\tsource/gl_rmisc.o \\\n\tsource/gl_rsurf.o \\\n\tsource/gl_screen.o \\\n\tsource/gl_warp.o \\\n\tsource/gl_fullbright.o \\\n\tsource/r_part.o \\\n\tsource/snd_dma.o \\\n\tsource/snd_mix.o \\\n\tsource/snd_mem.o \\\n\tsource/snd_psp2.o \\\n\tsource/net_psp2.o \\\n\tsource/net_adhoc_psp2.o \\\n\tsource/net_udp_psp2.o \\\n\tsource/in_psp2.o \\\n\tsource/gl_vidpsp2.o \\\n\tsource/neon_mathfun.o \\\n\tsource/webdownload.o\n\t\nCPPSOURCES\t:= source/audiodec\n\nCFILES\t:= $(COMMON_OBJS)\nCPPFILES   := $(foreach dir,$(CPPSOURCES), $(wildcard $(dir)/*.cpp))\nCGFILES  := $(foreach dir,$(SHADERS), $(wildcard $(dir)/*.cg))\nCGSHADERS  := $(CGFILES:.cg=.h)\nOBJS     := $(CFILES:.c=.o) $(CPPFILES:.cpp=.o)\n\nPREFIX  = arm-vita-eabi\nCC      = $(PREFIX)-gcc\nCXX      = $(PREFIX)-g++\nCFLAGS  = -fsigned-char -Wl,-q -O3 -g -fno-optimize-sibling-calls \\\n\t-ffast-math -mtune=cortex-a9 -mfpu=neon \\\n\t-DGLQUAKE -DHAVE_OGGVORBIS -DHAVE_MPG123 -DHAVE_LIBSPEEXDSP \\\n\t-DUSE_AUDIO_RESAMPLER -DGIT_VERSION=\\\"$(GIT_VERSION)\\\"\nCXXFLAGS  = $(CFLAGS) -fno-exceptions -std=gnu++11\nASFLAGS = $(CFLAGS)\n\nall: $(TARGET).vpk\n\n$(TARGET).vpk: $(TARGET).velf\n\tvita-make-fself -c -s $< build/eboot.bin\n\tvita-mksfoex -s TITLE_ID=$(TITLE) -d ATTRIBUTE2=12 \"$(TARGET)\" param.sfo\n\tcp -f param.sfo build/sce_sys/param.sfo\n\tvita-pack-vpk -s param.sfo -b build/eboot.bin $(TARGET).vpk \\\n\t\t-a build/shaders=shaders \\\n\t\t-a build/sce_sys=sce_sys\n\n%_f.h:\n\tpsp2cgc -profile sce_fp_psp2 $(@:_f.h=_f.cg) -Wperf -fastprecision -O3 -o build/$(@:_f.h=_f.gxp)\n\t\n%_v.h:\n\tpsp2cgc -profile sce_vp_psp2 $(@:_v.h=_v.cg) -Wperf -fastprecision -O3 -o build/$(@:_v.h=_v.gxp)\n\t\nshaders: $(CGSHADERS)\n\t\n%.velf: %.elf\n\tcp $< $<.unstripped.elf\n\t$(PREFIX)-strip -g $<\n\tvita-elf-create $< $@\n\n$(TARGET).elf: $(OBJS)\n\t$(CXX) $(CXXFLAGS) $^ $(LIBS) -o $@\n\nclean:\n\t@rm -rf $(TARGET).velf $(TARGET).elf $(OBJS) $(TARGET).elf.unstripped.elf $(TARGET).vpk build/eboot.bin build/sce_sys/param.sfo ./param.sfo\n"
  },
  {
    "path": "README.md",
    "content": "# Introduction\nvitaQuake is a Quake engine source port for PSVITA.\n\nAn official channel to discuss the development of this source port can be found on [Vita Nuova discord server](https://discord.gg/PyCaBx9).\n\n# Features\n- Hardware accelerated GPU rendering\n- Native 960x544 resolution\n- Rendering resolution up to 1920x1080 on the PSTV with [Sharpscale](https://git.shotatoshounenwachigau.moe/vita/sharpscale)\n- MSAA 2x and MSAA 4x support\n- Dual analogs support\n- Native IME for inputing commands/text\n- Sounds and Musics (CDTracks) support in OGG, MP3, WAV formats\n- Gyroscope and touchscreen support for camera movement\n- Custom arguments support and mods support\n- Support for both official missionpacks\n- Support for transparent surfaces (.alpha and .renderamt)\n- Increased Quake Engine limits (max vertices, max entities, max static entities, etc...)\n- LAN Multiplayer support (locale and online)\n- AdHoc Multiplayer support\n- ProQuake net protocol support\n- Savegames fully working\n- Support for colored lights with .lit files support\n- Support for Half-Life BSP\n- Supprt for BSP2 and 2BSP formats\n- Smooth animations thanks to interpolation techniques\n- Crosshair and custom crosshairs support\n- Mirrors support\n- Specular mode support\n- Fog support\n- Cel Shading support\n- Bilinear filtering support\n- Dynamic shadows support\n- Several different improvements in the renderer quality\n- Several different miscellaneous features (eg: transparent statusbar, benchmark feature, working gamma, etc...)\n- Map downloader support if you try to join an online server and you don't own the running map\n\n# Supported DarkPlaces extensions\n- DP_CON_SET\n- DP_CON_SETA\n- DP_EF_BLUE\n- DP_EF_NODRAW\n- DP_EF_RED\n- DP_ENT_ALPHA\n- DP_GFX_EXTERNALTEXTURES\n- DP_GFX_EXTERNALTEXTURES_PERMAPTEXTURES\n- DP_HALFLIFE_MAP\n- DP_LITSUPPORT\n- DP_QC_ASINACOSATANATAN2TAN\n- DP_QC_COPYENTITY\n- DP_QC_CVAR_STRING\n- DP_QC_EDICT_NUM\n- DP_QC_ETOS\n- DP_QC_FINDCHAIN\n- DP_QC_FINDCHAINFLOAT\n- DP_QC_MINMAXBOUND\n- DP_QC_NUM_FOR_EDICT\n- DP_QC_RANDOMVEC\n- DP_QC_SINCOSSQRTPOW\n- DP_QC_TRACEBOX\n- DP_SND_FAKETRACKS\n- DP_SV_MODELFLAGS_AS_EFFECTS\n- DP_SV_NODRAWTOCLIENT\n- DP_SV_DRAWONLYTOCLIENT\n- EXT_BITSHIFT\n- FRIK_FILE\n\n# CDAudio Support\n\nvitaQuake supports all soundtrack packs for Quake and its two official mission packs, \"Scourge of Armagon\" and \"Dissolution of Eternity.\" In order for the soundtrack to work, files must be placed in a folder named /cdtracks/ in each campaign folder (main game for example will be ux0:data/Quake/id1/cdtracks). \n\nBy default, the music folder has tracks named as track02, track03, etc. For vitaQuake, add an extra \"0\" after \"track\" in order for them to be loaded properly and in order. **Ex.: track02 -> track002**\n\nYou can find the official soundtrack for the main campaign in .ogg format [here](https://www.quaddicted.com/files/music/quake_music.zip).\n\n# Loading Expansions and Mods\n\nvitaQuake supports the official Quake expansions, \"Scourge of Armagon\" and \"Dissolution of Eternity.\" These were offical expansions, so they can be found usually wherever the full base game is sold (GOG, Steam). In order to get them to load properly, place them in the \"ux0:/data/quake/\" folder alongside \"id1\". \n\nBoth official mission packs support their own soundtracks as long as they are placed properly in their respective \"/cdtracks/\" folder.\n\nMod compatibility is varied, but as a general rule of thumb, mods compatible with winQuake will be compatible with vitaQuake.\n\nHere's a list of some popular mods and their actual working state:\n\nExpansion/Mod | Link | Status\n---|---|---|\nDissolution of Eternity | Official Expansion | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Fully Working`\ndopa | [Free](https://twitter.com/machinegames/status/746363189768650752?lang=en) | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Fully Working`\nHalo Revamped | [Free](https://wololo.net/downloads/index.php/download/1376) | ![#d0d000](https://placehold.it/15/d0d000/000000?text=+) `Boots, lots of bugs`\nKurok | [Free](http://www.bladebattles.com/kurok/) | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Playable with glitches`\nNazi Zombies Portable | [Free](https://www.moddb.com/games/nazi-zombies-portable/news/nazi-zombies-portable-ps-vita-info) | ![#ff0000](https://placehold.it/15/ff0000/000000?text=+) `Not Working`\nQuake Rally | [Free](https://www.moddb.com/mods/quake-rally) | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Fully Working`\nScourge of Armagon | Official Expansion | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Fully Working`\nSlayer's Testament | [Free](https://www.youtube.com/watch?v=abn9aCiJ3pY) | ![#ff0000](https://placehold.it/15/ff0000/000000?text=+) `Crash on models loading`\nSUPERHOT Quake | [Free](https://www.moddb.com/mods/superhot-quake) | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Working without monochromatic graphics`\nSUPERQOT | [Free](https://superhotgame.com/SUPERQOT/) | ![#ff0000](https://placehold.it/15/ff0000/000000?text=+) `Not Working`\nYPOD | [Free](https://www.quakewiki.net/archives/doom/) | ![#007f00](https://placehold.it/15/007f00/000000?text=+) `Fully Working`\n\n# Credits\n- idSoftware for winQuake sourcecode\n- MasterFeizz for ctrQuake sourcecode i studied to understand how winQuake works\n- EasyRPG Team for the audio decoder used for CDAudio support\n- Ch0wW for various improvements and code cleanup\n- JPG for ProQuake and some various fixes.\n- Cuevavirus for 1920x1080 rendering\n"
  },
  {
    "path": "build/sce_sys/livearea/contents/template.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\n<livearea style=\"a1\" format-ver=\"01.00\" content-rev=\"1\">\n\t<livearea-background>\n\t\t<image>bg.png</image>\n\t</livearea-background>\n\t\n\t<gate>\n\t\t<startup-image>startup.png</startup-image>\n\t</gate>\n\t\n\t<frame id='frame1' multi='o' autoflip='3' >\n\t\t<liveitem>\n\t\t\t<target>psla:-hipnotic</target>\n\t\t\t<image>hipnotic.png</image>\n\t\t</liveitem>\n\t</frame>\n\t\n\t<frame id='frame2' multi='o' autoflip='3' >\n\t\t<liveitem>\n\t\t\t<target>psla:-rogue</target>\n\t\t\t<image>rogue.png</image>\n\t\t</liveitem>\n\t</frame>\n\t\n\t<frame id=\"frame3\">\n\t\t<liveitem>\n\t\t\t<target>psla:-custom</target>\n\t\t\t<text valign=\"bottom\" align=\"left\" text-align=\"left\" word-wrap=\"off\" ellipsis=\"on\">\n\t\t\t\t<str size=\"20\" color=\"#ffffff\" shadow=\"on\">  Click here to launch with custom args</str>\n\t\t\t</text>\n\t\t</liveitem>\n\t</frame>\t\n\n</livearea>\n"
  },
  {
    "path": "shaders/modulate_alpha_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tuniform float4 vColor,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/modulate_alpha_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tuniform float4 vColor,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/modulate_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tuniform float4 vColor,\n\tuniform sampler2D tex\n\t)\n{\t\n\treturn tex2D(tex, vTexcoord) * vColor;\n}\n"
  },
  {
    "path": "shaders/modulate_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tuniform float4 vColor,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\treturn c;\n}\n"
  },
  {
    "path": "shaders/modulate_rgba_alpha_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat4 vColor : COLOR,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/modulate_rgba_alpha_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tfloat4 vColor : COLOR,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/modulate_rgba_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat4 vColor : COLOR,\n\tuniform sampler2D tex\n\t)\n{\t\n\treturn tex2D(tex, vTexcoord) * vColor;\n}\n"
  },
  {
    "path": "shaders/modulate_rgba_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tfloat4 vColor : COLOR,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord) * vColor;\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\treturn c;\n}\n"
  },
  {
    "path": "shaders/replace_alpha_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord);\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/replace_alpha_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord);\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\tif (c.a > 0.666) return c;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/replace_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tuniform sampler2D tex\n\t)\n{\t\n\treturn tex2D(tex, vTexcoord);\n}\n"
  },
  {
    "path": "shaders/replace_fog_f.cg",
    "content": "﻿float4 main(\n\tfloat2 vTexcoord : TEXCOORD0,\n\tfloat vFog : FOG,\n\tuniform sampler2D tex\n\t)\n{\t\n\tfloat4 c = tex2D(tex, vTexcoord);\n\t\n\tc.rgb = c.rgb * vFog;\n\t\n\treturn c;\n}\n"
  },
  {
    "path": "shaders/rgba_alpha_f.cg",
    "content": "float4 main(float4 vColor : COLOR) : COLOR\n{\n\tif (vColor.a > 0.666) return vColor;\n\telse discard;\n}\n"
  },
  {
    "path": "shaders/rgba_f.cg",
    "content": "float4 main(float4 vColor : COLOR) : COLOR\n{\n\treturn vColor;\n}\n"
  },
  {
    "path": "shaders/rgba_v.cg",
    "content": "void main(\n\tfloat3 aPosition,\n\tfloat4 aColor,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition: POSITION,\n\tfloat4 out vColor: COLOR)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(aPosition, 1.f));\n\tvColor = aColor;\n}\n"
  },
  {
    "path": "shaders/texture2d_fog_v.cg",
    "content": "﻿void main(\n\tfloat3 position,\n\tfloat2 texcoord,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition : POSITION,\n\tfloat out vFog : FOG,\n\tfloat2 out vTexcoord : TEXCOORD0)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(position, 1.f));\n\t\n\tfloat dist = distance(vPosition,float4(0.0,0.0,0.0,1.0));\n\tvFog = ((512.0 - dist) / (512.0));\n\t\n\tvTexcoord = texcoord;\n}\n"
  },
  {
    "path": "shaders/texture2d_rgba_fog_v.cg",
    "content": "void main(\n\tfloat3 position,\n\tfloat2 texcoord,\n\tfloat4 color,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition : POSITION,\n\tfloat out vFog : FOG,\n\tfloat2 out vTexcoord : TEXCOORD0,\n\tfloat4 out vColor : COLOR)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(position, 1.f));\n\t\n\tfloat dist = distance(vPosition,float4(0.0,0.0,0.0,1.0));\n\tvFog = ((512.0 - dist) / (512.0));\n\t\n\tvTexcoord = texcoord;\n\tvColor = color;\n}\n"
  },
  {
    "path": "shaders/texture2d_rgba_v.cg",
    "content": "void main(\n\tfloat3 position,\n\tfloat2 texcoord,\n\tfloat4 color,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition : POSITION,\n\tfloat2 out vTexcoord : TEXCOORD0,\n\tfloat4 out vColor : COLOR)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(position, 1.f));\n\tvTexcoord = texcoord;\n\tvColor = color;\n}\n"
  },
  {
    "path": "shaders/texture2d_v.cg",
    "content": "﻿void main(\n\tfloat3 position,\n\tfloat2 texcoord,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition : POSITION,\n\tfloat2 out vTexcoord : TEXCOORD0)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(position, 1.f));\n\tvTexcoord = texcoord;\n}\n"
  },
  {
    "path": "shaders/vertex_f.cg",
    "content": "float4 main(uniform float4 color) : COLOR\n{\n\treturn color;\n}\n"
  },
  {
    "path": "shaders/vertex_v.cg",
    "content": "void main(\n\tfloat3 aPosition,\n\tuniform float4x4 gl_ModelViewProjectionMatrix,\n\tfloat4 out vPosition: POSITION)\n{\n\tvPosition = mul(gl_ModelViewProjectionMatrix, float4(aPosition, 1.f));\n}\n"
  },
  {
    "path": "source/adivtab.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// table of quotients and remainders for [-15...16] / [-15...16]\n\n// numerator = -15\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{1, -5},\n{1, -6},\n{1, -7},\n{2, -1},\n{2, -3},\n{3, 0},\n{3, -3},\n{5, 0},\n{7, -1},\n{15, 0},\n{0, 0},\n{-15, 0},\n{-8, 1},\n{-5, 0},\n{-4, 1},\n{-3, 0},\n{-3, 3},\n{-3, 6},\n{-2, 1},\n{-2, 3},\n{-2, 5},\n{-2, 7},\n{-2, 9},\n{-2, 11},\n{-2, 13},\n{-1, 0},\n{-1, 1},\n// numerator = -14\n{0, -14},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{1, -5},\n{1, -6},\n{2, 0},\n{2, -2},\n{2, -4},\n{3, -2},\n{4, -2},\n{7, 0},\n{14, 0},\n{0, 0},\n{-14, 0},\n{-7, 0},\n{-5, 1},\n{-4, 2},\n{-3, 1},\n{-3, 4},\n{-2, 0},\n{-2, 2},\n{-2, 4},\n{-2, 6},\n{-2, 8},\n{-2, 10},\n{-2, 12},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n// numerator = -13\n{0, -13},\n{0, -13},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{1, -5},\n{1, -6},\n{2, -1},\n{2, -3},\n{3, -1},\n{4, -1},\n{6, -1},\n{13, 0},\n{0, 0},\n{-13, 0},\n{-7, 1},\n{-5, 2},\n{-4, 3},\n{-3, 2},\n{-3, 5},\n{-2, 1},\n{-2, 3},\n{-2, 5},\n{-2, 7},\n{-2, 9},\n{-2, 11},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n// numerator = -12\n{0, -12},\n{0, -12},\n{0, -12},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{1, -5},\n{2, 0},\n{2, -2},\n{3, 0},\n{4, 0},\n{6, 0},\n{12, 0},\n{0, 0},\n{-12, 0},\n{-6, 0},\n{-4, 0},\n{-3, 0},\n{-3, 3},\n{-2, 0},\n{-2, 2},\n{-2, 4},\n{-2, 6},\n{-2, 8},\n{-2, 10},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n// numerator = -11\n{0, -11},\n{0, -11},\n{0, -11},\n{0, -11},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{1, -5},\n{2, -1},\n{2, -3},\n{3, -2},\n{5, -1},\n{11, 0},\n{0, 0},\n{-11, 0},\n{-6, 1},\n{-4, 1},\n{-3, 1},\n{-3, 4},\n{-2, 1},\n{-2, 3},\n{-2, 5},\n{-2, 7},\n{-2, 9},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n// numerator = -10\n{0, -10},\n{0, -10},\n{0, -10},\n{0, -10},\n{0, -10},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{2, 0},\n{2, -2},\n{3, -1},\n{5, 0},\n{10, 0},\n{0, 0},\n{-10, 0},\n{-5, 0},\n{-4, 2},\n{-3, 2},\n{-2, 0},\n{-2, 2},\n{-2, 4},\n{-2, 6},\n{-2, 8},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n// numerator = -9\n{0, -9},\n{0, -9},\n{0, -9},\n{0, -9},\n{0, -9},\n{0, -9},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{1, -4},\n{2, -1},\n{3, 0},\n{4, -1},\n{9, 0},\n{0, 0},\n{-9, 0},\n{-5, 1},\n{-3, 0},\n{-3, 3},\n{-2, 1},\n{-2, 3},\n{-2, 5},\n{-2, 7},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n// numerator = -8\n{0, -8},\n{0, -8},\n{0, -8},\n{0, -8},\n{0, -8},\n{0, -8},\n{0, -8},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{2, 0},\n{2, -2},\n{4, 0},\n{8, 0},\n{0, 0},\n{-8, 0},\n{-4, 0},\n{-3, 1},\n{-2, 0},\n{-2, 2},\n{-2, 4},\n{-2, 6},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n// numerator = -7\n{0, -7},\n{0, -7},\n{0, -7},\n{0, -7},\n{0, -7},\n{0, -7},\n{0, -7},\n{0, -7},\n{1, 0},\n{1, -1},\n{1, -2},\n{1, -3},\n{2, -1},\n{3, -1},\n{7, 0},\n{0, 0},\n{-7, 0},\n{-4, 1},\n{-3, 2},\n{-2, 1},\n{-2, 3},\n{-2, 5},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n// numerator = -6\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{0, -6},\n{1, 0},\n{1, -1},\n{1, -2},\n{2, 0},\n{3, 0},\n{6, 0},\n{0, 0},\n{-6, 0},\n{-3, 0},\n{-2, 0},\n{-2, 2},\n{-2, 4},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n// numerator = -5\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{0, -5},\n{1, 0},\n{1, -1},\n{1, -2},\n{2, -1},\n{5, 0},\n{0, 0},\n{-5, 0},\n{-3, 1},\n{-2, 1},\n{-2, 3},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n{-1, 11},\n// numerator = -4\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{0, -4},\n{1, 0},\n{1, -1},\n{2, 0},\n{4, 0},\n{0, 0},\n{-4, 0},\n{-2, 0},\n{-2, 2},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n{-1, 11},\n{-1, 12},\n// numerator = -3\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{0, -3},\n{1, 0},\n{1, -1},\n{3, 0},\n{0, 0},\n{-3, 0},\n{-2, 1},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n{-1, 11},\n{-1, 12},\n{-1, 13},\n// numerator = -2\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{0, -2},\n{1, 0},\n{2, 0},\n{0, 0},\n{-2, 0},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n{-1, 11},\n{-1, 12},\n{-1, 13},\n{-1, 14},\n// numerator = -1\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{0, -1},\n{1, 0},\n{0, 0},\n{-1, 0},\n{-1, 1},\n{-1, 2},\n{-1, 3},\n{-1, 4},\n{-1, 5},\n{-1, 6},\n{-1, 7},\n{-1, 8},\n{-1, 9},\n{-1, 10},\n{-1, 11},\n{-1, 12},\n{-1, 13},\n{-1, 14},\n{-1, 15},\n// numerator = 0\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n{0, 0},\n// numerator = 1\n{-1, -14},\n{-1, -13},\n{-1, -12},\n{-1, -11},\n{-1, -10},\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{0, 0},\n{1, 0},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n{0, 1},\n// numerator = 2\n{-1, -13},\n{-1, -12},\n{-1, -11},\n{-1, -10},\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, 0},\n{0, 0},\n{2, 0},\n{1, 0},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n{0, 2},\n// numerator = 3\n{-1, -12},\n{-1, -11},\n{-1, -10},\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -1},\n{-3, 0},\n{0, 0},\n{3, 0},\n{1, 1},\n{1, 0},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n{0, 3},\n// numerator = 4\n{-1, -11},\n{-1, -10},\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -2},\n{-2, 0},\n{-4, 0},\n{0, 0},\n{4, 0},\n{2, 0},\n{1, 1},\n{1, 0},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n{0, 4},\n// numerator = 5\n{-1, -10},\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -3},\n{-2, -1},\n{-3, -1},\n{-5, 0},\n{0, 0},\n{5, 0},\n{2, 1},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n{0, 5},\n// numerator = 6\n{-1, -9},\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, 0},\n{-6, 0},\n{0, 0},\n{6, 0},\n{3, 0},\n{2, 0},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n{0, 6},\n// numerator = 7\n{-1, -8},\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -5},\n{-2, -3},\n{-2, -1},\n{-3, -2},\n{-4, -1},\n{-7, 0},\n{0, 0},\n{7, 0},\n{3, 1},\n{2, 1},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n{0, 7},\n// numerator = 8\n{-1, -7},\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -6},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, -1},\n{-4, 0},\n{-8, 0},\n{0, 0},\n{8, 0},\n{4, 0},\n{2, 2},\n{2, 0},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 8},\n{0, 8},\n{0, 8},\n{0, 8},\n{0, 8},\n{0, 8},\n{0, 8},\n{0, 8},\n// numerator = 9\n{-1, -6},\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -7},\n{-2, -5},\n{-2, -3},\n{-2, -1},\n{-3, -3},\n{-3, 0},\n{-5, -1},\n{-9, 0},\n{0, 0},\n{9, 0},\n{4, 1},\n{3, 0},\n{2, 1},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 9},\n{0, 9},\n{0, 9},\n{0, 9},\n{0, 9},\n{0, 9},\n{0, 9},\n// numerator = 10\n{-1, -5},\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -8},\n{-2, -6},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, -2},\n{-4, -2},\n{-5, 0},\n{-10, 0},\n{0, 0},\n{10, 0},\n{5, 0},\n{3, 1},\n{2, 2},\n{2, 0},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 10},\n{0, 10},\n{0, 10},\n{0, 10},\n{0, 10},\n{0, 10},\n// numerator = 11\n{-1, -4},\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -9},\n{-2, -7},\n{-2, -5},\n{-2, -3},\n{-2, -1},\n{-3, -4},\n{-3, -1},\n{-4, -1},\n{-6, -1},\n{-11, 0},\n{0, 0},\n{11, 0},\n{5, 1},\n{3, 2},\n{2, 3},\n{2, 1},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 11},\n{0, 11},\n{0, 11},\n{0, 11},\n{0, 11},\n// numerator = 12\n{-1, -3},\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -10},\n{-2, -8},\n{-2, -6},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, -3},\n{-3, 0},\n{-4, 0},\n{-6, 0},\n{-12, 0},\n{0, 0},\n{12, 0},\n{6, 0},\n{4, 0},\n{3, 0},\n{2, 2},\n{2, 0},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 12},\n{0, 12},\n{0, 12},\n{0, 12},\n// numerator = 13\n{-1, -2},\n{-1, -1},\n{-1, 0},\n{-2, -11},\n{-2, -9},\n{-2, -7},\n{-2, -5},\n{-2, -3},\n{-2, -1},\n{-3, -5},\n{-3, -2},\n{-4, -3},\n{-5, -2},\n{-7, -1},\n{-13, 0},\n{0, 0},\n{13, 0},\n{6, 1},\n{4, 1},\n{3, 1},\n{2, 3},\n{2, 1},\n{1, 6},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 13},\n{0, 13},\n{0, 13},\n// numerator = 14\n{-1, -1},\n{-1, 0},\n{-2, -12},\n{-2, -10},\n{-2, -8},\n{-2, -6},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, -4},\n{-3, -1},\n{-4, -2},\n{-5, -1},\n{-7, 0},\n{-14, 0},\n{0, 0},\n{14, 0},\n{7, 0},\n{4, 2},\n{3, 2},\n{2, 4},\n{2, 2},\n{2, 0},\n{1, 6},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 14},\n{0, 14},\n// numerator = 15\n{-1, 0},\n{-2, -13},\n{-2, -11},\n{-2, -9},\n{-2, -7},\n{-2, -5},\n{-2, -3},\n{-2, -1},\n{-3, -6},\n{-3, -3},\n{-3, 0},\n{-4, -1},\n{-5, 0},\n{-8, -1},\n{-15, 0},\n{0, 0},\n{15, 0},\n{7, 1},\n{5, 0},\n{3, 3},\n{3, 0},\n{2, 3},\n{2, 1},\n{1, 7},\n{1, 6},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n{0, 15},\n// numerator = 16\n{-2, -14},\n{-2, -12},\n{-2, -10},\n{-2, -8},\n{-2, -6},\n{-2, -4},\n{-2, -2},\n{-2, 0},\n{-3, -5},\n{-3, -2},\n{-4, -4},\n{-4, 0},\n{-6, -2},\n{-8, 0},\n{-16, 0},\n{0, 0},\n{16, 0},\n{8, 0},\n{5, 1},\n{4, 0},\n{3, 1},\n{2, 4},\n{2, 2},\n{2, 0},\n{1, 7},\n{1, 6},\n{1, 5},\n{1, 4},\n{1, 3},\n{1, 2},\n{1, 1},\n{1, 0},\n"
  },
  {
    "path": "source/anorm_dots.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n{\n{1.23,1.30,1.47,1.35,1.56,1.71,1.37,1.38,1.59,1.60,1.79,1.97,1.88,1.92,1.79,1.02,0.93,1.07,0.82,0.87,0.88,0.94,0.96,1.14,1.11,0.82,0.83,0.89,0.89,0.86,0.94,0.91,1.00,1.21,0.98,1.48,1.30,1.57,0.96,1.07,1.14,1.60,1.61,1.40,1.37,1.72,1.78,1.79,1.93,1.99,1.90,1.68,1.71,1.86,1.60,1.68,1.78,1.86,1.93,1.99,1.97,1.44,1.22,1.49,0.93,0.99,0.99,1.23,1.22,1.44,1.49,0.89,0.89,0.97,0.91,0.98,1.19,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.19,0.98,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.87,0.93,0.94,1.02,1.30,1.07,1.35,1.38,1.11,1.56,1.92,1.79,1.79,1.59,1.60,1.72,1.90,1.79,0.80,0.85,0.79,0.93,0.80,0.85,0.77,0.74,0.72,0.77,0.74,0.72,0.70,0.70,0.71,0.76,0.73,0.79,0.79,0.73,0.76,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.26,1.26,1.48,1.23,1.50,1.71,1.14,1.19,1.38,1.46,1.64,1.94,1.87,1.84,1.71,1.02,0.92,1.00,0.79,0.85,0.84,0.91,0.90,0.98,0.99,0.77,0.77,0.83,0.82,0.79,0.86,0.84,0.92,0.99,0.91,1.24,1.03,1.33,0.88,0.94,0.97,1.41,1.39,1.18,1.11,1.51,1.61,1.59,1.80,1.91,1.76,1.54,1.65,1.76,1.70,1.70,1.85,1.85,1.97,1.99,1.93,1.28,1.09,1.39,0.92,0.97,0.99,1.18,1.26,1.52,1.48,0.83,0.85,0.90,0.88,0.93,1.00,0.77,0.73,0.78,0.72,0.71,0.74,0.75,0.79,0.86,0.81,0.75,0.81,0.79,0.96,0.88,0.94,0.86,0.93,0.92,0.85,1.08,1.33,1.05,1.55,1.31,1.01,1.05,1.27,1.31,1.60,1.47,1.70,1.54,1.76,1.76,1.57,0.93,0.90,0.99,0.88,0.88,0.95,0.97,1.11,1.39,1.20,0.92,0.97,1.01,1.10,1.39,1.22,1.51,1.58,1.32,1.64,1.97,1.85,1.91,1.77,1.74,1.88,1.99,1.91,0.79,0.86,0.80,0.94,0.84,0.88,0.74,0.74,0.71,0.82,0.77,0.76,0.70,0.73,0.72,0.73,0.70,0.74,0.85,0.77,0.82,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.34,1.27,1.53,1.17,1.46,1.71,0.98,1.05,1.20,1.34,1.48,1.86,1.82,1.71,1.62,1.09,0.94,0.99,0.79,0.85,0.82,0.90,0.87,0.93,0.96,0.76,0.74,0.79,0.76,0.74,0.79,0.78,0.85,0.92,0.85,1.00,0.93,1.06,0.81,0.86,0.89,1.16,1.12,0.97,0.95,1.28,1.38,1.35,1.60,1.77,1.57,1.33,1.50,1.58,1.69,1.63,1.82,1.74,1.91,1.92,1.80,1.04,0.97,1.21,0.90,0.93,0.97,1.05,1.21,1.48,1.37,0.77,0.80,0.84,0.85,0.88,0.92,0.73,0.71,0.74,0.74,0.71,0.75,0.73,0.79,0.84,0.78,0.79,0.86,0.81,1.05,0.94,0.99,0.90,0.95,0.92,0.86,1.24,1.44,1.14,1.59,1.34,1.02,1.27,1.50,1.49,1.80,1.69,1.86,1.72,1.87,1.80,1.69,1.00,0.98,1.23,0.95,0.96,1.09,1.16,1.37,1.63,1.46,0.99,1.10,1.25,1.24,1.51,1.41,1.67,1.77,1.55,1.72,1.95,1.89,1.98,1.91,1.86,1.97,1.99,1.94,0.81,0.89,0.85,0.98,0.90,0.94,0.75,0.78,0.73,0.89,0.83,0.82,0.72,0.77,0.76,0.72,0.70,0.71,0.91,0.83,0.89,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.46,1.34,1.60,1.16,1.46,1.71,0.94,0.99,1.05,1.26,1.33,1.74,1.76,1.57,1.54,1.23,0.98,1.05,0.83,0.89,0.84,0.92,0.87,0.91,0.96,0.78,0.74,0.79,0.72,0.72,0.75,0.76,0.80,0.88,0.83,0.94,0.87,0.95,0.76,0.80,0.82,0.97,0.96,0.89,0.88,1.08,1.11,1.10,1.37,1.59,1.37,1.07,1.27,1.34,1.57,1.45,1.69,1.55,1.77,1.79,1.60,0.93,0.90,0.99,0.86,0.87,0.93,0.96,1.07,1.35,1.18,0.73,0.76,0.77,0.81,0.82,0.85,0.70,0.71,0.72,0.78,0.73,0.77,0.73,0.79,0.82,0.76,0.83,0.90,0.84,1.18,0.98,1.03,0.92,0.95,0.90,0.86,1.32,1.45,1.15,1.53,1.27,0.99,1.42,1.65,1.58,1.93,1.83,1.94,1.81,1.88,1.74,1.70,1.19,1.17,1.44,1.11,1.15,1.36,1.41,1.61,1.81,1.67,1.22,1.34,1.50,1.42,1.65,1.61,1.82,1.91,1.75,1.80,1.89,1.89,1.98,1.99,1.94,1.98,1.92,1.87,0.86,0.95,0.92,1.14,0.98,1.03,0.79,0.84,0.77,0.97,0.90,0.89,0.76,0.82,0.82,0.74,0.72,0.71,0.98,0.89,0.97,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.60,1.44,1.68,1.22,1.49,1.71,0.93,0.99,0.99,1.23,1.22,1.60,1.68,1.44,1.49,1.40,1.14,1.19,0.89,0.96,0.89,0.97,0.89,0.91,0.98,0.82,0.76,0.82,0.71,0.72,0.73,0.76,0.79,0.86,0.83,0.91,0.83,0.89,0.72,0.76,0.76,0.89,0.89,0.82,0.82,0.98,0.96,0.97,1.14,1.40,1.19,0.94,1.00,1.07,1.37,1.21,1.48,1.30,1.57,1.61,1.37,0.86,0.83,0.91,0.82,0.82,0.88,0.89,0.96,1.14,0.98,0.70,0.72,0.73,0.77,0.76,0.79,0.70,0.72,0.71,0.82,0.77,0.80,0.74,0.79,0.80,0.74,0.87,0.93,0.85,1.23,1.02,1.02,0.93,0.93,0.87,0.85,1.30,1.35,1.07,1.38,1.11,0.94,1.47,1.71,1.56,1.97,1.88,1.92,1.79,1.79,1.59,1.60,1.30,1.35,1.56,1.37,1.38,1.59,1.60,1.79,1.92,1.79,1.48,1.57,1.72,1.61,1.78,1.79,1.93,1.99,1.90,1.86,1.78,1.86,1.93,1.99,1.97,1.90,1.79,1.72,0.94,1.07,1.00,1.37,1.21,1.30,0.86,0.91,0.83,1.14,0.98,0.96,0.82,0.88,0.89,0.79,0.76,0.73,1.07,0.94,1.11,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.74,1.57,1.76,1.33,1.54,1.71,0.94,1.05,0.99,1.26,1.16,1.46,1.60,1.34,1.46,1.59,1.37,1.37,0.97,1.11,0.96,1.10,0.95,0.94,1.08,0.89,0.82,0.88,0.72,0.76,0.75,0.80,0.80,0.88,0.87,0.91,0.83,0.87,0.72,0.76,0.74,0.83,0.84,0.78,0.79,0.96,0.89,0.92,0.98,1.23,1.05,0.86,0.92,0.95,1.11,0.98,1.22,1.03,1.34,1.42,1.14,0.79,0.77,0.84,0.78,0.76,0.82,0.82,0.89,0.97,0.90,0.70,0.71,0.71,0.73,0.72,0.74,0.73,0.76,0.72,0.86,0.81,0.82,0.76,0.79,0.77,0.73,0.90,0.95,0.86,1.18,1.03,0.98,0.92,0.90,0.83,0.84,1.19,1.17,0.98,1.15,0.97,0.89,1.42,1.65,1.44,1.93,1.83,1.81,1.67,1.61,1.36,1.41,1.32,1.45,1.58,1.57,1.53,1.74,1.70,1.88,1.94,1.81,1.69,1.77,1.87,1.79,1.89,1.92,1.98,1.99,1.98,1.89,1.65,1.80,1.82,1.91,1.94,1.75,1.61,1.50,1.07,1.34,1.27,1.60,1.45,1.55,0.93,0.99,0.90,1.35,1.18,1.07,0.87,0.93,0.96,0.85,0.82,0.77,1.15,0.99,1.27,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.86,1.71,1.82,1.48,1.62,1.71,0.98,1.20,1.05,1.34,1.17,1.34,1.53,1.27,1.46,1.77,1.60,1.57,1.16,1.38,1.12,1.35,1.06,1.00,1.28,0.97,0.89,0.95,0.76,0.81,0.79,0.86,0.85,0.92,0.93,0.93,0.85,0.87,0.74,0.78,0.74,0.79,0.82,0.76,0.79,0.96,0.85,0.90,0.94,1.09,0.99,0.81,0.85,0.89,0.95,0.90,0.99,0.94,1.10,1.24,0.98,0.75,0.73,0.78,0.74,0.72,0.77,0.76,0.82,0.89,0.83,0.73,0.71,0.71,0.71,0.70,0.72,0.77,0.80,0.74,0.90,0.85,0.84,0.78,0.79,0.75,0.73,0.92,0.95,0.86,1.05,0.99,0.94,0.90,0.86,0.79,0.81,1.00,0.98,0.91,0.96,0.89,0.83,1.27,1.50,1.23,1.80,1.69,1.63,1.46,1.37,1.09,1.16,1.24,1.44,1.49,1.69,1.59,1.80,1.69,1.87,1.86,1.72,1.82,1.91,1.94,1.92,1.95,1.99,1.98,1.91,1.97,1.89,1.51,1.72,1.67,1.77,1.86,1.55,1.41,1.25,1.33,1.58,1.50,1.80,1.63,1.74,1.04,1.21,0.97,1.48,1.37,1.21,0.93,0.97,1.05,0.92,0.88,0.84,1.14,1.02,1.34,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.94,1.84,1.87,1.64,1.71,1.71,1.14,1.38,1.19,1.46,1.23,1.26,1.48,1.26,1.50,1.91,1.80,1.76,1.41,1.61,1.39,1.59,1.33,1.24,1.51,1.18,0.97,1.11,0.82,0.88,0.86,0.94,0.92,0.99,1.03,0.98,0.91,0.90,0.79,0.84,0.77,0.79,0.84,0.77,0.83,0.99,0.85,0.91,0.92,1.02,1.00,0.79,0.80,0.86,0.88,0.84,0.92,0.88,0.97,1.10,0.94,0.74,0.71,0.74,0.72,0.70,0.73,0.72,0.76,0.82,0.77,0.77,0.73,0.74,0.71,0.70,0.73,0.83,0.85,0.78,0.92,0.88,0.86,0.81,0.79,0.74,0.75,0.92,0.93,0.85,0.96,0.94,0.88,0.86,0.81,0.75,0.79,0.93,0.90,0.85,0.88,0.82,0.77,1.05,1.27,0.99,1.60,1.47,1.39,1.20,1.11,0.95,0.97,1.08,1.33,1.31,1.70,1.55,1.76,1.57,1.76,1.70,1.54,1.85,1.97,1.91,1.99,1.97,1.99,1.91,1.77,1.88,1.85,1.39,1.64,1.51,1.58,1.74,1.32,1.22,1.01,1.54,1.76,1.65,1.93,1.70,1.85,1.28,1.39,1.09,1.52,1.48,1.26,0.97,0.99,1.18,1.00,0.93,0.90,1.05,1.01,1.31,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.97,1.92,1.88,1.79,1.79,1.71,1.37,1.59,1.38,1.60,1.35,1.23,1.47,1.30,1.56,1.99,1.93,1.90,1.60,1.78,1.61,1.79,1.57,1.48,1.72,1.40,1.14,1.37,0.89,0.96,0.94,1.07,1.00,1.21,1.30,1.14,0.98,0.96,0.86,0.91,0.83,0.82,0.88,0.82,0.89,1.11,0.87,0.94,0.93,1.02,1.07,0.80,0.79,0.85,0.82,0.80,0.87,0.85,0.93,1.02,0.93,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.82,0.76,0.79,0.72,0.73,0.76,0.89,0.89,0.82,0.93,0.91,0.86,0.83,0.79,0.73,0.76,0.91,0.89,0.83,0.89,0.89,0.82,0.82,0.76,0.72,0.76,0.86,0.83,0.79,0.82,0.76,0.73,0.94,1.00,0.91,1.37,1.21,1.14,0.98,0.96,0.88,0.89,0.96,1.14,1.07,1.60,1.40,1.61,1.37,1.57,1.48,1.30,1.78,1.93,1.79,1.99,1.92,1.90,1.79,1.59,1.72,1.79,1.30,1.56,1.35,1.38,1.60,1.11,1.07,0.94,1.68,1.86,1.71,1.97,1.68,1.86,1.44,1.49,1.22,1.44,1.49,1.22,0.99,0.99,1.23,1.19,0.98,0.97,0.97,0.98,1.19,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.94,1.97,1.87,1.91,1.85,1.71,1.60,1.77,1.58,1.74,1.51,1.26,1.48,1.39,1.64,1.99,1.97,1.99,1.70,1.85,1.76,1.91,1.76,1.70,1.88,1.55,1.33,1.57,0.96,1.08,1.05,1.31,1.27,1.47,1.54,1.39,1.20,1.11,0.93,0.99,0.90,0.88,0.95,0.88,0.97,1.32,0.92,1.01,0.97,1.10,1.22,0.84,0.80,0.88,0.79,0.79,0.85,0.86,0.92,1.02,0.94,0.82,0.76,0.77,0.72,0.73,0.70,0.72,0.71,0.74,0.74,0.88,0.81,0.85,0.75,0.77,0.82,0.94,0.93,0.86,0.92,0.92,0.86,0.85,0.79,0.74,0.79,0.88,0.85,0.81,0.82,0.83,0.77,0.78,0.73,0.71,0.75,0.79,0.77,0.74,0.77,0.73,0.70,0.86,0.92,0.84,1.14,0.99,0.98,0.91,0.90,0.84,0.83,0.88,0.97,0.94,1.41,1.18,1.39,1.11,1.33,1.24,1.03,1.61,1.80,1.59,1.91,1.84,1.76,1.64,1.38,1.51,1.71,1.26,1.50,1.23,1.19,1.46,0.99,1.00,0.91,1.70,1.85,1.65,1.93,1.54,1.76,1.52,1.48,1.26,1.28,1.39,1.09,0.99,0.97,1.18,1.31,1.01,1.05,0.90,0.93,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.86,1.95,1.82,1.98,1.89,1.71,1.80,1.91,1.77,1.86,1.67,1.34,1.53,1.51,1.72,1.92,1.91,1.99,1.69,1.82,1.80,1.94,1.87,1.86,1.97,1.59,1.44,1.69,1.05,1.24,1.27,1.49,1.50,1.69,1.72,1.63,1.46,1.37,1.00,1.23,0.98,0.95,1.09,0.96,1.16,1.55,0.99,1.25,1.10,1.24,1.41,0.90,0.85,0.94,0.79,0.81,0.85,0.89,0.94,1.09,0.98,0.89,0.82,0.83,0.74,0.77,0.72,0.76,0.73,0.75,0.78,0.94,0.86,0.91,0.79,0.83,0.89,0.99,0.95,0.90,0.90,0.92,0.84,0.86,0.79,0.75,0.81,0.85,0.80,0.78,0.76,0.77,0.73,0.74,0.71,0.71,0.73,0.74,0.74,0.71,0.76,0.72,0.70,0.79,0.85,0.78,0.98,0.92,0.93,0.85,0.87,0.82,0.79,0.81,0.89,0.86,1.16,0.97,1.12,0.95,1.06,1.00,0.93,1.38,1.60,1.35,1.77,1.71,1.57,1.48,1.20,1.28,1.62,1.27,1.46,1.17,1.05,1.34,0.96,0.99,0.90,1.63,1.74,1.50,1.80,1.33,1.58,1.48,1.37,1.21,1.04,1.21,0.97,0.97,0.93,1.05,1.34,1.02,1.14,0.84,0.88,0.92,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.74,1.89,1.76,1.98,1.89,1.71,1.93,1.99,1.91,1.94,1.82,1.46,1.60,1.65,1.80,1.79,1.77,1.92,1.57,1.69,1.74,1.87,1.88,1.94,1.98,1.53,1.45,1.70,1.18,1.32,1.42,1.58,1.65,1.83,1.81,1.81,1.67,1.61,1.19,1.44,1.17,1.11,1.36,1.15,1.41,1.75,1.22,1.50,1.34,1.42,1.61,0.98,0.92,1.03,0.83,0.86,0.89,0.95,0.98,1.23,1.14,0.97,0.89,0.90,0.78,0.82,0.76,0.82,0.77,0.79,0.84,0.98,0.90,0.98,0.83,0.89,0.97,1.03,0.95,0.92,0.86,0.90,0.82,0.86,0.79,0.77,0.84,0.81,0.76,0.76,0.72,0.73,0.70,0.72,0.71,0.73,0.73,0.72,0.74,0.71,0.78,0.74,0.72,0.75,0.80,0.76,0.94,0.88,0.91,0.83,0.87,0.84,0.79,0.76,0.82,0.80,0.97,0.89,0.96,0.88,0.95,0.94,0.87,1.11,1.37,1.10,1.59,1.57,1.37,1.33,1.05,1.08,1.54,1.34,1.46,1.16,0.99,1.26,0.96,1.05,0.92,1.45,1.55,1.27,1.60,1.07,1.34,1.35,1.18,1.07,0.93,0.99,0.90,0.93,0.87,0.96,1.27,0.99,1.15,0.77,0.82,0.85,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.60,1.78,1.68,1.93,1.86,1.71,1.97,1.99,1.99,1.97,1.93,1.60,1.68,1.78,1.86,1.61,1.57,1.79,1.37,1.48,1.59,1.72,1.79,1.92,1.90,1.38,1.35,1.60,1.23,1.30,1.47,1.56,1.71,1.88,1.79,1.92,1.79,1.79,1.30,1.56,1.35,1.37,1.59,1.38,1.60,1.90,1.48,1.72,1.57,1.61,1.79,1.21,1.00,1.30,0.89,0.94,0.96,1.07,1.14,1.40,1.37,1.14,0.96,0.98,0.82,0.88,0.82,0.89,0.83,0.86,0.91,1.02,0.93,1.07,0.87,0.94,1.11,1.02,0.93,0.93,0.82,0.87,0.80,0.85,0.79,0.80,0.85,0.77,0.72,0.74,0.71,0.70,0.70,0.71,0.72,0.77,0.74,0.72,0.76,0.73,0.82,0.79,0.76,0.73,0.79,0.76,0.93,0.86,0.91,0.83,0.89,0.89,0.82,0.72,0.76,0.76,0.89,0.82,0.89,0.82,0.89,0.91,0.83,0.96,1.14,0.97,1.40,1.44,1.19,1.22,0.99,0.98,1.49,1.44,1.49,1.22,0.99,1.23,0.98,1.19,0.97,1.21,1.30,1.00,1.37,0.94,1.07,1.14,0.98,0.96,0.86,0.91,0.83,0.88,0.82,0.89,1.11,0.94,1.07,0.73,0.76,0.79,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.46,1.65,1.60,1.82,1.80,1.71,1.93,1.91,1.99,1.94,1.98,1.74,1.76,1.89,1.89,1.42,1.34,1.61,1.11,1.22,1.36,1.50,1.61,1.81,1.75,1.15,1.17,1.41,1.18,1.19,1.42,1.44,1.65,1.83,1.67,1.94,1.81,1.88,1.32,1.58,1.45,1.57,1.74,1.53,1.70,1.98,1.69,1.87,1.77,1.79,1.92,1.45,1.27,1.55,0.97,1.07,1.11,1.34,1.37,1.59,1.60,1.35,1.07,1.18,0.86,0.93,0.87,0.96,0.90,0.93,0.99,1.03,0.95,1.15,0.90,0.99,1.27,0.98,0.90,0.92,0.78,0.83,0.77,0.84,0.79,0.82,0.86,0.73,0.71,0.73,0.72,0.70,0.73,0.72,0.76,0.81,0.76,0.76,0.82,0.77,0.89,0.85,0.82,0.75,0.80,0.80,0.94,0.88,0.94,0.87,0.95,0.96,0.88,0.72,0.74,0.76,0.83,0.78,0.84,0.79,0.87,0.91,0.83,0.89,0.98,0.92,1.23,1.34,1.05,1.16,0.99,0.96,1.46,1.57,1.54,1.33,1.05,1.26,1.08,1.37,1.10,0.98,1.03,0.92,1.14,0.86,0.95,0.97,0.90,0.89,0.79,0.84,0.77,0.82,0.76,0.82,0.97,0.89,0.98,0.71,0.72,0.74,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.34,1.51,1.53,1.67,1.72,1.71,1.80,1.77,1.91,1.86,1.98,1.86,1.82,1.95,1.89,1.24,1.10,1.41,0.95,0.99,1.09,1.25,1.37,1.63,1.55,0.96,0.98,1.16,1.05,1.00,1.27,1.23,1.50,1.69,1.46,1.86,1.72,1.87,1.24,1.49,1.44,1.69,1.80,1.59,1.69,1.97,1.82,1.94,1.91,1.92,1.99,1.63,1.50,1.74,1.16,1.33,1.38,1.58,1.60,1.77,1.80,1.48,1.21,1.37,0.90,0.97,0.93,1.05,0.97,1.04,1.21,0.99,0.95,1.14,0.92,1.02,1.34,0.94,0.86,0.90,0.74,0.79,0.75,0.81,0.79,0.84,0.86,0.71,0.71,0.73,0.76,0.73,0.77,0.74,0.80,0.85,0.78,0.81,0.89,0.84,0.97,0.92,0.88,0.79,0.85,0.86,0.98,0.92,1.00,0.93,1.06,1.12,0.95,0.74,0.74,0.78,0.79,0.76,0.82,0.79,0.87,0.93,0.85,0.85,0.94,0.90,1.09,1.27,0.99,1.17,1.05,0.96,1.46,1.71,1.62,1.48,1.20,1.34,1.28,1.57,1.35,0.90,0.94,0.85,0.98,0.81,0.89,0.89,0.83,0.82,0.75,0.78,0.73,0.77,0.72,0.76,0.89,0.83,0.91,0.71,0.70,0.72,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00},\n{1.26,1.39,1.48,1.51,1.64,1.71,1.60,1.58,1.77,1.74,1.91,1.94,1.87,1.97,1.85,1.10,0.97,1.22,0.88,0.92,0.95,1.01,1.11,1.39,1.32,0.88,0.90,0.97,0.96,0.93,1.05,0.99,1.27,1.47,1.20,1.70,1.54,1.76,1.08,1.31,1.33,1.70,1.76,1.55,1.57,1.88,1.85,1.91,1.97,1.99,1.99,1.70,1.65,1.85,1.41,1.54,1.61,1.76,1.80,1.91,1.93,1.52,1.26,1.48,0.92,0.99,0.97,1.18,1.09,1.28,1.39,0.94,0.93,1.05,0.92,1.01,1.31,0.88,0.81,0.86,0.72,0.75,0.74,0.79,0.79,0.86,0.85,0.71,0.73,0.75,0.82,0.77,0.83,0.78,0.85,0.88,0.81,0.88,0.97,0.90,1.18,1.00,0.93,0.86,0.92,0.94,1.14,0.99,1.24,1.03,1.33,1.39,1.11,0.79,0.77,0.84,0.79,0.77,0.84,0.83,0.90,0.98,0.91,0.85,0.92,0.91,1.02,1.26,1.00,1.23,1.19,0.99,1.50,1.84,1.71,1.64,1.38,1.46,1.51,1.76,1.59,0.84,0.88,0.80,0.94,0.79,0.86,0.82,0.77,0.76,0.74,0.74,0.71,0.73,0.70,0.72,0.82,0.77,0.85,0.74,0.70,0.73,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00,1.00}\n}\n"
  },
  {
    "path": "source/anorms.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n{-0.525731, 0.000000, 0.850651}, \n{-0.442863, 0.238856, 0.864188}, \n{-0.295242, 0.000000, 0.955423}, \n{-0.309017, 0.500000, 0.809017}, \n{-0.162460, 0.262866, 0.951056}, \n{0.000000, 0.000000, 1.000000}, \n{0.000000, 0.850651, 0.525731}, \n{-0.147621, 0.716567, 0.681718}, \n{0.147621, 0.716567, 0.681718}, \n{0.000000, 0.525731, 0.850651}, \n{0.309017, 0.500000, 0.809017}, \n{0.525731, 0.000000, 0.850651}, \n{0.295242, 0.000000, 0.955423}, \n{0.442863, 0.238856, 0.864188}, \n{0.162460, 0.262866, 0.951056}, \n{-0.681718, 0.147621, 0.716567}, \n{-0.809017, 0.309017, 0.500000}, \n{-0.587785, 0.425325, 0.688191}, \n{-0.850651, 0.525731, 0.000000}, \n{-0.864188, 0.442863, 0.238856}, \n{-0.716567, 0.681718, 0.147621}, \n{-0.688191, 0.587785, 0.425325}, \n{-0.500000, 0.809017, 0.309017}, \n{-0.238856, 0.864188, 0.442863}, \n{-0.425325, 0.688191, 0.587785}, \n{-0.716567, 0.681718, -0.147621}, \n{-0.500000, 0.809017, -0.309017}, \n{-0.525731, 0.850651, 0.000000}, \n{0.000000, 0.850651, -0.525731}, \n{-0.238856, 0.864188, -0.442863}, \n{0.000000, 0.955423, -0.295242}, \n{-0.262866, 0.951056, -0.162460}, \n{0.000000, 1.000000, 0.000000}, \n{0.000000, 0.955423, 0.295242}, \n{-0.262866, 0.951056, 0.162460}, \n{0.238856, 0.864188, 0.442863}, \n{0.262866, 0.951056, 0.162460}, \n{0.500000, 0.809017, 0.309017}, \n{0.238856, 0.864188, -0.442863}, \n{0.262866, 0.951056, -0.162460}, \n{0.500000, 0.809017, -0.309017}, \n{0.850651, 0.525731, 0.000000}, \n{0.716567, 0.681718, 0.147621}, \n{0.716567, 0.681718, -0.147621}, \n{0.525731, 0.850651, 0.000000}, \n{0.425325, 0.688191, 0.587785}, \n{0.864188, 0.442863, 0.238856}, \n{0.688191, 0.587785, 0.425325}, \n{0.809017, 0.309017, 0.500000}, \n{0.681718, 0.147621, 0.716567}, \n{0.587785, 0.425325, 0.688191}, \n{0.955423, 0.295242, 0.000000}, \n{1.000000, 0.000000, 0.000000}, \n{0.951056, 0.162460, 0.262866}, \n{0.850651, -0.525731, 0.000000}, \n{0.955423, -0.295242, 0.000000}, \n{0.864188, -0.442863, 0.238856}, \n{0.951056, -0.162460, 0.262866}, \n{0.809017, -0.309017, 0.500000}, \n{0.681718, -0.147621, 0.716567}, \n{0.850651, 0.000000, 0.525731}, \n{0.864188, 0.442863, -0.238856}, \n{0.809017, 0.309017, -0.500000}, \n{0.951056, 0.162460, -0.262866}, \n{0.525731, 0.000000, -0.850651}, \n{0.681718, 0.147621, -0.716567}, \n{0.681718, -0.147621, -0.716567}, \n{0.850651, 0.000000, -0.525731}, \n{0.809017, -0.309017, -0.500000}, \n{0.864188, -0.442863, -0.238856}, \n{0.951056, -0.162460, -0.262866}, \n{0.147621, 0.716567, -0.681718}, \n{0.309017, 0.500000, -0.809017}, \n{0.425325, 0.688191, -0.587785}, \n{0.442863, 0.238856, -0.864188}, \n{0.587785, 0.425325, -0.688191}, \n{0.688191, 0.587785, -0.425325}, \n{-0.147621, 0.716567, -0.681718}, \n{-0.309017, 0.500000, -0.809017}, \n{0.000000, 0.525731, -0.850651}, \n{-0.525731, 0.000000, -0.850651}, \n{-0.442863, 0.238856, -0.864188}, \n{-0.295242, 0.000000, -0.955423}, \n{-0.162460, 0.262866, -0.951056}, \n{0.000000, 0.000000, -1.000000}, \n{0.295242, 0.000000, -0.955423}, \n{0.162460, 0.262866, -0.951056}, \n{-0.442863, -0.238856, -0.864188}, \n{-0.309017, -0.500000, -0.809017}, \n{-0.162460, -0.262866, -0.951056}, \n{0.000000, -0.850651, -0.525731}, \n{-0.147621, -0.716567, -0.681718}, \n{0.147621, -0.716567, -0.681718}, \n{0.000000, -0.525731, -0.850651}, \n{0.309017, -0.500000, -0.809017}, \n{0.442863, -0.238856, -0.864188}, \n{0.162460, -0.262866, -0.951056}, \n{0.238856, -0.864188, -0.442863}, \n{0.500000, -0.809017, -0.309017}, \n{0.425325, -0.688191, -0.587785}, \n{0.716567, -0.681718, -0.147621}, \n{0.688191, -0.587785, -0.425325}, \n{0.587785, -0.425325, -0.688191}, \n{0.000000, -0.955423, -0.295242}, \n{0.000000, -1.000000, 0.000000}, \n{0.262866, -0.951056, -0.162460}, \n{0.000000, -0.850651, 0.525731}, \n{0.000000, -0.955423, 0.295242}, \n{0.238856, -0.864188, 0.442863}, \n{0.262866, -0.951056, 0.162460}, \n{0.500000, -0.809017, 0.309017}, \n{0.716567, -0.681718, 0.147621}, \n{0.525731, -0.850651, 0.000000}, \n{-0.238856, -0.864188, -0.442863}, \n{-0.500000, -0.809017, -0.309017}, \n{-0.262866, -0.951056, -0.162460}, \n{-0.850651, -0.525731, 0.000000}, \n{-0.716567, -0.681718, -0.147621}, \n{-0.716567, -0.681718, 0.147621}, \n{-0.525731, -0.850651, 0.000000}, \n{-0.500000, -0.809017, 0.309017}, \n{-0.238856, -0.864188, 0.442863}, \n{-0.262866, -0.951056, 0.162460}, \n{-0.864188, -0.442863, 0.238856}, \n{-0.809017, -0.309017, 0.500000}, \n{-0.688191, -0.587785, 0.425325}, \n{-0.681718, -0.147621, 0.716567}, \n{-0.442863, -0.238856, 0.864188}, \n{-0.587785, -0.425325, 0.688191}, \n{-0.309017, -0.500000, 0.809017}, \n{-0.147621, -0.716567, 0.681718}, \n{-0.425325, -0.688191, 0.587785}, \n{-0.162460, -0.262866, 0.951056}, \n{0.442863, -0.238856, 0.864188}, \n{0.162460, -0.262866, 0.951056}, \n{0.309017, -0.500000, 0.809017}, \n{0.147621, -0.716567, 0.681718}, \n{0.000000, -0.525731, 0.850651}, \n{0.425325, -0.688191, 0.587785}, \n{0.587785, -0.425325, 0.688191}, \n{0.688191, -0.587785, 0.425325}, \n{-0.955423, 0.295242, 0.000000}, \n{-0.951056, 0.162460, 0.262866}, \n{-1.000000, 0.000000, 0.000000}, \n{-0.850651, 0.000000, 0.525731}, \n{-0.955423, -0.295242, 0.000000}, \n{-0.951056, -0.162460, 0.262866}, \n{-0.864188, 0.442863, -0.238856}, \n{-0.951056, 0.162460, -0.262866}, \n{-0.809017, 0.309017, -0.500000}, \n{-0.864188, -0.442863, -0.238856}, \n{-0.951056, -0.162460, -0.262866}, \n{-0.809017, -0.309017, -0.500000}, \n{-0.681718, 0.147621, -0.716567}, \n{-0.681718, -0.147621, -0.716567}, \n{-0.850651, 0.000000, -0.525731}, \n{-0.688191, 0.587785, -0.425325}, \n{-0.587785, 0.425325, -0.688191}, \n{-0.425325, 0.688191, -0.587785}, \n{-0.425325, -0.688191, -0.587785}, \n{-0.587785, -0.425325, -0.688191}, \n{-0.688191, -0.587785, -0.425325}, \n"
  },
  {
    "path": "source/asm_draw.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//\n// asm_draw.h\n//\n// Include file for asm drawing routines.\n//\n\n//\n// !!! note that this file must match the corresponding C structures at all\n// times !!!\n//\n\n// !!! if this is changed, it must be changed in r_local.h too !!!\n#define\tNEAR_CLIP\t0.01\n\n// !!! if this is changed, it must be changed in r_local.h too !!!\n#define\tCYCLE\t128\n\n// espan_t structure\n// !!! if this is changed, it must be changed in r_shared.h too !!!\n#define espan_t_u    \t0\n#define espan_t_v\t    4\n#define espan_t_count   8\n#define espan_t_pnext\t12\n#define espan_t_size    16\n\n// sspan_t structure\n// !!! if this is changed, it must be changed in d_local.h too !!!\n#define sspan_t_u    \t0\n#define sspan_t_v\t    4\n#define sspan_t_count   8\n#define sspan_t_size    12\n\n// spanpackage_t structure\n// !!! if this is changed, it must be changed in d_polyset.c too !!!\n#define spanpackage_t_pdest\t\t\t\t0\n#define spanpackage_t_pz\t\t\t\t4\n#define spanpackage_t_count\t\t\t\t8\n#define spanpackage_t_ptex\t\t\t\t12\n#define spanpackage_t_sfrac\t\t\t\t16\n#define spanpackage_t_tfrac\t\t\t\t20\n#define spanpackage_t_light\t\t\t\t24\n#define spanpackage_t_zi\t\t\t\t28\n#define spanpackage_t_size\t\t\t\t32 \n\n// edge_t structure\n// !!! if this is changed, it must be changed in r_shared.h too !!!\n#define et_u\t\t\t0\n#define et_u_step\t\t4\n#define et_prev\t\t\t8\n#define et_next\t\t\t12\n#define et_surfs\t\t16\n#define et_nextremove\t20\n#define et_nearzi\t\t24\n#define et_owner\t\t28\n#define et_size\t\t\t32\n\n// surf_t structure\n// !!! if this is changed, it must be changed in r_shared.h too !!!\n#define SURF_T_SHIFT\t6\n#define st_next\t\t\t0\n#define st_prev\t\t\t4\n#define st_spans\t\t8\n#define st_key\t\t\t12\n#define st_last_u\t\t16\n#define st_spanstate\t20\n#define st_flags\t\t24\n#define st_data\t\t\t28\n#define st_entity\t\t32\n#define st_nearzi\t\t36\n#define st_insubmodel\t40\n#define st_d_ziorigin\t44\n#define st_d_zistepu\t48\n#define st_d_zistepv\t52\n#define st_pad\t\t\t56\n#define st_size\t\t\t64\n\n// clipplane_t structure\n// !!! if this is changed, it must be changed in r_local.h too !!!\n#define cp_normal\t\t0\n#define cp_dist\t\t\t12\n#define cp_next\t\t\t16\n#define cp_leftedge\t\t20\n#define cp_rightedge\t21\n#define cp_reserved\t\t22\n#define cp_size\t\t\t24\n\n// medge_t structure\n// !!! if this is changed, it must be changed in model.h too !!!\n#define me_v\t\t\t\t0\n#define me_cachededgeoffset\t4\n#define me_size\t\t\t\t8\n\n// mvertex_t structure\n// !!! if this is changed, it must be changed in model.h too !!!\n#define mv_position\t\t0\n#define mv_size\t\t\t12\n\n// refdef_t structure\n// !!! if this is changed, it must be changed in render.h too !!!\n#define rd_vrect\t\t\t\t\t0\n#define rd_aliasvrect\t\t\t\t20\n#define rd_vrectright\t\t\t\t40\n#define rd_vrectbottom\t\t\t\t44\n#define rd_aliasvrectright\t\t\t48\n#define rd_aliasvrectbottom\t\t\t52\n#define rd_vrectrightedge\t\t\t56\n#define rd_fvrectx\t\t\t\t\t60\n#define rd_fvrecty\t\t\t\t\t64\n#define rd_fvrectx_adj\t\t\t\t68\n#define rd_fvrecty_adj\t\t\t\t72\n#define rd_vrect_x_adj_shift20\t\t76\n#define rd_vrectright_adj_shift20\t80\n#define rd_fvrectright_adj\t\t\t84\n#define rd_fvrectbottom_adj\t\t\t88\n#define rd_fvrectright\t\t\t\t92\n#define rd_fvrectbottom\t\t\t\t96\n#define rd_horizontalFieldOfView\t100\n#define rd_xOrigin\t\t\t\t\t104\n#define rd_yOrigin\t\t\t\t\t108\n#define rd_vieworg\t\t\t\t\t112\n#define rd_viewangles\t\t\t\t124\n#define rd_ambientlight\t\t\t\t136\n#define rd_size\t\t\t\t\t\t140\n\n// mtriangle_t structure\n// !!! if this is changed, it must be changed in model.h too !!!\n#define mtri_facesfront\t\t0\n#define mtri_vertindex\t\t4\n#define mtri_size\t\t\t16\t// !!! if this changes, array indexing in !!!\n\t\t\t\t\t\t\t\t// !!! d_polysa.s must be changed to match !!!\n#define mtri_shift\t\t\t4\n\n"
  },
  {
    "path": "source/asm_i386.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#ifndef __ASM_I386__\n#define __ASM_I386__\n\n#ifdef ELF\n#define C(label) label\n#else\n#define C(label) _##label\n#endif\n\n//\n// !!! note that this file must match the corresponding C structures at all\n// times !!!\n//\n\n// plane_t structure\n// !!! if this is changed, it must be changed in model.h too !!!\n// !!! if the size of this is changed, the array lookup in SV_HullPointContents\n//     must be changed too !!!\n#define pl_normal\t0\n#define pl_dist\t\t12\n#define pl_type\t\t16\n#define pl_signbits\t17\n#define pl_pad\t\t18\n#define pl_size\t\t20\n\n// hull_t structure\n// !!! if this is changed, it must be changed in model.h too !!!\n#define\thu_clipnodes\t\t0\n#define\thu_planes\t\t\t4\n#define\thu_firstclipnode\t8\n#define\thu_lastclipnode\t\t12\n#define\thu_clip_mins\t\t16\n#define\thu_clip_maxs\t\t28\n#define hu_size  \t\t\t40\n\n// dnode_t structure\n// !!! if this is changed, it must be changed in bspfile.h too !!!\n#define\tnd_planenum\t\t0\n#define\tnd_children\t\t4\n#define\tnd_mins\t\t\t8\n#define\tnd_maxs\t\t\t20\n#define\tnd_firstface\t32\n#define\tnd_numfaces\t\t36\n#define nd_size\t\t\t40\n\n// sfxcache_t structure\n// !!! if this is changed, it much be changed in sound.h too !!!\n#define sfxc_length\t\t0\n#define sfxc_loopstart\t4\n#define sfxc_speed\t\t8\n#define sfxc_width\t\t12\n#define sfxc_stereo\t\t16\n#define sfxc_data\t\t20\n\n// channel_t structure\n// !!! if this is changed, it much be changed in sound.h too !!!\n#define ch_sfx\t\t\t0\n#define ch_leftvol\t\t4\n#define ch_rightvol\t\t8\n#define ch_end\t\t\t12\n#define ch_pos\t\t\t16\n#define ch_looping\t\t20\n#define ch_entnum\t\t24\n#define ch_entchannel\t28\n#define ch_origin\t\t32\n#define ch_dist_mult\t44\n#define ch_master_vol\t48\n#define ch_size\t\t\t52\n\n// portable_samplepair_t structure\n// !!! if this is changed, it much be changed in sound.h too !!!\n#define psp_left\t\t0\n#define psp_right\t\t4\n#define psp_size\t\t8\n\n#endif\n\n"
  },
  {
    "path": "source/audiodec/audio_decoder.cpp",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n// Headers\n#include <cassert>\n#include <cstring>\n#include \"audio_decoder.h\"\n\n#include \"decoder_mpg123.h\"\n#include \"decoder_oggvorbis.h\"\n#include \"audio_resampler.h\"\n\nvoid AudioDecoder::Pause() {\n\tpaused = true;\n}\n\nvoid AudioDecoder::Resume() {\n\tpaused = false;\n}\n\nint AudioDecoder::Decode(uint8_t* buffer, int length) {\n\tif (paused) {\n\t\tmemset(buffer, '\\0', length);\n\t\treturn length;\n\t}\n\n\tint res = FillBuffer(buffer, length);\n\n\tif (res < 0) {\n\t\tmemset(buffer, '\\0', length);\n\t} else if (res < length) {\n\t\tmemset(&buffer[res], '\\0', length - res);\n\t}\n\n\tif (IsFinished() && looping) {\n\t\t++loop_count;\n\t\tRewind();\n\t\tif (length - res > 0) {\n\t\t\tint res2 = Decode(&buffer[res], length - res);\n\t\t\tif (res2 <= 0) {\n\t\t\t\treturn res;\n\t\t\t}\n\t\t\treturn res + res2;\n\t\t}\n\t}\n\n\treturn res;\n}\n\nint AudioDecoder::DecodeAsMono(uint8_t* left, uint8_t* right, int size) {\n\tint freq; Format format; int channels;\n\tGetFormat(freq, format, channels);\n\n\tif (channels == 1) {\n\t\treturn Decode(left, size);\n\t}\n\n\tif ((int)mono_buffer.size() < size * 2) {\n\t\tmono_buffer.resize(size * 2);\n\t}\n\t\n\tint read = Decode(mono_buffer.data(), size * 2);\n\tif (read < 0) {\n\t\tmemset(left, '\\0', size);\n\t\tmemset(right, '\\0', size);\n\t\treturn -1;\n\t}\n\n\tint sample_size = GetSamplesizeForFormat(format);\n\n\tfor (int i = 0; i <= read / 2; i += sample_size) {\n\t\tmemcpy(&left[i], &mono_buffer.data()[i * channels], sample_size);\n\t\tmemcpy(&right[i], &mono_buffer.data()[i * channels + sample_size], sample_size);\n\t}\n\n\tif (read < size / 2) {\n\t\tmemset(&left[read / 2], '\\0', size);\n\t\tmemset(&right[read / 2], '\\0', size);\n\t}\n\n\treturn read / 2;\n}\n\nclass WMAUnsupportedFormatDecoder : public AudioDecoder {\npublic:\n\tWMAUnsupportedFormatDecoder() {\n\t\terror_message = std::string(\"WMA audio files are not supported. Reinstall the\\n\") +\n\t\t\t\"game and don't convert them when asked by Windows!\\n\";\n\t}\n\tbool Open(FILE*) override { return false; }\n\tbool IsFinished() const override { return true; }\n\tvoid GetFormat(int&, Format&, int&) const override {}\nprivate:\n\tint FillBuffer(uint8_t*, int) override { return -1; };\n};\nconst char wma_magic[] = { (char)0x30, (char)0x26, (char)0xB2, (char)0x75 };\n\nstd::unique_ptr<AudioDecoder> AudioDecoder::Create(FILE* file, const std::string& filename) {\n\tchar magic[4] = { 0 };\n\tfread(magic, 4, 1, file);\n\tfseek(file, 0, SEEK_SET);\n\n\t// Try to use MIDI decoder, use fallback(s) if available\n\tif (!strncmp(magic, \"MThd\", 4)) {\n#ifdef HAVE_WILDMIDI\n\t\tstatic bool wildmidi_works = true;\n\t\tif (wildmidi_works) {\n\t\t\tAudioDecoder *mididec = nullptr;\n#  ifdef USE_AUDIO_RESAMPLER\n\t\t\tmididec = new AudioResampler(new WildMidiDecoder(filename));\n#  else\n\t\t\tmididec = new WildMidiDecoder(filename);\n#  endif\n\t\t\tif (mididec) {\n\t\t\t\tif (mididec->WasInited())\n\t\t\t\t\treturn std::unique_ptr<AudioDecoder>(mididec);\n\n\t\t\t\tdelete mididec;\n\t\t\t}\n\t\t\twildmidi_works = false;\n\t\t}\n#endif\n#if WANT_FMMIDI == 1\n#  ifdef USE_AUDIO_RESAMPLER\n\t\treturn std::unique_ptr<AudioDecoder>(new AudioResampler(new FmMidiDecoder(), true, AudioResampler::Quality::Low));\n#  else\n\t\treturn std::unique_ptr<AudioDecoder>(new FmMidiDecoder());\n#  endif\n#endif\n\t\t// No MIDI decoder available\n\t\treturn nullptr;\n\t}\n\n\t// Try to use internal OGG decoder\n\tif (!strncmp(magic, \"OggS\", 4)) { // OGG\n#if defined(HAVE_TREMOR) || defined(HAVE_OGGVORBIS)\n#  ifdef USE_AUDIO_RESAMPLER\n\t\treturn std::unique_ptr<AudioDecoder>(new AudioResampler(new OggVorbisDecoder()));\n#  else\n\t\treturn std::unique_ptr<AudioDecoder>(new OggVorbisDecoder());\n#  endif\n#endif\n\t}\n\t\n#ifdef HAVE_SLOW_CPU\n\t// Try to use a basic decoder for faster wav decoding if not ADPCM\n\tif (!strncmp(magic, \"RIFF\", 4)){\n\t\tfseek(file, 20, SEEK_SET);\n\t\tuint16_t raw_enc;\n\t\tfread(&raw_enc, 2, 1, file);\n\t\tfseek(file, 0, SEEK_SET);\n\t\tif (raw_enc == 0x01){ // Codec is normal PCM\n#  ifdef USE_AUDIO_RESAMPLER\n\t\t\treturn std::unique_ptr<AudioDecoder>(new AudioResampler(new WavDecoder()));\n#  else\n\t\t\treturn std::unique_ptr<AudioDecoder>(new WavDecoder());\n#  endif\n\t\t}\n\t}\n\n#endif\n\t\n\t// Try to use libsndfile for common formats\n\tif (!strncmp(magic, \"RIFF\", 4) || // WAV\n\t\t!strncmp(magic, \"FORM\", 4) || // WAV AIFF\n\t\t!strncmp(magic, \"OggS\", 4) || // OGG\n\t\t!strncmp(magic, \"fLaC\", 4)) { // FLAC\n#ifdef HAVE_LIBSNDFILE\n#  ifdef USE_AUDIO_RESAMPLER\n\t\t\treturn std::unique_ptr<AudioDecoder>(new AudioResampler(new LibsndfileDecoder()));\n#  else\n\t\t\treturn std::unique_ptr<AudioDecoder>(new LibsndfileDecoder());\n#  endif\n#endif\n\t\treturn nullptr;\n\t}\n\n\t// Inform about WMA issue\n\tif (!memcmp(magic, wma_magic, 4)) {\n\t\treturn std::unique_ptr<AudioDecoder>(new WMAUnsupportedFormatDecoder());\n\t}\n\n\t// False positive MP3s should be prevented before by checking for common headers\n#ifdef HAVE_MPG123\n\tstatic bool mpg123_works = true;\n\tif (mpg123_works) {\n\t\tAudioDecoder *mp3dec = nullptr;\n\t\tif (strncmp(magic, \"ID3\", 3) == 0) {\n#  ifdef USE_AUDIO_RESAMPLER\n\t\t\tmp3dec = new AudioResampler(new Mpg123Decoder());\n#  else\n\t\t\tmp3dec = new Mpg123Decoder();\n#  endif\n\t\t\tif (mp3dec) {\n\t\t\t\tif (mp3dec->WasInited())\n\t\t\t\t\treturn std::unique_ptr<AudioDecoder>(mp3dec);\n\n\t\t\t\tdelete mp3dec;\n\t\t\t}\n\t\t\tmpg123_works = false;\n\t\t\treturn nullptr;\n\t\t}\n\n\t\t// Parsing MP3s seems to be the only reliable way to detect them\n\t\tif (Mpg123Decoder::IsMp3(file)) {\n\t\t\tfseek(file, 0, SEEK_SET);\n#  ifdef USE_AUDIO_RESAMPLER\n\t\t\tmp3dec = new AudioResampler(new Mpg123Decoder());\n#  else\n\t\t\tmp3dec = new Mpg123Decoder();\n#  endif\n\t\t\tif (mp3dec) {\n\t\t\t\tif(mp3dec->WasInited())\n\t\t\t\t\treturn std::unique_ptr<AudioDecoder>(mp3dec);\n\n\t\t\t\tdelete mp3dec;\n\t\t\t}\n\t\t\tmpg123_works = false;\n\t\t\treturn nullptr;\n\t\t}\n\t}\n#endif\n\n\tfseek(file, 0, SEEK_SET);\n\treturn nullptr;\n}\n\nvoid AudioDecoder::SetFade(int begin, int end, int duration) {\n\tfade_time = 0.0;\n\n\tif (duration <= 0.0) {\n\t\tvolume = end;\n\t\treturn;\n\t}\n\n\tif (begin == end) {\n\t\tvolume = end;\n\t\treturn;\n\t}\n\n\tvolume = (double)begin;\n\tfade_end = (double)end;\n\tfade_time = (double)duration;\n\tdelta_step = (fade_end - volume) / fade_time;\n}\n\nvoid AudioDecoder::Update(int delta) {\n\tif (fade_time <= 0.0) {\n\t\treturn;\n\t}\n\t\n\tfade_time -= delta;\n\tvolume += delta * delta_step;\n\n\tvolume = volume > 100.0 ? 100.0 :\n\t\tvolume < 0.0 ? 0.0 :\n\t\tvolume;\n}\n\nvoid AudioDecoder::SetVolume(int volume) {\n\tthis->volume = (double)volume;\n}\n\nint AudioDecoder::GetVolume() const {\n\treturn (int)volume;\n}\n\nvoid AudioDecoder::Rewind() {\n\tif (!Seek(0, Origin::Begin)) {\n\t\t// The libs guarantee that Rewind works\n\t\tassert(false && \"Rewind\");\n\t}\n}\n\nbool AudioDecoder::GetLooping() const {\n\treturn looping;\n}\n\nvoid AudioDecoder::SetLooping(bool enable) {\n\tlooping = enable;\n}\n\nint AudioDecoder::GetLoopCount() const {\n\treturn loop_count;\n}\n\nbool AudioDecoder::WasInited() const {\n\treturn true;\n}\n\nstd::string AudioDecoder::GetError() const {\n\treturn error_message;\n}\n\nstd::string AudioDecoder::GetType() const {\n\treturn music_type;\n}\n\nbool AudioDecoder::SetFormat(int, Format, int) {\n\treturn false;\n}\n\nint AudioDecoder::GetPitch() const {\n\treturn 0;\n}\n\nbool AudioDecoder::SetPitch(int) {\n\treturn false;\n}\n\nbool AudioDecoder::Seek(size_t, Origin) {\n\treturn false;\n}\n\nsize_t AudioDecoder::Tell() const {\n\treturn -1;\n}\n\nint AudioDecoder::GetTicks() const {\n\treturn 0;\n}\n\nint AudioDecoder::GetSamplesizeForFormat(AudioDecoder::Format format) {\n\tswitch (format) {\n\t\tcase Format::S8:\n\t\tcase Format::U8:\n\t\t\treturn 1;\n\t\tcase Format::S16:\n\t\tcase Format::U16:\n\t\t\treturn 2;\n\t\tcase Format::S32:\n\t\tcase Format::U32:\n\t\tcase Format::F32:\n\t\t\treturn 4;\n\t}\n\n\tassert(false && \"Bad format\");\n\treturn -1;\n}\n"
  },
  {
    "path": "source/audiodec/audio_decoder.h",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef EASYRPG_AUDIO_DECODER_H\n#define EASYRPG_AUDIO_DECODER_H\n\n// Headers\n#include <cstdio>\n#include <string>\n#include <vector>\n#include <memory>\n\n/**\n * The AudioDecoder class provides an abstraction over the decoding of\n * common audio formats.\n * Create will instantitate a proper audio decoder and calling Decode will\n * fill a buffer with audio data which must be passed to the audio hardware.\n */\nclass AudioDecoder {\npublic:\n\tvirtual ~AudioDecoder() {}\n\n\t/** Sample format */\n\tenum class Format {\n\t\tS8,\n\t\tU8,\n\t\tS16,\n\t\tU16,\n\t\tS32,\n\t\tU32,\n\t\tF32\n\t};\n\n\t/** Seek origin for Seek command */\n\tenum class Origin {\n\t\tBegin = 0,\n\t\tCurrent = 1,\n\t\tEnd = 2\n\t};\n\n\t/**\n\t * Writes 'size' bytes in the specified buffer. The data matches the format\n\t * reported by GetFormat.\n\t * When size is is smaller then the amount of written bytes or an error occurs\n\t * the remaining buffer space is cleared.\n\t *\n\t * @param buffer Output buffer\n\t * @param size Size of the buffer in bytes\n\t * @return Number of bytes written to the buffer or -1 on error\n\t */\n\tint Decode(uint8_t* buffer, int size);\n\n\t/**\n\t * Splits stereo into mono and Writes 'size' bytes in each of the buffers.\n\t * The data matches the format reported by GetFormat, except that both\n\t * buffers will contain Mono audio. When the source format was already mono\n\t * the 'right' buffer is ignored (and not cleared)\n\t * When size is is smaller then the amount of written bytes or an error occurs\n\t * the remaining buffer space is cleared.\n\t *\n\t * @param left Output buffer of the left channel\n\t * @param right Output buffer of the right channel (or nothing if source is mono)\n\t * @param size Size of each of the buffers\n\t * @return Number of bytes written in one of the buffers or -1 on error\n\t */\n\tint DecodeAsMono(uint8_t* left, uint8_t* right, int size);\n\n\t/**\n\t * Parses the specified file handle and open a proper audio decoder to handle\n\t * the audio file.\n\t * Upon success the file handle is owned by the audio decoder and further\n\t * operations on it will be undefined! Upon failure the file handle points at\n\t * the beginning.\n\t * The filename is used for debug purposes but should match the FILE handle.\n\t * Upon failure the FILE handle is valid and points at the beginning.\n\t *\n\t * @param file File handle to parse\n\t * @param filename Path to the file handle\n\t * @return An audio decoder instance when the format was detected, otherwise null\n\t */\n\tstatic std::unique_ptr<AudioDecoder> Create(FILE* file, const std::string& filename);\n\n\t/**\n\t * Updates the volume for the fade in/out effect.\n\t * Volume changes will not really modify the volume but are only helper\n\t * functions for retrieving the volume information for the audio hardware.\n\t *\n\t * @param delta Time in ms since the last call of this function.\n\t */\n\tvoid Update(int delta);\n\n\t/**\n\t * Prepares a volume fade in/out effect.\n\t * To do a fade out begin must be larger then end.\n\t * Call Update to do the fade.\n\t * Volume changes will not really modify the volume but are only helper\n\t * functions for retrieving the volume information for the audio hardware.\n\t *\n\t * @param begin Begin volume (from 0-100)\n\t * @param end End volume (from 0-100)\n\t * @param duration Fade duration in ms\n\t */\n\tvoid SetFade(int begin, int end, int duration);\n\n\t/**\n\t * Sets the volume of the audio decoder.\n\t * Volume changes will not really modify the volume but are only helper\n\t * functions for retrieving the volume information for the audio hardware.\n\t *\n\t * @param volume (from 0-100)\n\t */\n\tvoid SetVolume(int volume);\n\n\t/**\n\t * Gets the volume of the audio decoder.\n\t * Volume changes will not really modify the volume but are only helper\n\t * functions for retrieving the volume information for the audio hardware.\n\t */\n\tint GetVolume() const;\n\n\t/**\n\t * Pauses the audio decoding.\n\t * Calling any Decode function will return a 0-buffer.\n\t */\n\tvoid Pause();\n\n\t/**\n\t * Resumes the audio decoding.\n\t * The decode function will continue behaving as expected.\n\t */\n\tvoid Resume();\n\n\t/**\n\t * Rewinds the audio stream to the beginning.\n\t */\n\tvoid Rewind();\n\n\t/**\n\t * Gets if the audio stream will loop when the stream finishes.\n\t *\n\t * @return if looping\n\t */\n\tbool GetLooping() const;\n\n\t/**\n\t * Enables/Disables audio stream looping.\n\t * When looping is enabled IsFinished will never return true and the stream\n\t * auto-rewinds (assuming Rewind is supported)\n\t *\n\t * @param enable Enable/Disable looping\n\t */\n\tvoid SetLooping(bool enable);\n\n\t/**\n\t * Gets the number of loops\n\t *\n\t * @return loop count\n\t */\n\tint GetLoopCount() const;\n\n\t/**\n\t * Gets the status of the newly created audio decoder.\n\t * Used to make sure the underlying library is properly initialized.\n\t *\n\t * @return true if initializing was succesful, false otherwise\n\t */\n\tvirtual bool WasInited() const;\n\n\t/**\n\t * Provides an error message when Open or a Decode function fail.\n\t *\n\t * @return Human readable error message\n\t */\n\tvirtual std::string GetError() const;\n\n\t/**\n\t * Returns the name of the format the current audio decoder decodes in\n\t * lower case.\n\t *\n\t * @return Format name\n\t */\n\tvirtual std::string GetType() const;\n\n\t// Functions to be implemented by the audio decoder\n\t/**\n\t * Assigns a file handle to the audio decoder.\n\t * Open should be only called once per audio decoder instance.\n\t * Use GetError to get the error reason on failure.\n\t *\n\t * @return true if inititalizing was succesful, false otherwise\n\t */\n\tvirtual bool Open(FILE* file) = 0;\n\n\t/**\n\t * Determines whether the stream is finished.\n\t *\n\t * @return true stream ended\n\t */\n\tvirtual bool IsFinished() const = 0;\n\n\t/**\n\t * Retrieves the format of the audio decoder.\n\t * It is guaranteed that these settings will stay constant the whole time.\n\t *\n\t * @param frequency Filled with the audio frequency\n\t * @param format Filled with the audio format\n\t * @param channel Filled with the amount of channels\n\t */\n\tvirtual void GetFormat(int& frequency, Format& format, int& channels) const = 0;\n\n\t/**\n\t * Requests a prefered format from the audio decoder. Not all decoders\n\t * support everything and it's recommended to use the audio hardware\n\t * for audio processing.\n\t * When false is returned use GetFormat to get the real format of the\n\t * output data.\n\t *\n\t * @param frequency Audio frequency\n\t * @param format Audio format\n\t * @param channel Number of channels\n\t * @return true when all settings were set, otherwise false (use GetFormat)\n\t */\n\tvirtual bool SetFormat(int frequency, Format format, int channels);\n\n\t/**\n\t * Gets the pitch multiplier.\n\t *\n\t * @return pitch multiplier\n\t */\n\tvirtual int GetPitch() const;\n\n\t/**\n\t * Sets the pitch multiplier.\n\t * 100 = normal speed\n\t * 200 = double speed and so on\n\t * Not all audio decoders support this. Using the audio hardware is\n\t * recommended.\n\t * \n\t * @param pitch Pitch multiplier to use\n\t * @return true if pitch was set, false otherwise\n\t */\n\tvirtual bool SetPitch(int pitch);\n\n\t/**\n\t * Seeks in the audio stream. The value of offset is implementation\n\t * defined but is guaranteed to match the result of Tell.\n\t * Only Rewinding is guaranteed to work.\n\t *\n\t * @param offset Offset to seek to\n\t * @param origin Position to seek from\n\t * @return Whether seek was successful\n\t */\n\tvirtual bool Seek(size_t offset, Origin origin);\n\n\t/**\n\t * Tells the current stream position. The value is implementation\n\t * defined.\n\t *\n\t * @return Position in the stream\n\t */\n\tvirtual size_t Tell() const;\n\n\t/**\n\t * Returns amount of executed ticks. Only useful for MIDI format.\n\t *\n\t * @return Amount of MIDI ticks.\n\t */\n\tvirtual int GetTicks() const;\n\n\t/**\n\t * Returns the amount of bytes per sample.\n\t *\n\t * @param Sample format\n\t * @return Bytes per sample\n\t */\n\tstatic int GetSamplesizeForFormat(AudioDecoder::Format format);\nprotected:\n\t/**\n\t * Called by the Decode functions to fill the buffer.\n\t *\n\t * @param buffer Buffer to fill\n\t * @param size Buffer size\n\t * @return number of bytes read or -1 on error\n\t */\n\tvirtual int FillBuffer(uint8_t* buffer, int size) = 0;\n\n\tstd::string error_message;\n\tstd::string music_type;\nprivate:\n\tbool paused = false;\n\tdouble volume = 0;\n\tdouble fade_end = 0;\n\tdouble fade_time = -1;\n\tdouble delta_step = 0;\n\n\tbool looping = false;\n\tint loop_count = 0;\n\n\tstd::vector<uint8_t> mono_buffer;\n};\n\n#endif\n"
  },
  {
    "path": "source/audiodec/audio_resampler.cpp",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#if defined(HAVE_LIBSPEEXDSP) || defined(HAVE_LIBSAMPLERATE) \n\n#include <cassert>\n#include \"audio_resampler.h\"\n\n#define ERROR -1\n#define STANDARD_PITCH 100\n\n/**\n * Utility function used to convert a buffer of a arbitrary AudioDecoder::Format to a float buffer\n * \n * @param[in] wrapped_decoder The decoder from which audio samples are read\n * @param[inout] buffer The buffer which will receive the converted samples, \n *\t\t\thas to be at least amount_of_samples_to_read*sizeof(float) bytes big.\n * @param[in] amount_of_samples_to_read The number of samples to read.\n * @param[in] input_samplesize The size of one sample of the decoder in it's original format - given in bytes\n * @param[in] input_format The original format of the samples\n * \n * @return The number of converted samples - if this number is smaller than amount_of_samples_to_read the wrapped decoder has reaches it's end.\n *\t\tIf the returned value has a negative value an error occured.\n */\ninline static int DecodeAndConvertFloat(AudioDecoder * wrapped_decoder,\n\t\t\t\t\t\t\t\t\t\tuint8_t * buffer, \n\t\t\t\t\t\t\t\t\t\tint amount_of_samples_to_read, \n\t\t\t\t\t\t\t\t\t\tconst int input_samplesize, \n\t\t\t\t\t\t\t\t\t\tconst AudioDecoder::Format input_format){\n\tfloat* bufferAsFloat = (float*)buffer;\n\tif (wrapped_decoder->IsFinished()) return 0; //Workaround for decoders which don't detect there own end\n\tint amount_of_samples_read = wrapped_decoder->Decode(buffer, amount_of_samples_to_read*input_samplesize);\n\tif (amount_of_samples_read <= 0) {\n\t\treturn amount_of_samples_read; //error occured - or nothing read\n\t} else {\n\t\tamount_of_samples_read /= input_samplesize;\n\t}\n\t//Convert the read data (amount_of_data_read is at least one at this moment)\n\tswitch (input_format) {\n\t\tcase AudioDecoder::Format::S8:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((int8_t*)bufferAsFloat)[i] / 128.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U8:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((uint8_t*)bufferAsFloat)[i] / 128.0 - 1.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::S16:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((int16_t*)bufferAsFloat)[i] / 32768.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U16:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((uint16_t*)bufferAsFloat)[i] / 32768.0 - 1.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::S32:\n\t\t\t//Convert inplace (same size)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((int32_t*)bufferAsFloat)[i] / 2147483648.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U32:\n\t\t\t//Convert inplace (same size)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsFloat[i] = ((uint32_t*)bufferAsFloat)[i] / 2147483648.0 - 1.0;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::F32:\n\t\t\t//Nothing to convert\n\t\t\tbreak;\n\t}\n\treturn amount_of_samples_read;\n}\n\n#if defined(HAVE_LIBSPEEXDSP)\n/**\n * Utility function used to convert a buffer of a arbitrary AudioDecoder::Format to a int16 buffer\n * \n * @param[in] wrapped_decoder The decoder from which audio samples are read\n * @param[inout] buffer The buffer which will receive the converted samples, \n *\t\t\thas to be at least amount_of_samples_to_read*max(sizeof(int16_t),input_samplesize) bytes big.\n * @param[in] amount_of_samples_to_read The number of samples to read.\n * @param[in] input_samplesize The size of one sample of the decoder in it's original format - given in bytes\n * @param[in] input_format The original format of the samples\n * \n * @return The number of converted samples - if this number is smaller than amount_of_samples_to_read the wrapped decoder has reaches it's end.\n *\t\tIf the returned value has a negative value an error occured.\n */\ninline static int DecodeAndConvertInt16(AudioDecoder * wrapped_decoder, \n\t\t\t\t\t\t\t\t\t\tuint8_t * buffer, \n\t\t\t\t\t\t\t\t\t\tint amount_of_samples_to_read, \n\t\t\t\t\t\t\t\t\t\tconst int input_samplesize, \n\t\t\t\t\t\t\t\t\t\tconst AudioDecoder::Format input_format){\n\tint16_t* bufferAsInt16 = (int16_t*)buffer;\n\tif (wrapped_decoder->IsFinished()) return 0; //Workaround for decoders which don't detect there own end\n\tint amount_of_samples_read = wrapped_decoder->Decode(buffer, amount_of_samples_to_read*input_samplesize);\n\tif (amount_of_samples_read <= 0) {\n\t\treturn amount_of_samples_read; //error occured - or nothing read\n\t} else {\n\t\t//Convert the number of bytes to the number of samples\n\t\tamount_of_samples_read /= input_samplesize;\n\t}\n\t//Convert the read data (amount_of_data_read is at least one at this moment)\n\tswitch (input_format) {\n\t\tcase AudioDecoder::Format::S8:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsInt16[i] = ((int8_t*)bufferAsInt16)[i] << 8;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U8:\n\t\t\t//Convert inplace (the last frames are unused if smaller)\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsInt16[i] = (((int16_t)(((uint8_t*)bufferAsInt16)[i])) - 128) << 8;\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::S16:\n\t\t\t//Nothing to convert\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U16:\n\t\t\t//Convert unsigned to signed\n\t\t\tfor (int i = amount_of_samples_read - 1; i >= 0; i--) {\n\t\t\t\tbufferAsInt16[i] = (int16_t)(((int32_t)(((uint16_t*)bufferAsInt16)[i])) - 32768);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::S32:\n\t\t\t//Convert inplace (from front to back to prevent overwriting the buffer)\n\t\t\tfor (int i = 0; i < amount_of_samples_read; i++) {\n\t\t\t\tbufferAsInt16[i] = (int16_t)((((int32_t*)bufferAsInt16)[i]) >> 16);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::U32:\n\t\t\t//Convert inplace (from front to back to prevent overwriting the buffer)\n\t\t\tfor (int i = 0; i < amount_of_samples_read; i++) {\n\t\t\t\tbufferAsInt16[i] = (int16_t)(((int32_t)((((uint32_t*)bufferAsInt16)[i]) >> 16)) - 32768);\n\t\t\t}\n\t\t\tbreak;\n\t\tcase AudioDecoder::Format::F32:\n\t\t\t//Convert inplace (from front to back to prevent overwriting the buffer)\n\t\t\tfor (int i = 0; i < amount_of_samples_read; i++) {\n\t\t\t\tfloat number = ((((float*)bufferAsInt16)[i])*32768.0);\n\t\t\t\tbufferAsInt16[i] = (number <= 32767.0) ? ((number >= -32768.0) ? number : -32768) : 32767;\n\t\t\t}\n\t\t\tbreak;\n\t}\n\treturn amount_of_samples_read;\n}\n#endif\n\nAudioResampler::AudioResampler(AudioDecoder * wrapped, bool pitch_handled, AudioResampler::Quality quality)\n{\n\t//There is no need for a standalone resampler decoder\n\tassert(wrapped != 0);\n\n\twrapped_decoder = wrapped;\n\tmusic_type = wrapped->GetType();\n\tlasterror = 0;\n\tpitch_handled_by_decoder = pitch_handled;\n\n\t#if defined(HAVE_LIBSPEEXDSP)\n\t\tswitch (quality) {\n\t\t\tcase Quality::Low:\n\t\t\t\tsampling_quality = 1;\n\t\t\t\tbreak;\n\t\t\tcase Quality::Medium:\n\t\t\t\tsampling_quality = 3;\n\t\t\t\tbreak;\n\t\t\tcase Quality::High:\n\t\t\t\tsampling_quality = 5;\n\t\t\t\tbreak;\n\t\t}\n\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\tswitch (quality) {\n\t\t\tcase Quality::Low:\n\t\t\t\tsampling_quality = SRC_SINC_FASTEST;\n\t\t\t\tbreak;\n\t\t\tcase Quality::Medium:\n\t\t\t\tsampling_quality = SRC_SINC_MEDIUM_QUALITY;\n\t\t\t\tbreak;\n\t\t\tcase Quality::High:\n\t\t\t\tsampling_quality = SRC_SINC_BEST_QUALITY;\n\t\t\t\tbreak;\n\t\t}\n\t#endif\n\n\tfinished = false;\n\tpitch = 100;\n\n}\n\nAudioResampler::~AudioResampler() {\n\tif (conversion_state != 0) {\n\t#if defined(HAVE_LIBSPEEXDSP)\n\t\t\tspeex_resampler_destroy(conversion_state);\n\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\t\tsrc_delete(conversion_state);\n\t#endif\n\t}\n\tif (wrapped_decoder != 0) {\n\t\tdelete wrapped_decoder;\n\t}\n}\n\nbool AudioResampler::WasInited() const {\n\treturn wrapped_decoder->WasInited();\n}\n\nbool AudioResampler::Open(FILE* file) {\n\tif (wrapped_decoder->Open(file)) {\n\t\twrapped_decoder->GetFormat(input_rate, input_format, nr_of_channels);\n\n\t\t//determine if the input format is supported by the resampler\n\t\tswitch (input_format) {\n\t\t\tcase Format::F32: output_format = input_format; break;\n\t\t#ifdef HAVE_LIBSPEEXDSP\n\t\t\tcase Format::S16: output_format = input_format; break;\n\t\t#endif\n\t\t\tdefault: output_format = Format::F32; break;\n\t\t}\n\n\t\t//Set input format to output_format if possible\n\t\twrapped_decoder->SetFormat(input_rate, output_format, nr_of_channels);\n\t\t//Reread format to get new values\n\t\twrapped_decoder->GetFormat(input_rate, input_format, nr_of_channels);\n\t\toutput_rate = input_rate;\n\n\t\t#if defined(HAVE_LIBSPEEXDSP)\n\t\t\tconversion_state = speex_resampler_init(nr_of_channels, input_rate, output_rate, sampling_quality, &lasterror);\n\t\t\tconversion_data.ratio_num = input_rate;\n\t\t\tconversion_data.ratio_denom = output_rate;\n\t\t\tspeex_resampler_skip_zeros(conversion_state);\n\t\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\t\tconversion_state = src_new(sampling_quality, nr_of_channels, &lasterror);\n\t\t#endif\n\n\t\t//Init the conversion data structure\n\t\tconversion_data.input_frames = 0;\n\t\tconversion_data.input_frames_used = 0;\n\t\tfinished = false;\n\t\treturn conversion_state != 0;\n\t} else {\n\t\treturn false;\n\t}\n}\n\nbool AudioResampler::Seek(size_t offset, Origin origin) {\n\tif (wrapped_decoder->Seek(offset, origin)) {\n\t\t//reset conversio data\n\t\tconversion_data.input_frames = 0;\n\t\tconversion_data.input_frames_used = 0;\n\t\tfinished = wrapped_decoder->IsFinished();\n\t\t#if defined(HAVE_LIBSPEEXDSP)\n\t\t\tspeex_resampler_reset_mem(conversion_state);\n\t\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\t\tsrc_reset(conversion_state);\n\t\t#endif\n\t\treturn true;\n\t}\n\treturn false;\n\n}\n\nsize_t AudioResampler::Tell() const {\n\treturn wrapped_decoder->Tell();\n}\n\nint AudioResampler::GetTicks() const {\n\treturn wrapped_decoder->GetTicks();\n}\n\nbool AudioResampler::IsFinished() const {\n\treturn finished;\n}\n\nvoid AudioResampler::GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const {\n\tfrequency = output_rate;\n\tformat = output_format;\n\tchannels = nr_of_channels;\n}\n\nbool AudioResampler::SetFormat(int freq, AudioDecoder::Format fmt, int channels) {\n\t//Check whether requested format is supported by the resampler\n\tswitch (fmt) {\n\tcase Format::F32: output_format = fmt; break;\n\t#ifdef HAVE_LIBSPEEXDSP\n\t\tcase Format::S16: output_format = fmt; break;\n\t#endif\n\tdefault: break;\n\t}\n\twrapped_decoder->SetFormat(input_rate, output_format, channels);\n\twrapped_decoder->GetFormat(input_rate, input_format, nr_of_channels);\n\toutput_rate = freq;\n\treturn (nr_of_channels == channels&&output_format == fmt);\n}\n\nint AudioResampler::GetPitch() const {\n\tif (pitch_handled_by_decoder) {\n\t\treturn wrapped_decoder->GetPitch();\n\t} else {\n\t\treturn pitch;\n\t}\n}\n\nbool AudioResampler::SetPitch(int pitch_) {\n\tif (pitch_handled_by_decoder) {\n\t\treturn wrapped_decoder->SetPitch(pitch_);\n\t} else {\n\t\tpitch = pitch_;\n\t\treturn true;\n\t}\n}\n\nint AudioResampler::FillBuffer(uint8_t* buffer, int length) {\n\tint amount_filled = 0;\n\tif((input_rate == output_rate) && ((pitch == STANDARD_PITCH) || pitch_handled_by_decoder)) {\n\t\t//Do only format conversion\n\t\tamount_filled = FillBufferSameRate(buffer, length);\n\t} else {\n\t\tif (conversion_state == 0) {\n\t\t\terror_message = \"internal error: state pointer is a nullptr\";\n\t\t\tamount_filled = ERROR;\n\t\t} else {\n\t\t\t//Do samplerate conversion\n\t\t\tamount_filled = FillBufferDifferentRate(buffer, length);\n\t\t}\n\t}\n\t//Clear the remaining buffer as specified in audio_decoder.h\n\tfor (int i = (amount_filled > 0) ? amount_filled : 0; i < length; i++) {\n\t\tbuffer[i] = 0;\n\t}\n\treturn amount_filled;\n}\n\nint AudioResampler::FillBufferSameRate(uint8_t* buffer, int length) {\n\tconst int input_samplesize = GetSamplesizeForFormat(input_format);\n\tconst int output_samplesize = GetSamplesizeForFormat(output_format);\n\t//The buffer size has to be a multiple of a frame\n\tconst int buffer_size=sizeof(internal_buffer) - sizeof(internal_buffer)%(nr_of_channels*input_samplesize);\n\t\n\tint total_output_frames = length / (output_samplesize*nr_of_channels);\n\tint amount_of_data_to_read = 0;\n\tint amount_of_data_read = total_output_frames*nr_of_channels;\n\t\n\tint decoded = 0;\n\n\tif (input_samplesize > output_samplesize) {\n\t\t//It is necessary to use the internal_buffer to convert the samples.\n\t\twhile (total_output_frames > 0) {\n\t\t\tamount_of_data_to_read = buffer_size / input_samplesize;\n\t\t\t\n\t\t\t//limit amount_of_data_to_read in the last loop \n\t\t\tamount_of_data_to_read = (amount_of_data_to_read > total_output_frames) ? total_output_frames : amount_of_data_to_read;\n\n\t\t\tswitch (output_format) {\n\t\t\t\tcase AudioDecoder::Format::F32: \n\t\t\t\tamount_of_data_read = DecodeAndConvertFloat(wrapped_decoder, internal_buffer, amount_of_data_to_read, input_samplesize, input_format); \n\t\t\t\tbreak;\n\t\t\t#ifdef HAVE_LIBSPEEXDSP\n\t\t\t\tcase AudioDecoder::Format::S16: \n\t\t\t\tamount_of_data_read = DecodeAndConvertInt16(wrapped_decoder, internal_buffer, amount_of_data_to_read, input_samplesize, input_format); \n\t\t\t\tbreak;\n\t\t\t#endif\n\t\t\t\tdefault: error_message = \"internal error: output_format is not convertable\"; return ERROR;\n\t\t\t}\n\t\t\tif (amount_of_data_read < 0) {\n\t\t\t\terror_message = wrapped_decoder->GetError();\n\t\t\t\treturn amount_of_data_read; //error occured\n\t\t\t}\n\n\t\t\t//Copy the converted samples\n\t\t\tfor (int i = 0; i < amount_of_data_read*output_samplesize; i++) {\n\t\t\t\tbuffer[i] = internal_buffer[i];\n\t\t\t}\n\t\t\t//Prepare next loop\n\t\t\ttotal_output_frames -= amount_of_data_read;\n\t\t\tdecoded += amount_of_data_read;\n\t\t\tbuffer += amount_of_data_read*output_samplesize;\n\n\t\t\t//If the end of the decoder is reached (it has finished)\n\t\t\tif (amount_of_data_read < amount_of_data_to_read) {\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t}\n\t} else {\n\t\t//It is possible to work inplace as length is specified for the output samplesize.\n\t\tswitch (output_format) {\n\t\t\tcase AudioDecoder::Format::F32: \n\t\t\tdecoded = DecodeAndConvertFloat(wrapped_decoder, buffer, amount_of_data_read, input_samplesize, input_format); \n\t\t\tbreak;\n\t\t#ifdef HAVE_LIBSPEEXDSP\n\t\t\tcase AudioDecoder::Format::S16: \n\t\t\tdecoded = DecodeAndConvertInt16(wrapped_decoder, buffer, amount_of_data_read, input_samplesize, input_format); \n\t\t\tbreak;\n\t\t#endif\n\t\t\tdefault: error_message = \"internal error: output_format is not convertable\"; return ERROR;\n\t\t}\n\t}\n\n\tfinished = wrapped_decoder->IsFinished();\n\tif (decoded < 0) {\n\t\terror_message = wrapped_decoder->GetError();\n\t\treturn decoded;\n\t} else {\n\t\treturn decoded*output_samplesize;\n\t}\n}\n\nint AudioResampler::FillBufferDifferentRate(uint8_t* buffer, int length) {\n\tconst int input_samplesize = GetSamplesizeForFormat(input_format);\n\tconst int output_samplesize = GetSamplesizeForFormat(output_format);\n\t//The buffer size has to be a multiple of a frame\n\tconst int buffer_size=sizeof(internal_buffer) - sizeof(internal_buffer)%(nr_of_channels*((input_samplesize>output_samplesize) ? input_samplesize : output_samplesize));\n\t\n\tint total_output_frames = length / (output_samplesize*nr_of_channels);\n\tint amount_of_samples_to_read = 0;\n\tint amount_of_samples_read = 0;\n\t\n\tuint8_t * advanced_input_buffer = internal_buffer;\n\tint unused_frames = 0;\n\tint empty_buffer_space = 0;\n\tint error = 0;\n\t\n\t#ifdef HAVE_LIBSPEEXDSP\n\t\tspx_uint32_t numerator = 0;\n\t\tspx_uint32_t denominator = 0;\n\t#endif\n\n\twhile (total_output_frames > 0) {\n\t\t//Calculate how much frames of the last cycle are unused - to reuse them\n\t\tunused_frames = conversion_data.input_frames - conversion_data.input_frames_used;\n\t\tempty_buffer_space = buffer_size / output_samplesize - unused_frames*nr_of_channels;\n\t\t\n\t\tadvanced_input_buffer = internal_buffer;\n\n\t\t//If there is still unused data in the input_buffer order it to the front\n\t\tfor (int i = 0; i < unused_frames*nr_of_channels*output_samplesize; i++) {\n\t\t\t*advanced_input_buffer = *(advanced_input_buffer + empty_buffer_space*output_samplesize);\n\t\t\tadvanced_input_buffer++;\n\t\t}\n\t\t//advanced_input_buffer is now offset to the first frame of new data!\n\n\t\t//ensure that the input buffer is not able to overrun\n\t\tamount_of_samples_to_read = (input_samplesize > output_samplesize) ? (empty_buffer_space*output_samplesize) / input_samplesize : empty_buffer_space;\n\n\t\t//Read as many frames as needed to refill the buffer (filled after the conversion to float)\n\t\tif (amount_of_samples_to_read != 0) {\n\t\t\tswitch (output_format) {\n\t\t\t\tcase AudioDecoder::Format::F32: amount_of_samples_read = DecodeAndConvertFloat(wrapped_decoder, advanced_input_buffer, amount_of_samples_to_read, input_samplesize, input_format); break;\n\t\t\t#ifdef HAVE_LIBSPEEXDSP\n\t\t\t\tcase AudioDecoder::Format::S16:  amount_of_samples_read = DecodeAndConvertInt16(wrapped_decoder, advanced_input_buffer, amount_of_samples_to_read, input_samplesize, input_format); break;\n\t\t\t#endif\n\t\t\t\tdefault: error_message = \"internal error: output_format is not convertable\"; return ERROR;\n\t\t\t}\n\t\t\tif (amount_of_samples_read < 0) {\n\t\t\t\terror_message = wrapped_decoder->GetError();\n\t\t\t\treturn amount_of_samples_read; //error occured\n\t\t\t}\n\t\t}\n\t\t//Now we have a prepared full buffer of converted values\n\n\n\t\t//Prepare the source data\n\t\tconversion_data.input_frames = amount_of_samples_read / nr_of_channels + unused_frames;\n\t\tconversion_data.output_frames = total_output_frames;\n\n\t\t#if defined(HAVE_LIBSPEEXDSP)\n\t\t\tconversion_data.input_frames_used = conversion_data.input_frames;\n\t\t\tconversion_data.output_frames_gen = conversion_data.output_frames;\n\n\t\t\t//libspeexdsp defines a sample rate conversion with a fraction (input/output)\n\t\t\tnumerator = input_rate*pitch;\n\t\t\tdenominator = output_rate * STANDARD_PITCH;\n\t\t\tif (pitch_handled_by_decoder) {\n\t\t\t\tnumerator = input_rate;\n\t\t\t\tdenominator = output_rate;\n\t\t\t}\n\t\t\tif (conversion_data.ratio_num != numerator || conversion_data.ratio_denom != denominator) {\n\t\t\t\tint err=speex_resampler_set_rate_frac(conversion_state, numerator, denominator, input_rate, output_rate);\n\t\t\t\tconversion_data.ratio_num = numerator;\n\t\t\t\tconversion_data.ratio_denom = denominator;\n\t\t\t}\n\t\t\t\n\t\t\t//A pitfall from libspeexdsp if the output buffer is defined to big - everything stutters -achieved good values with the same size as the input buffer for a maximum\n\t\t\tconversion_data.output_frames_gen=(conversion_data.input_frames<conversion_data.output_frames_gen) ? conversion_data.input_frames :conversion_data.output_frames_gen;\n\t\t\t\n\t\t\tswitch (output_format) {\n\t\t\tcase Format::F32:\n\t\t\t\terror = speex_resampler_process_interleaved_float(conversion_state, (float*)internal_buffer, &conversion_data.input_frames_used, (float*)buffer, &conversion_data.output_frames_gen);\n\t\t\t\tbreak;\n\t\t\tcase Format::S16:\n\t\t\t\terror = speex_resampler_process_interleaved_int(conversion_state, (spx_int16_t*)internal_buffer, &conversion_data.input_frames_used, (spx_int16_t*)buffer, &conversion_data.output_frames_gen);\n\t\t\t\tbreak;\n\t\t\tdefault: error_message = \"internal error: output_format is not convertable\"; return ERROR;\n\t\t\t}\n\t\t\t\n\t\t\tif (error != 0) {\n\t\t\t\terror_message = speex_resampler_strerror(error);\n\t\t\t\treturn ERROR;\n\t\t\t}\n\t\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\t\tconversion_data.data_in = (float*)internal_buffer;\n\t\t\tconversion_data.data_out = (float*)buffer;\n\t\t\tif (pitch_handled_by_decoder) {\n\t\t\t\tconversion_data.src_ratio = (output_rate*1.0) / input_rate;\n\t\t\t}\n\t\t\telse {\n\t\t\t\tconversion_data.src_ratio = (output_rate*STANDARD_PITCH *1.0) / (input_rate*pitch*1.0);\n\t\t\t}\n\t\t\tconversion_data.end_of_input = (wrapped_decoder->IsFinished()) ? 1 : 0;\n\n\t\t\t//Now let libsamplerate filter the data\n\t\t\terror = src_process(conversion_state, &conversion_data);\n\n\t\t\tif (error != 0) {\n\t\t\t\terror_message = src_strerror(error);\n\t\t\t\treturn ERROR;\n\t\t\t}\n\t\t#endif\n\n\t\ttotal_output_frames -= conversion_data.output_frames_gen;\n\t\tbuffer += conversion_data.output_frames_gen*nr_of_channels*output_samplesize;\n\n\t\tif ((conversion_data.input_frames == 0 && conversion_data.output_frames_gen <= conversion_data.output_frames) || conversion_data.output_frames_gen == 0) {\n\t\t\tfinished = true;\n\t\t\t//There is nothing left to convert - return how much samples (in bytes) are converted! \n\t\t\treturn length - total_output_frames*(output_samplesize*nr_of_channels);\n\t\t}\n\t}\n\treturn length;\n}\n\n#endif\n"
  },
  {
    "path": "source/audiodec/audio_resampler.h",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef EASYRPG_AUDIO_RESAMPLER_H\n#define EASYRPG_AUDIO_RESAMPLER_H\n\n// Headers\n#include \"audio_decoder.h\"\n#include <string>\n#include <memory>\n\n#if defined(HAVE_LIBSPEEXDSP)\n#include <speex/speex_resampler.h>\n#elif defined(HAVE_LIBSAMPLERATE)\n#include <samplerate.h>\n#endif\n\n/**\n * Audio resampler powered by Libspeexdsp or Libsamplerate\n * Wraps another decoder and provides resampling.\n */\nclass AudioResampler : public AudioDecoder {\npublic:\n\t/** Resampling quality */\n\tenum class Quality {\n\t\tHigh,\n\t\tMedium,\n\t\tLow\n\t};\n\t\n\t/**\n\t * Constructs a resampler\n\t * \n\t * @param[in] decoder The decoder which provides samples to the resampler - will be owned by the resampler\n\t * @param[in] pitch_handled Defines whether the decoder handles pitch changes by itself or not. \n\t * @param[in] quality Sets the quality rting of the resampler - higher quality implies slower filtering\n\t */\n\tAudioResampler(AudioDecoder * decoder, bool pitch_handled=false, Quality quality=Quality::Medium);\n\t\n\t/**\n\t * Destroys the resampler as well as its owned ressources\n\t */\n\t~AudioResampler();\n\n\t/**\n\t * Wraps the status querying of the contained decoder.\n\t * Used to make sure the underlying library is properly initialized.\n\t *\n\t * @return true if initializing was succesful, false otherwise\n\t */\n\tbool WasInited() const;\n\n\t/**\n\t * Wraps the opening function of the contained decoder\n\t * \n\t * @param[in] file Filepointer to a file readable by the wrapped decoder\n\t * \n\t * @return Whether the operation was successful or not\n\t */\n\tbool Open(FILE* file) override;\n\n\t/**\n\t * Wraps the seek function of the contained decoder\n\t * @note If the seek function of the wrapped decoder is \n\t *\tsomewhat corelated to time the offset is not influenced by the resampling ratio\n\t *\n\t * @param offset Offset to seek to\n\t * @param origin Position to seek from\n\t *\n\t * @return Whether seek was successful\n\t */\n\tbool Seek(size_t offset, Origin origin) override;\n\n\t/**\n\t * Wraps the tell function of the contained decoder\n\t *\n\t * @return Position in the stream\n\t */\n\tsize_t Tell() const override;\n\n\t/**\n\t * Wraps the GetTicks Function of the contained decoder\n\t *\n\t * @return Amount of MIDI ticks.\n\t */\n\tint GetTicks() const override;\n\t\n\t/**\n\t * Returns wheter the resampled audio stream is finished\n\t *\n\t * @return true if the stream has reached it's end\n\t */\n\tbool IsFinished() const override;\n\n\t/**\n\t * Retrieves the format of the audio decoder.\n\t *\n\t * @param frequency Filled with the audio frequency\n\t * @param format Filled with the audio format\n\t * @param channel Filled with the amount of channels\n\t */\n\tvoid GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const override;\n\n\t/**\n\t * Requests a certain frame format from the resampler. \n\t * Supported formats are:\n\t *  * float,int16_t for libspeexdsp\n\t *  * float for libsamplerate\n\t * The channel setting is redirected to the wrapped decoder.\n\t * The frequency setting controls the resampler.\n\t *\n\t * @param frequency Sample rate the resampler should output\n\t * @param format Audio format the resampler should output\n\t * @param channel Number of channels\n\t * @return true when all settings were set, otherwise false (use GetFormat)\n\t */\n\tbool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;\n\n\t/**\n\t * Gets the pitch multiplier.\n\t *\n\t * @return pitch multiplier\n\t */\n\tint GetPitch() const override;\n\n\t/**\n\t * Sets the pitch multiplier.\n\t * 100 = normal speed\n\t * 200 = double speed and so on\n\t * If the pitch is handled by the resampler this setting controls the resampling in conjunction with the frequency.\n\t * \n\t * @param pitch Pitch multiplier to use\n\t * @return true if pitch was set, false otherwise\n\t */\n\tbool SetPitch(int pitch) override;\n\nprivate:\n\t/**\n\t * Called by the Decode functions to fill the buffer.\n\t *\n\t * @param buffer Buffer to fill\n\t * @param size Buffer size\n\t * @return number of bytes read or -1 on error\n\t */\n\tint FillBuffer(uint8_t* buffer, int length) override;\n\t\n\t/**\n\t * Internally used by the FillBuffer function if the output rate equals the input rate\n\t */\n\tint FillBufferSameRate(uint8_t* buffer, int length);\n\n\t/**\n\t * Internally used by the FillBuffer function if resampling is necessary\n\t */\n\tint FillBufferDifferentRate(uint8_t* buffer, int length);\n\t\n\tAudioDecoder * wrapped_decoder;\n\tbool pitch_handled_by_decoder;\n\tint pitch;\n\tint sampling_quality;\n\tint lasterror;\n\tbool finished;\n\n\tint nr_of_channels;\n\tFormat input_format;\n\tint input_rate;\n\tFormat output_format;\n\tint output_rate;\n\t\n\t#if defined(HAVE_LIBSPEEXDSP)\n\t\tstruct {\n\t\t\tspx_uint32_t input_frames, output_frames;\n\t\t\tspx_uint32_t input_frames_used, output_frames_gen;\n\t\t\tspx_uint32_t ratio_num, ratio_denom;\n\t\t} conversion_data;\n\t\tSpeexResamplerState * conversion_state;\n\t#elif defined(HAVE_LIBSAMPLERATE)\n\t\tSRC_DATA conversion_data;\n\t\tSRC_STATE * conversion_state;\n\t#endif\n\n\t/**\n\t * A buffer needed for operations which can't be performed in place (e.g resampling)\n\t * The size of the buffer defines the number of calls to the resampling algorithmn\n\t * (In the cpp file sizeof is used therefore it can be adjusted to fit the available memory)\n\t */\n\tuint8_t internal_buffer[256*sizeof(float)];\n};\n\n#endif\n"
  },
  {
    "path": "source/audiodec/cd_psp2.cpp",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include <vitasdk.h>\n#include <stdlib.h>\n#include <string.h>\n#include <unistd.h>\n#define min\n#define max\nextern \"C\"{\n\t#include \"../quakedef.h\"\n}\n#undef min\n#undef max\n#include \"audio_decoder.h\"\n\nextern char* mod_path;\n\n#define BUFSIZE 8192 // Max dimension of audio buffer size\n#define NSAMPLES 2048 // Number of samples for output\n\n// Music block struct\nstruct DecodedMusic{\n\tuint8_t* audiobuf;\n\tuint8_t* audiobuf2;\n\tuint8_t* cur_audiobuf;\n\tFILE* handle;\n\tbool isPlaying;\n\tbool loop;\n\tvolatile bool pauseTrigger;\n\tvolatile bool closeTrigger;\n\tvolatile bool changeVol;\n};\n\n// Internal stuffs\nDecodedMusic* BGM = NULL;\nstd::unique_ptr<AudioDecoder> audio_decoder;\nSceUID thread, Audio_Mutex, Talk_Mutex;\nvolatile bool mustExit = false;\nfloat old_vol = 1.0;\n\n// Audio thread code\nstatic int bgmThread(unsigned int args, void* arg){\n\t\n\t// Initializing audio port\n\tint ch = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, NSAMPLES, 48000, SCE_AUDIO_OUT_MODE_STEREO);\n\tsceAudioOutSetConfig(ch, -1, -1, (SceAudioOutMode)-1);\n\told_vol = bgmvolume.value;\n\tint vol = 32767 * bgmvolume.value;\n\tint vol_stereo[] = {vol, vol};\n\tsceAudioOutSetVolume(ch, (SceAudioOutChannelFlag)(SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH), vol_stereo);\n\t\n\tDecodedMusic* mus;\n\tfor (;;){\n\t\t\n\t\t// Waiting for an audio output request\n\t\tsceKernelWaitSema(Audio_Mutex, 1, NULL);\n\t\t\n\t\t// Fetching track\n\t\tmus = BGM;\n\t\t\n\t\t// Checking if a new track is available\n\t\tif (mus == NULL){\n\t\t\t\n\t\t\t//If we enter here, we probably are in the exiting procedure\n\t\t\tif (mustExit){\n\t\t\t\tsceAudioOutReleasePort(ch);\n\t\t\t\tmustExit = false;\n\t\t\t\tsceKernelExitDeleteThread(0);\n\t\t\t}\n\t\t\n\t\t}\n\t\t\n\t\t// Initializing audio decoder\n\t\taudio_decoder = AudioDecoder::Create(mus->handle, \"Track\");\n\t\taudio_decoder->Open(mus->handle);\n\t\taudio_decoder->SetLooping(mus->loop);\n\t\taudio_decoder->SetFormat(48000, AudioDecoder::Format::S16, 2);\n\t\t\n\t\t// Initializing audio buffers\n\t\tmus->audiobuf = (uint8_t*)malloc(BUFSIZE);\n\t\tmus->audiobuf2 = (uint8_t*)malloc(BUFSIZE);\n\t\tmus->cur_audiobuf = mus->audiobuf;\n\t\t\n\t\t// Audio playback loop\n\t\tfor (;;){\n\t\t\n\t\t\t// Check if the music must be paused\n\t\t\tif (mus->pauseTrigger || mustExit){\n\t\t\t\n\t\t\t\t// Check if the music must be closed\n\t\t\t\tif (mus->closeTrigger){\n\t\t\t\t\taudio_decoder.reset();\n\t\t\t\t\tfree(mus->audiobuf);\n\t\t\t\t\tfree(mus->audiobuf2);\n\t\t\t\t\tfree(mus);\n\t\t\t\t\tBGM = NULL;\n\t\t\t\t\tmus = NULL;\n\t\t\t\t\tif (!mustExit){\n\t\t\t\t\t\tsceKernelSignalSema(Talk_Mutex, 1);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t// Check if the thread must be closed\n\t\t\t\tif (mustExit){\n\t\t\t\t\n\t\t\t\t\t// Check if the audio stream has already been closed\n\t\t\t\t\tif (mus != NULL){\n\t\t\t\t\t\tmus->closeTrigger = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\t\n\t\t\t\t\t// Recursively closing all the threads\n\t\t\t\t\tsceAudioOutReleasePort(ch);\n\t\t\t\t\tmustExit = false;\n\t\t\t\t\tsceKernelExitDeleteThread(0);\n\t\t\t\t\t\n\t\t\t\t}\n\t\t\t\n\t\t\t\tmus->isPlaying = !mus->isPlaying;\n\t\t\t\tmus->pauseTrigger = false;\n\t\t\t}\n\t\t\t\n\t\t\t// Check if a volume change is required\n\t\t\tif (mus->changeVol){\n\t\t\t\told_vol = bgmvolume.value;\n\t\t\t\tint vol = 32767 * bgmvolume.value;\n\t\t\t\tint vol_stereo[] = {vol, vol};\n\t\t\t\tsceAudioOutSetVolume(ch, (SceAudioOutChannelFlag)(SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH), vol_stereo);\n\t\t\t\tmus->changeVol = false;\n\t\t\t}\n\t\t\t\n\t\t\tif (mus->isPlaying){\n\t\t\t\t\n\t\t\t\t// Check if audio playback finished\n\t\t\t\tif ((!mus->loop) && audio_decoder->IsFinished()) mus->isPlaying = false;\n\t\t\t\t\n\t\t\t\t// Update audio output\n\t\t\t\tif (mus->cur_audiobuf == mus->audiobuf) mus->cur_audiobuf = mus->audiobuf2;\n\t\t\t\telse mus->cur_audiobuf = mus->audiobuf;\n\t\t\t\taudio_decoder->Decode(mus->cur_audiobuf, BUFSIZE);\t\n\t\t\t\tsceAudioOutOutput(ch, mus->cur_audiobuf);\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t}\n\t\t\n\t}\n\t\n}\n\nvoid CDAudio_Play(byte track, bool looping)\n{\n\tCDAudio_Stop();\n\tchar fname[256];\n\tsprintf (fname, \"%s/%s/cdtracks/track\", host_parms.basedir, (mod_path == NULL) ? GAMENAME_DIR : mod_path);\n\tif (track < 100){\n\t\tsprintf(fname, \"%s0\", fname);\n\t\tif (track < 10){\n\t\t\tsprintf(fname, \"%s0\", fname);\n\t\t}\n\t}\n\tsprintf(fname,\"%s%d\",fname,track);\n\tchar tmp[256];\n\tsprintf(tmp,\"%s.ogg\",fname);\n\t\t\n\tFILE* fd = fopen(tmp,\"rb\");\n\tif (fd == NULL){\n\t\tsprintf(tmp,\"%s.mp3\",fname);\n\t\tfd = fopen(tmp,\"rb\");\n\t}\n\tif (fd == NULL) return;\n\tDecodedMusic* memblock = (DecodedMusic*)malloc(sizeof(DecodedMusic));\n\tmemblock->handle = fd;\n\tmemblock->pauseTrigger = false;\n\tmemblock->closeTrigger = false;\n\tmemblock->isPlaying = true;\n\tmemblock->loop = looping;\n\tBGM = memblock;\n\tsceKernelSignalSema(Audio_Mutex, 1);\n}\n\nvoid CDAudio_Stop(void)\n{\n\tif (BGM != NULL){\n\t\tBGM->closeTrigger = true;\n\t\tBGM->pauseTrigger = true;\n\t\tsceKernelWaitSema(Talk_Mutex, 1, NULL);\n\t}\n}\n\n\nvoid CDAudio_Pause(void)\n{\n\tif (BGM != NULL) BGM->pauseTrigger = true;\n}\n\n\nvoid CDAudio_Resume(void)\n{\n\tif (BGM != NULL) BGM->pauseTrigger = true;\n}\n\n\nvoid CDAudio_Update(void)\n{\n\tif (BGM != NULL){\n\t\tif (old_vol != bgmvolume.value) BGM->changeVol = true;\n\t}\n}\n\n\nint CDAudio_Init(void)\n{\n\tint res;\n\t\n\t// Creating audio mutex\n\tAudio_Mutex = sceKernelCreateSema(\"Audio Mutex\", 0, 0, 1, NULL);\n\tTalk_Mutex = sceKernelCreateSema(\"Talk Mutex\", 0, 0, 1, NULL);\n\t\n\t// Creating audio thread\n\tthread = sceKernelCreateThread(\"Audio Thread\", &bgmThread, 0x10000100, 0x10000, 0, 0, NULL);\n\tsceKernelStartThread(thread, sizeof(thread), &thread);\n\t\n\treturn 0;\n}\n\n\nvoid CDAudio_Shutdown(void)\n{\t\n\tmustExit = true;\n\tsceKernelSignalSema(Audio_Mutex, 1);\n\tsceKernelWaitThreadEnd(thread, NULL, NULL);\n\tsceKernelDeleteSema(Audio_Mutex);\n\tsceKernelDeleteSema(Talk_Mutex);\n}\n"
  },
  {
    "path": "source/audiodec/decoder_mpg123.cpp",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifdef HAVE_MPG123\n\n// Headers\n#include <cassert>\n#include \"decoder_mpg123.h\"\n\nstatic bool init = false;\nstatic void Mpg123Decoder_deinit(void) {\n\tmpg123_exit();\n}\n\nstatic ssize_t custom_read(void* io, void* buffer, size_t nbyte) {\n\tFILE* f = reinterpret_cast<FILE*>(io);\n\treturn fread(buffer, 1, nbyte, f);\n}\n\nstatic off_t custom_seek(void* io, off_t offset, int seek_type) {\n\tFILE* f = reinterpret_cast<FILE*>(io);\n\tfseek(f, offset, seek_type);\n\treturn ftell(f);\n}\n\nstatic void custom_close(void* io) {\n\tFILE* f = reinterpret_cast<FILE*>(io);\n\tfclose(f);\n}\n\nstatic void noop_close(void*) {}\n\nMpg123Decoder::Mpg123Decoder() :\n\thandle(nullptr, mpg123_delete)\n{\n\tmusic_type = \"mp3\";\n\n\t// only initialize library once\n\tif (!init) {\n\t\terr = mpg123_init();\n\t\tif (err != MPG123_OK) {\n\t\t\terror_message = \"mpg123: \" + std::string(mpg123_plain_strerror(err));\n\t\t\treturn;\n\t\t}\n\t\t// setup deinitialization\n\t\tatexit(Mpg123Decoder_deinit);\n\t}\n\n\thandle.reset(mpg123_new(nullptr, &err));\n\tmpg123_replace_reader_handle(handle.get(), custom_read, custom_seek, custom_close);\n\n\tif (!handle) {\n\t\terror_message = \"mpg123: \" + std::string(mpg123_plain_strerror(err));\n\t\treturn;\n\t}\n\n\tinit = true;\n}\n\nMpg123Decoder::~Mpg123Decoder() {\n}\n\nbool Mpg123Decoder::WasInited() const {\n\treturn init;\n}\n\nbool Mpg123Decoder::Open(FILE* file) {\n\tif (!init) {\n\t\treturn false;\n\t}\n\n\tfinished = false;\n\n\terr = mpg123_open_handle(handle.get(), file);\n\tif (err != MPG123_OK) {\n\t\terror_message = \"mpg123: \" + std::string(mpg123_plain_strerror(err));\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nbool Mpg123Decoder::Seek(size_t offset, Origin origin) {\n\tfinished = false;\n\tmpg123_seek_frame(handle.get(), offset, (int)origin);\n\n\treturn true;\n}\n\nbool Mpg123Decoder::IsFinished() const {\n\treturn finished;\n}\n\nstatic int format_to_mpg123_format(AudioDecoder::Format format) {\n\tswitch (format) {\n\t\tcase AudioDecoder::Format::U8:\n\t\t\treturn MPG123_ENC_UNSIGNED_8;\n\t\tcase AudioDecoder::Format::S8:\n\t\t\treturn MPG123_ENC_SIGNED_8;\n\t\tcase AudioDecoder::Format::U16:\n\t\t\treturn MPG123_ENC_UNSIGNED_16;\n\t\tcase AudioDecoder::Format::S16:\n\t\t\treturn MPG123_ENC_SIGNED_16;\n\t\tcase AudioDecoder::Format::U32:\n\t\t\treturn MPG123_ENC_UNSIGNED_32;\n\t\tcase AudioDecoder::Format::S32:\n\t\t\treturn MPG123_ENC_SIGNED_32;\n\t\tcase AudioDecoder::Format::F32:\n\t\t\treturn MPG123_ENC_FLOAT_32;\n\t\tdefault:\n\t\t\tassert(false);\n\t}\n\n\treturn -1;\n}\n\nstatic AudioDecoder::Format mpg123_format_to_format(int format) {\n\tswitch (format) {\n\t\tcase MPG123_ENC_UNSIGNED_8:\n\t\t\treturn AudioDecoder::Format::U8;\n\t\tcase MPG123_ENC_SIGNED_8:\n\t\t\treturn AudioDecoder::Format::S8;\n\t\tcase MPG123_ENC_UNSIGNED_16:\n\t\t\treturn AudioDecoder::Format::U16;\n\t\tcase MPG123_ENC_SIGNED_16:\n\t\t\treturn AudioDecoder::Format::S16;\n\t\tcase MPG123_ENC_UNSIGNED_32:\n\t\t\treturn AudioDecoder::Format::U32;\n\t\tcase MPG123_ENC_SIGNED_32:\n\t\t\treturn AudioDecoder::Format::S32;\n\t\tcase MPG123_ENC_FLOAT_32:\n\t\t\treturn AudioDecoder::Format::F32;\n\t\tdefault:\n\t\t\tassert(false);\n\t}\n\n\treturn (AudioDecoder::Format)-1;\n}\n\nvoid Mpg123Decoder::GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const {\n\tlong freq;\n\tint ch;\n\tint fmt;\n\n\tmpg123_getformat(handle.get(), &freq, &ch, &fmt);\n\n\tfrequency = (int)freq;\n\tchannels = ch;\n\tformat = mpg123_format_to_format(fmt);\n}\n\nbool Mpg123Decoder::SetFormat(int freq, AudioDecoder::Format fmt, int channels) {\n\t// mpg123 has a built-in pseudo-resampler, not needing SDL_ConvertAudio later\n\t// Remove all available conversion formats\n\t// Add just one format to force mpg123 pseudo-resampler work\n\tmpg123_format_none(handle.get());\n\n\terr = mpg123_format(handle.get(), (long)freq, (int)channels, (int)format_to_mpg123_format(fmt));\n\tif (err != MPG123_OK) {\n\t\terr = mpg123_format(handle.get(), (long)44100, (int)channels, (int)format_to_mpg123_format(fmt));\n\t\tif (err != MPG123_OK) {\n\t\t\tmpg123_format(handle.get(), (long)44100, (int)2, (int)MPG123_ENC_SIGNED_16);\n\t\t}\n\n\t\treturn false;\n\t}\n\n\treturn err == MPG123_OK;\n}\n\nbool Mpg123Decoder::IsMp3(FILE* stream) {\n\tMpg123Decoder decoder;\n\t// Prevent stream handle destruction\n\tmpg123_replace_reader_handle(decoder.handle.get(), custom_read, custom_seek, noop_close);\n\t// Prevent skipping of too many garbage, breaks heuristic\n\tmpg123_param(decoder.handle.get(), MPG123_RESYNC_LIMIT, 64, 0.0);\n\tif (!decoder.Open(stream)) {\n\t\treturn false;\n\t}\n\n\tunsigned char buffer[1024];\n\tint err = 0;\n\tsize_t done = 0;\n\tint err_count = 0;\n\t\n\t// Read beginning of assumed MP3 file and count errors as an heuristic to detect MP3\n\tfor (int i = 0; i < 10; ++i) {\n\t\terr = mpg123_read(decoder.handle.get(), buffer, 1024, &done);\n\t\tif (err != MPG123_OK) {\n\t\t\terr_count += 1;\n\t\t}\n\t\tif (err_count >= 3) {\n\t\t\tbreak;\n\t\t}\n\t}\n\n\treturn err_count < 3;\n}\n\nint Mpg123Decoder::FillBuffer(uint8_t* buffer, int length) {\n\tint err;\n\tsize_t done = 0;\n\tsize_t decoded = 0;\n\n\t// Skip invalid frames until getting a valid one\n\tdo {\n\t\terr = mpg123_read(handle.get(), reinterpret_cast<unsigned char*>(buffer), length, &done);\n\t\tdecoded += done;\n\t} while (done && err != MPG123_OK);\n\n\tif (err == MPG123_DONE) {\n\t\tfinished = true;\n\t}\n\n\treturn (int)decoded;\n}\n\n#endif\n"
  },
  {
    "path": "source/audiodec/decoder_mpg123.h",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef EASYRPG_AUDIO_DECODER_MPG123_H\n#define EASYRPG_AUDIO_DECODER_MPG123_H\n\n// Headers\n#include \"audio_decoder.h\"\n#include <string>\n#ifdef HAVE_MPG123\n#include <mpg123.h>\n#endif\n#include <memory>\n\n/**\n * Audio decoder for MP3 powered by mpg123\n */\nclass Mpg123Decoder : public AudioDecoder {\npublic:\n\tMpg123Decoder();\n\n\t~Mpg123Decoder();\n\n\tbool WasInited() const override;\n\n\tbool Open(FILE* file) override;\n\n\tbool Seek(size_t offset, Origin origin) override;\n\n\tbool IsFinished() const override;\n\n\tvoid GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const override;\n\n\tbool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;\n\n\tstatic bool IsMp3(FILE* stream);\nprivate:\n\tint FillBuffer(uint8_t* buffer, int length) override;\n\n#ifdef HAVE_MPG123\n\tstd::unique_ptr<mpg123_handle, decltype(&mpg123_delete)> handle;\n#endif\n\tFILE* file_handle;\n\tint err = 0;\n\tbool finished = false;\n\n\tint frequency = 44100;\n};\n\n#endif\n"
  },
  {
    "path": "source/audiodec/decoder_oggvorbis.cpp",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n\n#if defined(HAVE_TREMOR) || defined(HAVE_OGGVORBIS)\n\n// Headers\n#include <cassert>\n#ifdef HAVE_TREMOR\n#include <tremor/ivorbiscodec.h>\n#include <tremor/ivorbisfile.h>\n#else\n#include <vorbis/codec.h>\n#include <vorbis/vorbisfile.h>\n#endif\n#include \"audio_decoder.h\"\n#include \"decoder_oggvorbis.h\"\n\nOggVorbisDecoder::OggVorbisDecoder() {\n\tmusic_type = \"ogg\";\n}\n\nOggVorbisDecoder::~OggVorbisDecoder() {\n\tif (ovf) {\n\t\tov_clear(ovf);\n\t\tdelete ovf;\n\t}\n}\n\nbool OggVorbisDecoder::Open(FILE* file) {\n\tfinished = false;\n\n\tif (ovf) {\n\t\tov_clear(ovf);\n\t\tdelete ovf;\n\t}\n\tovf = new OggVorbis_File;\n\n\tint res = ov_open(file, ovf, NULL, 0);\n\tif (res < 0) {\n\t\terror_message = \"OggVorbis: Error reading file\";\n\t\tdelete ovf;\n\t\tfclose(file);\n\t\treturn false;\n\t}\n\n\tvorbis_info *vi = ov_info(ovf, -1);\n\tif (!vi) {\n\t\terror_message = \"OggVorbis: Error getting file information\";\n\t\tov_clear(ovf);\n\t\tdelete ovf;\n\t\treturn false;\n\t}\n\n\t// (long)ov_pcm_total(ovf, -1)) -> decoded length in samples, maybe useful for ticks later?\n\tfrequency = vi->rate;\n\tchannels = vi->channels;\n\n\treturn true;\n}\n\nbool OggVorbisDecoder::Seek(size_t offset, Origin origin) {\n\tif (offset == 0 && origin == Origin::Begin) {\n\t\tif (ovf) {\n\t\t\tov_raw_seek(ovf, 0);\n\t\t}\n\t\tfinished = false;\n\t\treturn true;\n\t}\n\n\treturn false;\n}\n\nbool OggVorbisDecoder::IsFinished() const {\n\tif (!ovf)\n\t\treturn false;\n\n\treturn finished;\n}\n\nvoid OggVorbisDecoder::GetFormat(int& freq, AudioDecoder::Format& format, int& chans) const {\n\tfreq = frequency;\n\tformat = Format::S16;\n\tchans = channels;\n}\n\nbool OggVorbisDecoder::SetFormat(int freq, AudioDecoder::Format format, int chans) {\n\tif (freq != frequency || chans != channels || format != Format::S16)\n\t\treturn false;\n\n\treturn true;\n}\n\nbool OggVorbisDecoder::SetPitch(int pitch) {\n\tif (pitch != 100) {\n\t\treturn false;\n\t}\n\n\treturn true;\n}\n\nint OggVorbisDecoder::FillBuffer(uint8_t* buffer, int length) {\n\tif (!ovf)\n\t\treturn -1;\n\n\tstatic int section;\n\tint read = 0;\n\tint to_read = length;\n\n\tdo {\n#ifdef HAVE_TREMOR\n\t\tread = ov_read(ovf, reinterpret_cast<char*>(buffer + length - to_read), to_read, &section);\n#else\n\t\tread = ov_read(ovf, reinterpret_cast<char*>(buffer + length - to_read), to_read, 0/*LE*/, 2/*16bit*/, 1/*signed*/, &section);\n#endif\n\t\t// stop decoding when error or end of file\n\t\tif (read <= 0)\n\t\t\tbreak;\n\n\t\tto_read -= read;\n\t} while(to_read > 0);\n\n\t// end of file\n\tif (read == 0)\n\t\tfinished = true;\n\n\t// error\n\tif (read < 0)\n\t\treturn -1;\n\n\treturn length - to_read;\n}\n\n#endif\n"
  },
  {
    "path": "source/audiodec/decoder_oggvorbis.h",
    "content": "/*\n * This file is part of EasyRPG Player.\n *\n * EasyRPG Player is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * EasyRPG Player is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with EasyRPG Player. If not, see <http://www.gnu.org/licenses/>.\n */\n\n#ifndef EASYRPG_AUDIO_DECODER_OGGVORBIS_H\n#define EASYRPG_AUDIO_DECODER_OGGVORBIS_H\n\n// Headers\n#include <string>\n#include <memory>\n#ifdef HAVE_TREMOR\n#include <tremor/ivorbiscodec.h>\n#include <tremor/ivorbisfile.h>\n#elif HAVE_OGGVORBIS\n#include <vorbis/codec.h>\n#include <vorbis/vorbisfile.h>\n#endif\n#include \"audio_decoder.h\"\n\n/**\n * Audio decoder for Ogg Vorbis powered by libTremor/libOgg+libVorbis\n */\nclass OggVorbisDecoder : public AudioDecoder {\npublic:\n\tOggVorbisDecoder();\n\n\t~OggVorbisDecoder();\n\n\t// Audio Decoder interface\n\tbool Open(FILE* file) override;\n\n\tbool Seek(size_t offset, Origin origin) override;\n\n\tbool IsFinished() const override;\n\n\tvoid GetFormat(int& frequency, AudioDecoder::Format& format, int& channels) const override;\n\n\tbool SetFormat(int frequency, AudioDecoder::Format format, int channels) override;\n\n\tbool SetPitch(int pitch) override;\nprivate:\n\tint FillBuffer(uint8_t* buffer, int length) override;\n\n#if defined(HAVE_TREMOR) || defined(HAVE_OGGVORBIS)\n\tOggVorbis_File *ovf = NULL;\n#endif\n\tbool finished = false;\n\tint frequency = 44100;\n\tint channels = 2;\n};\n\n#endif\n"
  },
  {
    "path": "source/block16.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\nLEnter16_16:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch0:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch1:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch2:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch3:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch4:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch5:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch6:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch7:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\nLEnter8_16:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch8:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch9:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch10:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch11:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\nLEnter4_16:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch12:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch13:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n\nLEnter2_16:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovw\t0x12345678(,%eax,2),%ax\nLBPatch14:\n\taddl\t%ebp,%edx\n\tmovw\t%ax,(%edi)\n\tmovw\t0x12345678(,%ecx,2),%cx\nLBPatch15:\n\tmovw\t%cx,2(%edi)\n\taddl\t$0x4,%edi\n"
  },
  {
    "path": "source/block8.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\nLEnter16_8:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch0:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch1:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch2:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch3:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch4:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch5:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch6:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch7:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\nLEnter8_8:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch8:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch9:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch10:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch11:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\nLEnter4_8:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch12:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch13:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\nLEnter2_8:\n\tmovb\t(%esi),%al\n\tmovb\t(%esi,%ebx,),%cl\n\tmovb\t%dh,%ah\n\taddl\t%ebp,%edx\n\tmovb\t%dh,%ch\n\tleal\t(%esi,%ebx,2),%esi\n\tmovb\t0x12345678(%eax),%al\nLBPatch14:\n\taddl\t%ebp,%edx\n\tmovb\t%al,(%edi)\n\tmovb\t0x12345678(%ecx),%cl\nLBPatch15:\n\tmovb\t%cl,1(%edi)\n\taddl\t$0x2,%edi\n\n"
  },
  {
    "path": "source/bspfile.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n\n// upper design bounds\n\n#define\tMAX_MAP_HULLS\t\t4\n\n#define\tMAX_MAP_MODELS\t\t256\n#define\tMAX_MAP_BRUSHES\t\t4096\n#define\tMAX_MAP_ENTITIES\t1024\n#define\tMAX_MAP_ENTSTRING\t65536\n\n#define\tMAX_MAP_PLANES\t\t32767\n#define\tMAX_MAP_NODES\t\t32767\t\t// because negative shorts are contents\n#define\tMAX_MAP_CLIPNODES\t32767\n#define\tMAX_MAP_LEAFS\t\t65535\n#define\tMAX_MAP_VERTS\t\t65535\n#define\tMAX_MAP_FACES\t\t65535\n#define\tMAX_MAP_MARKSURFACES 65535\n#define\tMAX_MAP_TEXINFO\t\t4096\n#define\tMAX_MAP_EDGES\t\t256000\n#define\tMAX_MAP_SURFEDGES\t512000\n#define\tMAX_MAP_TEXTURES\t512\n#define\tMAX_MAP_MIPTEX\t\t0x200000\n#define\tMAX_MAP_LIGHTING\t0x100000\n#define\tMAX_MAP_VISIBILITY\t0x100000\n\n#define\tMAX_MAP_PORTALS\t\t65536\n\n// key / value pair sizes\n\n#define\tMAX_KEY\t\t32\n#define\tMAX_VALUE\t1024\n\n//=============================================================================\n\n\n#define Q1_BSPVERSION\t29\n#define HL_BSPVERSION\t30\n\n// RMQ support (2PSB). 32bits instead of shorts for all but bbox sizes (which still use shorts)\n#define BSP2VERSION_2PSB (('B' << 24) | ('S' << 16) | ('P' << 8) | '2')\n\n// BSP2 support. 32bits instead of shorts for everything (bboxes use floats)\n#define BSP2VERSION_BSP2 (('B' << 0) | ('S' << 8) | ('P' << 16) | ('2'<<24))\n\n#define\tTOOLVERSION\t2\n\ntypedef struct\n{\n\tint\t\tfileofs, filelen;\n} lump_t;\n\n#define\tLUMP_ENTITIES\t0\n#define\tLUMP_PLANES\t\t1\n#define\tLUMP_TEXTURES\t2\n#define\tLUMP_VERTEXES\t3\n#define\tLUMP_VISIBILITY\t4\n#define\tLUMP_NODES\t\t5\n#define\tLUMP_TEXINFO\t6\n#define\tLUMP_FACES\t\t7\n#define\tLUMP_LIGHTING\t8\n#define\tLUMP_CLIPNODES\t9\n#define\tLUMP_LEAFS\t\t10\n#define\tLUMP_MARKSURFACES 11\n#define\tLUMP_EDGES\t\t12\n#define\tLUMP_SURFEDGES\t13\n#define\tLUMP_MODELS\t\t14\n\n#define\tHEADER_LUMPS\t15\n\ntypedef struct\n{\n\tfloat\t\tmins[3], maxs[3];\n\tfloat\t\torigin[3];\n\tint\t\t\theadnode[MAX_MAP_HULLS];\n\tint\t\t\tvisleafs;\t\t// not including the solid leaf 0\n\tint\t\t\tfirstface, numfaces;\n} dmodel_t;\n\ntypedef struct\n{\n\tint\t\t\tversion;\t\n\tlump_t\t\tlumps[HEADER_LUMPS];\n} dheader_t;\n\ntypedef struct\n{\n\tint\t\t\tnummiptex;\n\tint\t\t\tdataofs[4];\t\t// [nummiptex]\n} dmiptexlump_t;\n\n#define\tMIPLEVELS\t4\ntypedef struct miptex_s\n{\n\tchar\t\tname[16];\n\tunsigned\twidth, height;\n\tunsigned\toffsets[MIPLEVELS];\t\t// four mip maps stored\n} miptex_t;\n\n\ntypedef struct\n{\n\tfloat\tpoint[3];\n} dvertex_t;\n\n\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\n// 3-5 are non-axial planes snapped to the nearest\n#define\tPLANE_ANYX\t\t3\n#define\tPLANE_ANYY\t\t4\n#define\tPLANE_ANYZ\t\t5\n\ntypedef struct\n{\n\tfloat\tnormal[3];\n\tfloat\tdist;\n\tint\t\ttype;\t\t// PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate\n} dplane_t;\n\n\n\n#define\tCONTENTS_EMPTY\t\t-1\n#define\tCONTENTS_SOLID\t\t-2\n#define\tCONTENTS_WATER\t\t-3\n#define\tCONTENTS_SLIME\t\t-4\n#define\tCONTENTS_LAVA\t\t-5\n#define\tCONTENTS_SKY\t\t-6\n#define\tCONTENTS_ORIGIN\t\t-7\t\t// removed at csg time\n#define\tCONTENTS_CLIP\t\t-8\t\t// changed to contents_solid\n\n#define\tCONTENTS_CURRENT_0\t\t-9\n#define\tCONTENTS_CURRENT_90\t\t-10\n#define\tCONTENTS_CURRENT_180\t-11\n#define\tCONTENTS_CURRENT_270\t-12\n#define\tCONTENTS_CURRENT_UP\t\t-13\n#define\tCONTENTS_CURRENT_DOWN\t-14\n\n\n// !!! if this is changed, it must be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tshort\t\tchildren[2];\t// negative numbers are -(leafs+1), not nodes\n\tshort\t\tmins[3];\t\t// for sphere culling\n\tshort\t\tmaxs[3];\n\tunsigned short\tfirstface;\n\tunsigned short\tnumfaces;\t// counting both sides\n} dsnode_t;\n\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tint\t\t\tchildren[2];\t// negative numbers are -(leafs+1), not nodes\n\tshort\t\tmins[3];\t\t// for sphere culling\n\tshort\t\tmaxs[3];\n\tunsigned int\tfirstface;\n\tunsigned int\tnumfaces;\t// counting both sides\n} dl1node_t;\n\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tint\t\t\tchildren[2];\t// negative numbers are -(leafs+1), not nodes\n\tfloat\t\tmins[3];\t\t// for sphere culling\n\tfloat\t\tmaxs[3];\n\tunsigned int\tfirstface;\n\tunsigned int\tnumfaces;\t// counting both sides\n} dl2node_t;\n\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tshort\t\tchildren[2];\t// negative numbers are contents\n} dsclipnode_t;\n\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tint\t\t\tchildren[2];\t// negative numbers are contents\n} dlclipnode_t;\n\ntypedef struct texinfo_s\n{\n\tfloat\t\tvecs[2][4];\t\t// [s/t][xyz offset]\n\tint\t\t\tmiptex;\n\tint\t\t\tflags;\n} texinfo_t;\n#define\tTEX_SPECIAL\t\t1\t\t// sky or slime, no lightmap or 256 subdivision\n\n// note that edge 0 is never used, because negative edge nums are used for\n// counterclockwise use of the edge in a face\ntypedef struct\n{\n\tunsigned short\tv[2];\t\t// vertex numbers\n} dsedge_t;\n\ntypedef struct\n{\n\tunsigned int\tv[2];\t\t// vertex numbers\n} dledge_t;\n\n#define\tMAXLIGHTMAPS\t4\ntypedef struct\n{\n\tshort\t\tplanenum;\n\tshort\t\tside;\n\n\tint\t\t\tfirstedge;\t\t// we must support > 64k edges\n\tshort\t\tnumedges;\t\n\tshort\t\ttexinfo;\n\n// lighting info\n\tbyte\t\tstyles[MAXLIGHTMAPS];\n\tint\t\t\tlightofs;\t\t// start of [numstyles*surfsize] samples\n} dsface_t;\n\ntypedef struct\n{\n\tint\t\t\tplanenum;\n\tint\t\t\tside;\n\n\n\tint\t\t\tfirstedge;\t\t// we must support > 64k edges\n\tint\t\t\tnumedges;\n\tint\t\t\ttexinfo;\n\n// lighting info\n\tbyte\t\tstyles[MAXLIGHTMAPS];\n\tint\t\t\tlightofs;\t\t// start of [numstyles*surfsize] samples\n} dlface_t;\n\n#define\tAMBIENT_WATER\t0\n#define\tAMBIENT_SKY\t\t1\n#define\tAMBIENT_SLIME\t2\n#define\tAMBIENT_LAVA\t3\n\n#define\tNUM_AMBIENTS\t\t\t4\t\t// automatic ambient sounds\n\n// leaf 0 is the generic CONTENTS_SOLID leaf, used for all solid areas\n// all other leafs need visibility info\ntypedef struct\n{\n\tint\t\t\tcontents;\n\tint\t\t\tvisofs;\t\t\t\t// -1 = no visibility info\n\n\tshort\t\tmins[3];\t\t\t// for frustum culling\n\tshort\t\tmaxs[3];\n\n\tunsigned short\t\tfirstmarksurface;\n\tunsigned short\t\tnummarksurfaces;\n\n\tbyte\t\tambient_level[NUM_AMBIENTS];\n} dsleaf_t;\n\ntypedef struct\n{\n\tint\t\t\tcontents;\n\tint\t\t\tvisofs;\t\t\t\t// -1 = no visibility info\n\n\tshort\t\tmins[3];\t\t\t// for frustum culling\n\tshort\t\tmaxs[3];\n\n\tunsigned int\t\tfirstmarksurface;\n\tunsigned int\t\tnummarksurfaces;\n\n\tbyte\t\tambient_level[NUM_AMBIENTS];\n} dl1leaf_t;\n\ntypedef struct\n{\n\tint\t\t\tcontents;\n\tint\t\t\tvisofs;\t\t\t\t// -1 = no visibility info\n\n\tfloat\t\tmins[3];\t\t\t// for frustum culling\n\tfloat\t\tmaxs[3];\n\n\tunsigned int\t\tfirstmarksurface;\n\tunsigned int\t\tnummarksurfaces;\n\n\tbyte\t\tambient_level[NUM_AMBIENTS];\n} dl2leaf_t;\n\n//============================================================================\n\n#ifndef QUAKE_GAME\n\n#define\tANGLE_UP\t-1\n#define\tANGLE_DOWN\t-2\n\n\n// the utilities get to be lazy and just use large static arrays\n\nextern\tint\t\t\tnummodels;\nextern\tdmodel_t\tdmodels[MAX_MAP_MODELS];\n\nextern\tint\t\t\tvisdatasize;\nextern\tbyte\t\tdvisdata[MAX_MAP_VISIBILITY];\n\nextern\tint\t\t\tlightdatasize;\nextern\tbyte\t\tdlightdata[MAX_MAP_LIGHTING];\n\nextern\tint\t\t\ttexdatasize;\nextern\tbyte\t\tdtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t)\n\nextern\tint\t\t\tentdatasize;\nextern\tchar\t\tdentdata[MAX_MAP_ENTSTRING];\n\nextern\tint\t\t\tnumleafs;\nextern\tdleaf_t\t\tdleafs[MAX_MAP_LEAFS];\n\nextern\tint\t\t\tnumplanes;\nextern\tdplane_t\tdplanes[MAX_MAP_PLANES];\n\nextern\tint\t\t\tnumvertexes;\nextern\tdvertex_t\tdvertexes[MAX_MAP_VERTS];\n\nextern\tint\t\t\tnumnodes;\nextern\tdnode_t\t\tdnodes[MAX_MAP_NODES];\n\nextern\tint\t\t\tnumtexinfo;\nextern\ttexinfo_t\ttexinfo[MAX_MAP_TEXINFO];\n\nextern\tint\t\t\tnumfaces;\nextern\tdface_t\t\tdfaces[MAX_MAP_FACES];\n\nextern\tint\t\t\tnumclipnodes;\nextern\tdclipnode_t\tdclipnodes[MAX_MAP_CLIPNODES];\n\nextern\tint\t\t\tnumedges;\nextern\tdedge_t\t\tdedges[MAX_MAP_EDGES];\n\nextern\tint\t\t\tnummarksurfaces;\nextern\tunsigned short\tdmarksurfaces[MAX_MAP_MARKSURFACES];\n\nextern\tint\t\t\tnumsurfedges;\nextern\tint\t\t\tdsurfedges[MAX_MAP_SURFEDGES];\n\n\nvoid DecompressVis (byte *in, byte *decompressed);\nint CompressVis (byte *vis, byte *dest);\n\nvoid\tLoadBSPFile (char *filename);\nvoid\tWriteBSPFile (char *filename);\nvoid\tPrintBSPFileSizes (void);\n\n//===============\n\n\ntypedef struct epair_s\n{\n\tstruct epair_s\t*next;\n\tchar\t*key;\n\tchar\t*value;\n} epair_t;\n\ntypedef struct\n{\n\tvec3_t\t\torigin;\n\tint\t\t\tfirstbrush;\n\tint\t\t\tnumbrushes;\n\tepair_t\t\t*epairs;\n} entity_t;\n\nextern\tint\t\t\tnum_entities;\nextern\tentity_t\tentities[MAX_MAP_ENTITIES];\n\nvoid\tParseEntities (void);\nvoid\tUnparseEntities (void);\n\nvoid \tSetKeyValue (entity_t *ent, signed char *key, signed char *value);\nsigned char \t*ValueForKey (entity_t *ent, signed char *key);\n// will return \"\" if not present\n\nvec_t\tFloatForKey (entity_t *ent, signed char *key);\nvoid \tGetVectorForKey (entity_t *ent, signed char *key, vec3_t vec);\n\nepair_t *ParseEpair (void);\n\n#endif\n"
  },
  {
    "path": "source/cdaudio.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\nint CDAudio_Init(void);\nvoid CDAudio_Play(byte track, bool looping);\nvoid CDAudio_Stop(void);\nvoid CDAudio_Pause(void);\nvoid CDAudio_Resume(void);\nvoid CDAudio_Shutdown(void);\nvoid CDAudio_Update(void);\n"
  },
  {
    "path": "source/chase.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// chase.c -- chase camera code\n\n#include \"quakedef.h\"\n\nCVAR(chase_active,\t0,\tCVAR_NONE)\t// CVAR enabling thirdperson\nCVAR(chase_back,\t100, CVAR_NONE)\nCVAR(chase_up,\t\t16, CVAR_NONE)\nCVAR(chase_right,\t0,\tCVAR_NONE)\n\n//----------------------------------------------\n\nvec3_t\tchase_pos;\nvec3_t\tchase_angles;\t\nvec3_t\tchase_dest;\nvec3_t\tchase_dest_angles;\n\n\nvoid Chase_Init (void)\n{\n\tCvar_RegisterVariable (&chase_back);\n\tCvar_RegisterVariable (&chase_up);\n\tCvar_RegisterVariable (&chase_right);\n\tCvar_RegisterVariable (&chase_active);\n}\n\nvoid Chase_Reset (void)\n{\n\t// for respawning and teleporting\n//\tstart position 12 units behind head\n}\n\nvoid TraceLine (vec3_t start, vec3_t end, vec3_t impact)\n{\n\ttrace_t\ttrace;\n\n\tmemset (&trace, 0, sizeof(trace));\n\tSV_RecursiveHullCheck (cl.worldmodel->hulls, 0, 0, 1, start, end, &trace);\n\n\tVectorCopy (trace.endpos, impact);\n}\n\nvoid Chase_Update (void)\n{\n\tint\t\ti;\n\tfloat\tdist;\n\tvec3_t\tforward, up, right;\n\tvec3_t\tdest, stop;\n\n\n\t// if can't see player, reset\n\tAngleVectors (cl.viewangles, forward, right, up);\n\n\t// calc exact destination\n\tfor (i=0 ; i<3 ; i++)\n\t\tchase_dest[i] = r_refdef.vieworg[i] \n\t\t- forward[i]*chase_back.value\n\t\t- right[i]*chase_right.value;\n\tchase_dest[2] = r_refdef.vieworg[2] + chase_up.value;\n\n\t// find the spot the player is looking at\n\tVectorMA (r_refdef.vieworg, 4096, forward, dest);\n\tTraceLine (r_refdef.vieworg, dest, stop);\n\n\t// calculate pitch to look at the same spot from camera\n\tVectorSubtract (stop, r_refdef.vieworg, stop);\n\tdist = DotProduct (stop, forward);\n\tif (dist < 1)\n\t\tdist = 1;\n\tr_refdef.viewangles[PITCH] = -atan(stop[2] / dist) / M_PI * 180;\n\n\t// move towards destination\n\tVectorCopy (chase_dest, r_refdef.vieworg);\n}\n\n"
  },
  {
    "path": "source/cl_demo.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n\nbool benchmark;\n\nvoid CL_FinishTimeDemo (void);\n\n/*\n==============================================================================\n\nDEMO CODE\n\nWhen a demo is playing back, all NET_SendMessages are skipped, and\nNET_GetMessages are read from the demo file.\n\nWhenever cl.time gets past the last received message, another message is\nread from the demo file.\n==============================================================================\n*/\n\n/*\n==============\nCL_StopPlayback\n\nCalled when a demo file runs out, or the user starts a game\n==============\n*/\nvoid CL_StopPlayback (void)\n{\n\tif (!cls.demoplayback)\n\t\treturn;\n\n\tfclose (cls.demofile);\n\tcls.demoplayback = false;\n\tcls.demofile = NULL;\n\tcls.state = ca_disconnected;\n\n\tif (cls.timedemo || benchmark)\n\t\tCL_FinishTimeDemo ();\n}\n\n/*\n====================\nCL_WriteDemoMessage\n\nDumps the current net message, prefixed by the length and view angles\n====================\n*/\nvoid CL_WriteDemoMessage (void)\n{\n\tint\t\tlen;\n\tint\t\ti;\n\tfloat\tf;\n\n\tlen = LittleLong (net_message.cursize);\n\tfwrite (&len, 4, 1, cls.demofile);\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tf = LittleFloat (cl.viewangles[i]);\n\t\tfwrite (&f, 4, 1, cls.demofile);\n\t}\n\tfwrite (net_message.data, net_message.cursize, 1, cls.demofile);\n\tfflush (cls.demofile);\n}\n\n/*\n====================\nCL_GetMessage\n\nHandles recording and playback of demos, on top of NET_ code\n====================\n*/\n\nbool bBenchmarkStarted;\nint CL_GetMessage (void)\n{\n\tint\t\tr, i;\n\tfloat\tf;\n\t\n\tif\t(cls.demoplayback)\n\t{\n\t// decide if it is time to grab the next message\t\t\n\t\tif (cls.signon == SIGNONS)\t// always grab until fully connected\n\t\t{\n\t\t\tif (cls.timedemo && !benchmark)\n\t\t\t{\n\t\t\t\tif (host_framecount == cls.td_lastframe)\n\t\t\t\t\treturn 0;\t\t// already read this frame's message\n\t\t\t\tcls.td_lastframe = host_framecount;\n\t\t\t// if this is the second frame, grab the real td_starttime\n\t\t\t// so the bogus time on the first frame doesn't count\n\t\t\t\tif (host_framecount == cls.td_startframe + 1 && !benchmark){\n\t\t\t\t\tcls.td_starttime = realtime;\n\t\t\t\t}\n\t\t\t\telse if (host_framecount == cls.td_startframe + 30 && key_dest == key_benchmark) { bBenchmarkStarted = true; benchmark = true; }// Ignore first sec for the benchmark\n\t\t\t}\n\t\t\telse if ( /* cl.time > 0 && */ cl.time <= cl.mtime[0])\n\t\t\t{\n\t\t\t\t\treturn 0;\t\t// don't need another message yet\n\t\t\t}\n\t\t}\n\t\t\n\t// get the next message\n\t\tfread (&net_message.cursize, 4, 1, cls.demofile);\n\t\tVectorCopy (cl.mviewangles[0], cl.mviewangles[1]);\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\tr = fread (&f, 4, 1, cls.demofile);\n\t\t\tcl.mviewangles[0][i] = LittleFloat (f);\n\t\t}\n\t\t\n\t\tnet_message.cursize = LittleLong (net_message.cursize);\n\t\tif (net_message.cursize > MAX_MSGLEN)\n\t\t\tSys_Error (\"Demo message > MAX_MSGLEN\");\n\t\tr = fread (net_message.data, net_message.cursize, 1, cls.demofile);\n\t\tif (r != 1)\n\t\t{\n\t\t\tCL_StopPlayback ();\n\t\t\treturn 0;\n\t\t}\n\t\n\t\treturn 1;\n\t}\n\n\twhile (1)\n\t{\n\t\tr = NET_GetMessage (cls.netcon);\n\t\t\n\t\tif (r != 1 && r != 2)\n\t\t\treturn r;\n\t\n\t// discard nop keepalive message\n\t\tif (net_message.cursize == 1 && net_message.data[0] == svc_nop)\n\t\t\tCon_Printf (\"<-- server to client keepalive\\n\");\n\t\telse\n\t\t\tbreak;\n\t}\n\n\tif (cls.demorecording)\n\t\tCL_WriteDemoMessage ();\n\t\n\treturn r;\n}\n\n\n/*\n====================\nCL_Stop_f\n\nstop recording a demo\n====================\n*/\nvoid CL_Stop_f (void)\n{\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (!cls.demorecording)\n\t{\n\t\tCon_Printf (\"Not recording a demo.\\n\");\n\t\treturn;\n\t}\n\n// write a disconnect message to the demo file\n\tSZ_Clear (&net_message);\n\tMSG_WriteByte (&net_message, svc_disconnect);\n\tCL_WriteDemoMessage ();\n\n// finish up\n\tfclose (cls.demofile);\n\tcls.demofile = NULL;\n\tcls.demorecording = false;\n\tCon_Printf (\"Completed demo\\n\");\n}\n\n/*\n====================\nCL_Record_f\n\nrecord <demoname> <map> [cd track]\n====================\n*/\nvoid CL_Record_f (void)\n{\n\tint\t\tc;\n\tchar\tname[MAX_OSPATH];\n\tint\t\ttrack;\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tc = Cmd_Argc();\n\tif (c != 2 && c != 3 && c != 4)\n\t{\n\t\tCon_Printf (\"record <demoname> [<map> [cd track]]\\n\");\n\t\treturn;\n\t}\n\n\tif (strstr(Cmd_Argv(1), \"..\"))\n\t{\n\t\tCon_Printf (\"Relative pathnames are not allowed.\\n\");\n\t\treturn;\n\t}\n\n\tif (c == 2 && cls.state == ca_connected)\n\t{\n\t\tCon_Printf(\"Can not record - already connected to server\\nClient demo recording must be started before connecting\\n\");\n\t\treturn;\n\t}\n\n// write the forced cd track number, or -1\n\tif (c == 4)\n\t{\n\t\ttrack = atoi(Cmd_Argv(3));\n\t\tCon_Printf (\"Forcing CD track to %i\\n\", cls.forcetrack);\n\t}\n\telse\n\t\ttrack = -1;\t\n\n\tsprintf (name, \"%s/%s\", com_gamedir, Cmd_Argv(1));\n\t\n//\n// start the map up\n//\n\tif (c > 2)\n\t\tCmd_ExecuteString ( va(\"map %s\", Cmd_Argv(2)), src_command);\n\t\n//\n// open the demo file\n//\n\tCOM_DefaultExtension (name, \".dem\");\n\n\tCon_Printf (\"recording to %s.\\n\", name);\n\tcls.demofile = fopen (name, \"wb\");\n\tif (!cls.demofile)\n\t{\n\t\tCon_Printf (\"ERROR: couldn't open.\\n\");\n\t\treturn;\n\t}\n\n\tcls.forcetrack = track;\n\tfprintf (cls.demofile, \"%i\\n\", cls.forcetrack);\n\t\n\tcls.demorecording = true;\n}\n\n\n/*\n====================\nCL_PlayDemo_f\n\nplay [demoname]\n====================\n*/\nvoid CL_PlayDemo_f (void)\n{\n\tchar\tname[256];\n\tint c;\n\tbool neg = false;\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"play <demoname> : plays a demo\\n\");\n\t\treturn;\n\t}\n\n//\n// disconnect from server\n//\n\tCL_Disconnect ();\n\t\n//\n// open the demo file\n//\n\tstrcpy (name, Cmd_Argv(1));\n\tCOM_DefaultExtension (name, \".dem\");\n\n\tCon_Printf (\"Playing demo from %s.\\n\", name);\n\tCOM_FOpenFile (name, &cls.demofile, NULL);\n\tif (!cls.demofile)\n\t{\n\t\tCon_Printf (\"ERROR: couldn't open.\\n\");\n\t\tcls.demonum = -1;\t\t// stop demo loop\n\t\treturn;\n\t}\n\n\tcls.demoplayback = true;\n\tcls.state = ca_connected;\n\tcls.forcetrack = 0;\n\n\twhile ((c = getc(cls.demofile)) != '\\n')\n\t\tif (c == '-')\n\t\t\tneg = true;\n\t\telse\n\t\t\tcls.forcetrack = cls.forcetrack * 10 + (c - '0');\n\n\tif (neg)\n\t\tcls.forcetrack = -cls.forcetrack;\n// ZOID, fscanf is evil\n//\tfscanf (cls.demofile, \"%i\\n\", &cls.forcetrack);\n}\n\n/*\n====================\nCL_FinishTimeDemo\n\n====================\n*/\nextern int average_fps;\nvoid CL_FinishTimeDemo (void)\n{\n\tint\t\tframes;\n\tfloat\ttime;\n\t\n\tcls.timedemo = false;\n\t\n// the first frame didn't count\n\tframes = (host_framecount - cls.td_startframe) - 1;\n\ttime = realtime - cls.td_starttime;\n\tif (!time)\n\t\ttime = 1;\n\tif (benchmark){\n\t\taverage_fps = frames/time;\n\t\tkey_dest = key_menu;\n\t\tm_state = m_benchmark;\n\t\tbenchmark = false;\n\t}else Con_Printf (\"%i frames %5.1f seconds %5.1f fps\\n\", frames, time, frames/time);\n}\n\n/*\n====================\nCL_TimeDemo_f\n\ntimedemo [demoname]\n====================\n*/\nvoid CL_TimeDemo_f (void)\n{\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"timedemo <demoname> : gets demo speeds\\n\");\n\t\treturn;\n\t}\n\n\tCL_PlayDemo_f ();\n\t\n// cls.td_starttime will be grabbed at the second frame of the demo, so\n// all the loading time doesn't get counted\n\t\n\tcls.timedemo = true;\n\tcls.td_startframe = host_framecount;\n\tcls.td_lastframe = -1;\t\t// get a new message this frame\n}\n\n/*\n====================\nCL_Benchmark_f\n\nbenchmark [demoname]\n====================\n*/\nextern int max_fps;\nextern int min_fps;\nvoid CL_Benchmark_f (void)\n{\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"benchmark <demoname> : starts a demo benchmark\\n\");\n\t\treturn;\n\t}\n\n\tCL_PlayDemo_f ();\n\t\n\t// cls.td_starttime will be grabbed at the second frame of the demo, so\n\t// all the loading time doesn't get counted\n\t\n\t// resetting fps counters\n\tmax_fps = 0;\n\tmin_fps = 999;\n\t\n\t//benchmark = true;\n\tcls.timedemo = true;\n\tcls.td_startframe = host_framecount;\n\tcls.td_lastframe = -1;\t\t// get a new message this frame\n}\n\n"
  },
  {
    "path": "source/cl_input.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cl.input.c  -- builds an intended movement command to send to the server\n\n// Quake is a trademark of Id Software, Inc., (c) 1996 Id Software, Inc. All\n// rights reserved.\n\n#include \"quakedef.h\"\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 a parameter to the command so it can be matched up with\nthe release.\n\nstate bit 0 is the current state of the key\nstate bit 1 is edge triggered on the up to down transition\nstate bit 2 is edge triggered on the down to up transition\n\n===============================================================================\n*/\n\nCVAR(cl_upspeed, 200, CVAR_NONE)\nCVAR(cl_forwardspeed, 200, CVAR_ARCHIVE)\nCVAR(cl_backspeed, 200, CVAR_ARCHIVE)\nCVAR(cl_sidespeed, 350, CVAR_NONE)\n\nCVAR(cl_movespeedkey, 2.0, CVAR_NONE)\nCVAR(cl_yawspeed, 140, CVAR_NONE)\nCVAR(cl_pitchspeed, 150, CVAR_NONE)\nCVAR(cl_anglespeedkey, 1.5, CVAR_NONE)\n\nCVAR(cl_fullpitch, 0, CVAR_NONE) // ProQuake - get rid of the \"unknown command\" messages\n\n//----------------------------------------------\n\nkbutton_t\tin_mlook, in_klook;\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, in_use, in_jump, in_attack;\nkbutton_t\tin_up, in_down;\n\nint\t\t\tin_impulse;\n\n\nvoid KeyDown (kbutton_t *b)\n{\n\tint\t\tk;\n\tchar\t*c;\n\n\tc = Cmd_Argv(1);\n\tif (c[0])\n\t\tk = atoi(c);\n\telse\n\t\tk = -1;\t\t// typed manually at the console for continuous down\n\n\tif (k == b->down[0] || k == b->down[1])\n\t\treturn;\t\t// repeating key\n\n\tif (!b->down[0])\n\t\tb->down[0] = k;\n\telse if (!b->down[1])\n\t\tb->down[1] = k;\n\telse\n\t{\n\t\tCon_Printf (\"Three keys down for a button!\\n\");\n\t\treturn;\n\t}\n\n\tif (b->state & 1)\n\t\treturn;\t\t// still down\n\tb->state |= 1 + 2;\t// down + impulse down\n}\n\nvoid KeyUp (kbutton_t *b)\n{\n\tint\t\tk;\n\tchar\t*c;\n\n\tc = Cmd_Argv(1);\n\tif (c[0])\n\t\tk = atoi(c);\n\telse\n\t{ // typed manually at the console, assume for unsticking, so clear all\n\t\tb->down[0] = b->down[1] = 0;\n\t\tb->state = 4;\t// impulse up\n\t\treturn;\n\t}\n\n\tif (b->down[0] == k)\n\t\tb->down[0] = 0;\n\telse if (b->down[1] == k)\n\t\tb->down[1] = 0;\n\telse\n\t\treturn;\t\t// key up without coresponding down (menu pass through)\n\tif (b->down[0] || b->down[1])\n\t\treturn;\t\t// some other key is still holding it down\n\n\tif (!(b->state & 1))\n\t\treturn;\t\t// still up (this should not happen)\n\tb->state &= ~1;\t\t// now up\n\tb->state |= 4; \t\t// impulse up\n}\n\nvoid IN_KLookDown (void) {KeyDown(&in_klook);}\nvoid IN_KLookUp (void) {KeyUp(&in_klook);}\nvoid IN_MLookDown (void) {KeyDown(&in_mlook);}\nvoid IN_MLookUp (void) {\nKeyUp(&in_mlook);\nif ( !(in_mlook.state&1) &&  lookspring.value)\n\tV_StartPitchDrift();\n}\nvoid IN_UpDown(void) {KeyDown(&in_up);}\nvoid IN_UpUp(void) {KeyUp(&in_up);}\nvoid IN_DownDown(void) {KeyDown(&in_down);}\nvoid IN_DownUp(void) {KeyUp(&in_down);}\nvoid IN_LeftDown(void) {KeyDown(&in_left);}\nvoid IN_LeftUp(void) {KeyUp(&in_left);}\nvoid IN_RightDown(void) {KeyDown(&in_right);}\nvoid IN_RightUp(void) {KeyUp(&in_right);}\nvoid IN_ForwardDown(void) {KeyDown(&in_forward);}\nvoid IN_ForwardUp(void) {KeyUp(&in_forward);}\nvoid IN_BackDown(void) {KeyDown(&in_back);}\nvoid IN_BackUp(void) {KeyUp(&in_back);}\nvoid IN_LookupDown(void) {KeyDown(&in_lookup);}\nvoid IN_LookupUp(void) {KeyUp(&in_lookup);}\nvoid IN_LookdownDown(void) {KeyDown(&in_lookdown);}\nvoid IN_LookdownUp(void) {KeyUp(&in_lookdown);}\nvoid IN_MoveleftDown(void) {KeyDown(&in_moveleft);}\nvoid IN_MoveleftUp(void) {KeyUp(&in_moveleft);}\nvoid IN_MoverightDown(void) {KeyDown(&in_moveright);}\nvoid IN_MoverightUp(void) {KeyUp(&in_moveright);}\n\nvoid IN_SpeedDown(void) {KeyDown(&in_speed);}\nvoid IN_SpeedUp(void) {KeyUp(&in_speed);}\nvoid IN_StrafeDown(void) {KeyDown(&in_strafe);}\nvoid IN_StrafeUp(void) {KeyUp(&in_strafe);}\n\nvoid IN_AttackDown(void) {KeyDown(&in_attack);}\nvoid IN_AttackUp(void) {KeyUp(&in_attack);}\n\nvoid IN_UseDown (void) {KeyDown(&in_use);}\nvoid IN_UseUp (void) {KeyUp(&in_use);}\nvoid IN_JumpDown (void) {KeyDown(&in_jump);}\nvoid IN_JumpUp (void) {KeyUp(&in_jump);}\n\nvoid IN_Impulse (void) {in_impulse=atoi(Cmd_Argv(1));}\n\n/*\n===============\nCL_KeyState\n\nReturns 0.25 if a key was pressed and released during the frame,\n0.5 if it was pressed and held\n0 if held then released, and\n1.0 if held for the entire time\n===============\n*/\nfloat CL_KeyState (kbutton_t *key)\n{\n\tfloat\t\tval;\n\tbool\timpulsedown, impulseup, down;\n\n\timpulsedown = key->state & 2;\n\timpulseup = key->state & 4;\n\tdown = key->state & 1;\n\tval = 0;\n\n\tif (impulsedown && !impulseup)\n\t\tif (down)\n\t\t\tval = 0.5;\t// pressed and held this frame\n\t\telse\n\t\t\tval = 0;\t//\tI_Error ();\n\tif (impulseup && !impulsedown)\n\t\tif (down)\n\t\t\tval = 0;\t//\tI_Error ();\n\t\telse\n\t\t\tval = 0;\t// released this frame\n\tif (!impulsedown && !impulseup)\n\t\tif (down)\n\t\t\tval = 1.0;\t// held the entire frame\n\t\telse\n\t\t\tval = 0;\t// up the entire frame\n\tif (impulsedown && impulseup)\n\t\tif (down)\n\t\t\tval = 0.75;\t// released and re-pressed this frame\n\t\telse\n\t\t\tval = 0.25;\t// pressed and released this frame\n\n\tkey->state &= 1;\t\t// clear impulses\n\n\treturn val;\n}\n\n\n\n\n//==========================================================================\n\n/*\n================\nCL_AdjustAngles\n\nMoves the local angle positions\n================\n*/\nvoid CL_AdjustAngles (void)\n{\n\tfloat\tspeed;\n\tfloat\tup, down;\n\n\tif (in_speed.state & 1)\n\t\tspeed = host_frametime * cl_anglespeedkey.value;\n\telse\n\t\tspeed = host_frametime;\n\n\tif (gl_xflip.value) cl.viewangles[YAW] *= -1;\n\t\n\tif (!(in_strafe.state & 1))\n\t{\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\tcl.viewangles[YAW] = anglemod(cl.viewangles[YAW]);\n\t}\n\t\n\tif (gl_xflip.value) cl.viewangles[YAW] *= -1;\n\t\n\tif (in_klook.state & 1)\n\t{\n\t\tV_StopPitchDrift ();\n\t\tcl.viewangles[PITCH] -= speed*cl_pitchspeed.value * CL_KeyState (&in_forward);\n\t\tcl.viewangles[PITCH] += speed*cl_pitchspeed.value * CL_KeyState (&in_back);\n\t}\n\n\tup = CL_KeyState (&in_lookup);\n\tdown = CL_KeyState(&in_lookdown);\n\n\tcl.viewangles[PITCH] -= speed*cl_pitchspeed.value * up;\n\tcl.viewangles[PITCH] += speed*cl_pitchspeed.value * down;\n\n\tif (up || down)\n\t\tV_StopPitchDrift ();\n\n// ProQuake aiming compatibility\n\tif (pq_fullpitch.value)\n\t\tcl.viewangles[PITCH] = COM_Clamp(cl.viewangles[PITCH], -90, 90);\n\telse\n\t\tcl.viewangles[PITCH] = COM_Clamp(cl.viewangles[PITCH], -70, 80);\n\n\tcl.viewangles[ROLL] = COM_Clamp(cl.viewangles[ROLL], -50, 50);\n}\n\n/*\n================\nCL_BaseMove\n\nSend the intended movement message to the server\n================\n*/\nvoid CL_BaseMove (usercmd_t *cmd)\n{\n\tif (cls.signon != SIGNONS)\n\t\treturn;\n\n\tCL_AdjustAngles ();\n\n\tmemset (cmd, 0, sizeof(*cmd));\n\n\tif (in_strafe.state & 1)\n\t{\n\t\tcmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_right);\n\t\tcmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_left);\n\t}\n\n\tcmd->sidemove += cl_sidespeed.value * CL_KeyState (&in_moveright);\n\tcmd->sidemove -= cl_sidespeed.value * CL_KeyState (&in_moveleft);\n\n\tif(gl_xflip.value) cmd->sidemove *= -1;\n\t\n\tcmd->upmove += cl_upspeed.value * CL_KeyState (&in_up);\n\tcmd->upmove -= cl_upspeed.value * CL_KeyState (&in_down);\n\n\tif (! (in_klook.state & 1) )\n\t{\n\t\tcmd->forwardmove += cl_forwardspeed.value * CL_KeyState (&in_forward);\n\t\tcmd->forwardmove -= cl_backspeed.value * CL_KeyState (&in_back);\n\t}\n\n//\n// adjust for speed key\n//\n\tif (in_speed.state & 1)\n\t{\n\t\tcmd->forwardmove *= cl_movespeedkey.value;\n\t\tcmd->sidemove *= cl_movespeedkey.value;\n\t\tcmd->upmove *= cl_movespeedkey.value;\n\t}\n\n#ifdef QUAKE2\n\tcmd->lightlevel = cl.light_level;\n#endif\n}\n\n\n\n/*\n==============\nCL_SendMove\n==============\n*/\nvoid CL_SendMove(usercmd_t *cmd)\n{\n\tint\t\ti;\n\tint\t\tbits;\n\tsizebuf_t\tbuf;\n\tbyte\tdata[128];\n\n\tbuf.maxsize = 128;\n\tbuf.cursize = 0;\n\tbuf.data = data;\n\n\tcl.cmd = *cmd;\n\n\t//\n\t// send the movement message\n\t//\n\tMSG_WriteByte(&buf, clc_move);\n\tMSG_WriteFloat(&buf, cl.mtime[0]);\t// so server can get ping times\n\n\tif (!cls.demoplayback && (cls.netcon->proquake_connection == MOD_PROQUAKE)) {\n\t\tfor (i = 0; i < 3; i++)\n\t\t\tMSG_WritePreciseAngle(&buf, cl.viewangles[i]);\n\t}\n\telse\n\t{\t\n\t\tfor (i = 0; i < 3; i++)\n\t\t\tMSG_WriteAngle(&buf, cl.viewangles[i]);\n\t}\n\n  \tMSG_WriteShort (&buf, cmd->forwardmove);\n    MSG_WriteShort (&buf, cmd->sidemove);\n    MSG_WriteShort (&buf, cmd->upmove);\n\n//\n// send button bits\n//\n\tbits = 0;\n\n\tif ( in_attack.state & 3 )\n\t\tbits |= 1;\n\tin_attack.state &= ~2;\n\n\tif (in_jump.state & 3)\n\t\tbits |= 2;\n\tin_jump.state &= ~2;\n\n    MSG_WriteByte (&buf, bits);\n\n    MSG_WriteByte (&buf, in_impulse);\n\tin_impulse = 0;\n\n#ifdef QUAKE2\n//\n// light level\n//\n\tMSG_WriteByte (&buf, cmd->lightlevel);\n#endif\n\n//\n// deliver the message\n//\n\tif (cls.demoplayback)\n\t\treturn;\n\n//\n// always dump the first two message, because it may contain leftover inputs\n// from the last level\n//\n\tif (++cl.movemessages <= 2)\n\t\treturn;\n\n\tif (NET_SendUnreliableMessage (cls.netcon, &buf) == -1)\n\t{\n\t\tCon_Printf (\"CL_SendMove: lost server connection\\n\");\n\t\tCL_Disconnect ();\n\t}\n}\n\n/*\n============\nCL_InitInput\n============\n*/\nvoid CL_InitInput (void)\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_AttackDown);\n\tCmd_AddCommand (\"-attack\", IN_AttackUp);\n\tCmd_AddCommand (\"+use\", IN_UseDown);\n\tCmd_AddCommand (\"-use\", IN_UseUp);\n\tCmd_AddCommand (\"+jump\", IN_JumpDown);\n\tCmd_AddCommand (\"-jump\", IN_JumpUp);\n\tCmd_AddCommand (\"impulse\", IN_Impulse);\n\tCmd_AddCommand (\"+klook\", IN_KLookDown);\n\tCmd_AddCommand (\"-klook\", IN_KLookUp);\n\tCmd_AddCommand (\"+mlook\", IN_MLookDown);\n\tCmd_AddCommand (\"-mlook\", IN_MLookUp);\n\n\tCvar_RegisterVariable (&cl_fullpitch); // ProQuake CVAR\n}\n"
  },
  {
    "path": "source/cl_main.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cl_main.c  -- client main loop\n\n#include \"quakedef.h\"\n#include <curl/curl.h>\n\n// we need to declare some mouse variables here, because the menu system\n// references them even when on a unix system.\n\n// these two are not intended to be set directly\ncvar_t\tcl_name = {\"_cl_name\", \"player\", CVAR_ARCHIVE};\ncvar_t\tcl_color = {\"_cl_color\", \"0\", CVAR_ARCHIVE};\n\nCVAR (cl_shownet,\t0, CVAR_DEBUG) // can be 0, 1, or 2\nCVAR (cl_nolerp,\t0, CVAR_NONE)\n\nCVAR (always_run,\t1, CVAR_ARCHIVE)\nCVAR (lookspring,\t0, CVAR_ARCHIVE)\nCVAR (lookstrafe,\t0, CVAR_ARCHIVE)\n\n// ToDo: Redirect them to the mouse input file.\nCVAR (sensitivity, 3, CVAR_ARCHIVE)\nCVAR (m_pitch,\t0.022,\tCVAR_ARCHIVE)\nCVAR (m_yaw,\t0.022,\tCVAR_ARCHIVE)\nCVAR (m_forward, 1,\t\tCVAR_ARCHIVE)\nCVAR (m_side,\t0.8,\tCVAR_ARCHIVE)\n\ncvar_t cl_web_download = {\"cl_web_download\", \"1\", CVAR_ARCHIVE};\ncvar_t cl_web_download_url = {\"cl_web_download_url\", \"http://bigfoot.servequake.com/\", CVAR_ARCHIVE};\n\n// PSVITA extra Cvars (ToDo: redirect them to in_psp2.c, since it has nothing to do here)\nCVAR (invert_camera, 0, CVAR_ARCHIVE)\n\n//----------------------------------------------\n\nclient_static_t\tcls;\nclient_state_t\tcl;\n\nefrag_t*\t\tcl_efrags;\nentity_t*\t\tcl_entities;\nentity_t*\t\tcl_static_entities;\nlightstyle_t\tcl_lightstyle[MAX_LIGHTSTYLES];\ndlight_t\t\tcl_dlights[MAX_DLIGHTS];\n\nint\t\t\t\tcl_numvisedicts;\nentity_t\t\t*cl_visedicts[MAX_VISEDICTS];\n\n/*\n=====================\nCL_ClearState\n\n=====================\n*/\nvoid CL_ClearState (void)\n{\n\tint\t\t\ti;\n\n\tif (!sv.active)\n\t\tHost_ClearMemory ();\n\n// wipe the entire cl structure\n\tmemset (&cl, 0, sizeof(cl));\n\n\tSZ_Clear (&cls.message);\n\n// clear other arrays\n\tmemset (cl_efrags, 0, sizeof(cl_efrags));\n\tmemset (cl_entities, 0, sizeof(cl_entities));\n\tmemset (cl_dlights, 0, sizeof(cl_dlights));\n\tmemset (cl_lightstyle, 0, sizeof(cl_lightstyle));\n\tmemset (cl_temp_entities, 0, sizeof(cl_temp_entities));\n\tmemset (cl_beams, 0, sizeof(cl_beams));\n\n//\n// allocate the efrags and chain together into a free list\n//\n\tcl.free_efrags = cl_efrags;\n\tfor (i=0 ; i<MAX_EFRAGS-1 ; i++)\n\t\tcl.free_efrags[i].entnext = &cl.free_efrags[i+1];\n\tcl.free_efrags[i].entnext = NULL;\n}\n\n/*\n=====================\nCL_Disconnect\n\nSends a disconnect message to the server\nThis is also called on Host_Error, so it shouldn't cause any errors\n=====================\n*/\nvoid CL_Disconnect (void)\n{\n// stop sounds (especially looping!)\n\tS_StopAllSounds (true);\n\n// bring the console down and fade the colors back to normal\n//\tSCR_BringDownConsole ();\n\n// We have to shut down webdownloading first\n\tif( cls.download.web )\n\t{\n\t\tcls.download.disconnect = true;\n\t\treturn;\n\t}\n\n// if running a local server, shut it down\n\tif (cls.demoplayback)\n\t\tCL_StopPlayback ();\n\telse if (cls.state == ca_connected)\n\t{\n\t\tif (cls.demorecording)\n\t\t\tCL_Stop_f ();\n\n\t\tCon_DPrintf (\"Sending clc_disconnect\\n\");\n\t\tSZ_Clear (&cls.message);\n\t\tMSG_WriteByte (&cls.message, clc_disconnect);\n\t\tNET_SendUnreliableMessage (cls.netcon, &cls.message);\n\t\tSZ_Clear (&cls.message);\n\t\tNET_Close (cls.netcon);\n\n\t\tcls.state = ca_disconnected;\n\t\tif (sv.active)\n\t\t\tHost_ShutdownServer(false);\n\t}\n\n\tcls.demoplayback = cls.timedemo = false;\n\tcls.signon = 0;\n}\n\nvoid CL_Disconnect_f (void)\n{\n\tCL_Disconnect ();\n\tif (sv.active)\n\t\tHost_ShutdownServer (false);\n}\n\n\n\n\n/*\n=====================\nCL_EstablishConnection\n\nHost should be either \"local\" or a net address to be passed on\n=====================\n*/\nvoid CL_EstablishConnection (char *host)\n{\n\tif (cls.state == ca_dedicated)\n\t\treturn;\n\n\tif (cls.demoplayback)\n\t\treturn;\n\n\tCL_Disconnect ();\n\n\tcls.netcon = NET_Connect (host);\n\n\tif (!cls.netcon)\n\t{\n\t\tCon_Printf(\"\\nsyntax: connect server:port (port is optional)\\n\");//r00k added\n\t\tif (net_hostport != 26000)\n\t\t\tCon_Printf(\"\\nTry using port 26000\\n\");//r00k added\n\t\tHost_Error(\"connect failed\");\n\t}\n\n\tCon_DPrintf (\"CL_EstablishConnection: connected to %s\\n\", host);\n\n\tcls.demonum = -1;\t\t\t// not in the demo loop now\n\tcls.state = ca_connected;\n\tcls.signon = 0;\t\t\t\t// need all the signon messages before playing\n\t\n\tMSG_WriteByte(&cls.message, clc_nop);\t// JPG 3.40 - fix for NAT\n}\n\n/*\n=====================\nCL_SignonReply\n\nAn svc_signonnum has been received, perform a client side setup\n=====================\n*/\nextern cshift_t\tcshift_empty;\nvoid CL_SignonReply (void)\n{\n\tchar \tstr[8192];\n\nCon_DPrintf (\"CL_SignonReply: %i\\n\", cls.signon);\n\n\tswitch (cls.signon)\n\t{\n\tcase 1:\n\t\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\t\tMSG_WriteString (&cls.message, \"prespawn\");\n\t\tbreak;\n\n\tcase 2:\n\t\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\t\tMSG_WriteString (&cls.message, va(\"name \\\"%s\\\"\\n\", cl_name.string));\n\n\t\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\t\tMSG_WriteString (&cls.message, va(\"color %i %i\\n\", ((int)cl_color.value)>>4, ((int)cl_color.value)&15));\n\n\t\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\t\tsprintf (str, \"spawn %s\", cls.spawnparms);\n\t\tMSG_WriteString (&cls.message, str);\n\t\tbreak;\n\n\tcase 3:\n\t\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\t\tMSG_WriteString (&cls.message, \"begin\");\n\t\tCache_Report ();\t\t// print remaining memory\n\t\tbreak;\n\n\tcase 4:\n\t\tSCR_EndLoadingPlaque ();\t\t// allow normal screen updates\n\t\tcshift_empty.percent = 0;\t\t// Ch0wW: Hacky fix for the TF screen fading to black.\n\t\tbreak;\n\t}\n}\n\n/*\n=====================\nCL_NextDemo\n\nCalled to play the next demo in the demo loop\n=====================\n*/\nvoid CL_NextDemo (void)\n{\n\tchar\tstr[1024];\n\n\tif (cls.demonum == -1)\n\t\treturn;\t\t// don't play demos\n\n\tSCR_BeginLoadingPlaque ();\n\n\tif (!cls.demos[cls.demonum][0] || cls.demonum == MAX_DEMOS)\n\t{\n\t\tcls.demonum = 0;\n\t\tif (!cls.demos[cls.demonum][0])\n\t\t{\n\t\t\tCon_Printf (\"No demos listed with startdemos\\n\");\n\t\t\tcls.demonum = -1;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tsprintf (str,\"playdemo %s\\n\", cls.demos[cls.demonum]);\n\tCbuf_InsertText (str);\n\tcls.demonum++;\n}\n\n/*\n==============\nCL_PrintEntities_f\n==============\n*/\nvoid CL_PrintEntities_f (void)\n{\n\tentity_t\t*ent;\n\tint\t\t\ti;\n\n\tfor (i=0,ent=cl_entities ; i<cl.num_entities ; i++,ent++)\n\t{\n\t\tCon_Printf (\"%3i:\",i);\n\t\tif (!ent->model)\n\t\t{\n\t\t\tCon_Printf (\"EMPTY\\n\");\n\t\t\tcontinue;\n\t\t}\n\t\tCon_Printf (\"%s:%2i  (%5.1f,%5.1f,%5.1f) [%5.1f %5.1f %5.1f]\\n\"\n\t\t,ent->model->name,ent->frame, ent->origin[0], ent->origin[1], ent->origin[2], ent->angles[0], ent->angles[1], ent->angles[2]);\n\t}\n}\n\n\n/*\n===============\nSetPal\n\nDebugging tool, just flashes the screen\n===============\n*/\nvoid SetPal (int i)\n{\n\n}\n\n/*\n===============\nCL_AllocDlight\n\n===============\n*/\ndlight_t *CL_AllocDlight (int key)\n{\n\tint\t\ti;\n\tdlight_t\t*dl;\n\n// first look for an exact key match\n\tif (key)\n\t{\n\t\tdl = cl_dlights;\n\t\tfor (i=0 ; i<MAX_DLIGHTS ; i++, dl++)\n\t\t{\n\t\t\tif (dl->key == key)\n\t\t\t{\n\t\t\t\tmemset (dl, 0, sizeof(*dl));\n\t\t\t\tdl->key = key;\n\t\t\t\tdl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc\n\t\t\t\treturn dl;\n\t\t\t}\n\t\t}\n\t}\n\n// then look for anything else\n\tdl = cl_dlights;\n\tfor (i=0 ; i<MAX_DLIGHTS ; i++, dl++)\n\t{\n\t\tif (dl->die < cl.time)\n\t\t{\n\t\t\tmemset (dl, 0, sizeof(*dl));\n\t\t\tdl->key = key;\n\t\t\tdl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc\n\t\t\treturn dl;\n\t\t}\n\t}\n\n\tdl = &cl_dlights[0];\n\tmemset (dl, 0, sizeof(*dl));\n\tdl->key = key;\n\tdl->color[0] = dl->color[1] = dl->color[2] = 1; //johnfitz -- lit support via lordhavoc\n\treturn dl;\n}\n\n\n/*\n===============\nCL_DecayLights\n\n===============\n*/\nvoid CL_DecayLights (void)\n{\n\tint\t\t\ti;\n\tdlight_t\t*dl;\n\tfloat\t\ttime;\n\n\ttime = cl.time - cl.oldtime;\n\n\tdl = cl_dlights;\n\tfor (i=0 ; i<MAX_DLIGHTS ; i++, dl++)\n\t{\n\t\tif (dl->die < cl.time || !dl->radius)\n\t\t\tcontinue;\n\n\t\tdl->radius -= time*dl->decay;\n\t\tif (dl->radius < 0)\n\t\t\tdl->radius = 0;\n\t}\n}\n\n\n/*\n===============\nCL_LerpPoint\n\nDetermines the fraction between the last two messages that the objects\nshould be put at.\n===============\n*/\nextern bool benchmark;\n\nfloat\tCL_LerpPoint (void)\n{\n\tfloat\tf, frac;\n\n\tf = cl.mtime[0] - cl.mtime[1];\n\n\tif (!f || cl_nolerp.value || (cls.timedemo && !benchmark) || sv.active)\n\t{\n\t\tcl.time = cl.mtime[0];\n\t\treturn 1;\n\t}\n\n\tif (f > 0.1)\n\t{\t// dropped packet, or start of demo\n\t\tcl.mtime[1] = cl.mtime[0] - 0.1;\n\t\tf = 0.1;\n\t}\n\tfrac = (cl.time - cl.mtime[1]) / f;\n//Con_Printf (\"frac: %f\\n\",frac);\n\tif (frac < 0)\n\t{\n\t\tif (frac < -0.01)\n\t\t{\nSetPal(1);\n\t\t\tcl.time = cl.mtime[1];\n//\t\t\t\tCon_Printf (\"low frac\\n\");\n\t\t}\n\t\tfrac = 0;\n\t}\n\telse if (frac > 1)\n\t{\n\t\tif (frac > 1.01)\n\t\t{\nSetPal(2);\n\t\t\tcl.time = cl.mtime[0];\n//\t\t\t\tCon_Printf (\"high frac\\n\");\n\t\t}\n\t\tfrac = 1;\n\t}\n\telse\n\t\tSetPal(0);\n\n\treturn frac;\n}\n\n\n/*\n===============\nCL_RelinkEntities\n===============\n*/\nvoid CL_RelinkEntities (void)\n{\n\tentity_t\t*ent;\n\tint\t\t\ti, j;\n\tfloat\t\tfrac, f, d;\n\tvec3_t\t\tdelta;\n\tfloat\t\tbobjrotate;\n\tvec3_t\t\toldorg;\n\tdlight_t\t*dl;\n\n// determine partial update time\n\tfrac = CL_LerpPoint ();\n\n\tcl_numvisedicts = 0;\n\n//\n// interpolate player info\n//\n\tfor (i=0 ; i<3 ; i++)\n\t\tcl.velocity[i] = cl.mvelocity[1][i] +\n\t\t\tfrac * (cl.mvelocity[0][i] - cl.mvelocity[1][i]);\n\n\tif (cls.demoplayback)\n\t{\n\t// interpolate the angles\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\td = cl.mviewangles[0][j] - cl.mviewangles[1][j];\n\t\t\tif (d > 180)\n\t\t\t\td -= 360;\n\t\t\telse if (d < -180)\n\t\t\t\td += 360;\n\t\t\tcl.viewangles[j] = cl.mviewangles[1][j] + frac*d;\n\t\t}\n\t}\n\n\tbobjrotate = anglemod(100*cl.time);\n\n// start on the entity after the world\n\tfor (i=1,ent=cl_entities+1 ; i<cl.num_entities ; i++,ent++)\n\t{\n\t\tif (!ent->model)\n\t\t{\t// empty slot\n\t\t\tif (ent->forcelink)\n\t\t\t\tR_RemoveEfrags (ent);\t// just became empty\n\t\t\tcontinue;\n\t\t}\n\n// if the object wasn't included in the last packet, remove it\n\t\tif (ent->msgtime != cl.mtime[0])\n\t\t{\n\t\t\tent->model = NULL;\n\t\t\t\n\t\t\t// fenix@io.com: model transform interpolation\n\t\t\tent->frame_start_time = 0;\n\t\t\tent->translate_start_time = 0;\n\t\t\tent->rotate_start_time = 0;\n\t\t\t\n\t\t\tcontinue;\n\t\t}\n\n\t\tVectorCopy (ent->origin, oldorg);\n\n\t\tif (ent->forcelink)\n\t\t{\t// the entity was not updated in the last message\n\t\t\t// so move to the final spot\n\t\t\tVectorCopy (ent->msg_origins[0], ent->origin);\n\t\t\tVectorCopy (ent->msg_angles[0], ent->angles);\n\t\t}\n\t\telse\n\t\t{\t// if the delta is large, assume a teleport and don't lerp\n\t\t\tf = frac;\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tdelta[j] = ent->msg_origins[0][j] - ent->msg_origins[1][j];\n\t\t\t\tif (delta[j] > 100 || delta[j] < -100)\n\t\t\t\t\tf = 1;\t\t// assume a teleportation, not a motion\n\t\t\t}\n\t\t\t\n\t\t\t// fenix@io.com: model transform interpolation\n\t\t\t// interpolation should be reset in the event of a large delta\n\t\t\tif (f >= 1){\n\t\t\t\tent->frame_start_time     = 0;\n\t\t\t\tent->translate_start_time = 0;\n\t\t\t\tent->rotate_start_time    = 0;\n\t\t\t}\n\n\t\t// interpolate the origin and angles\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tent->origin[j] = ent->msg_origins[1][j] + f*delta[j];\n\n\t\t\t\td = ent->msg_angles[0][j] - ent->msg_angles[1][j];\n\t\t\t\tif (d > 180)\n\t\t\t\t\td -= 360;\n\t\t\t\telse if (d < -180)\n\t\t\t\t\td += 360;\n\t\t\t\tent->angles[j] = ent->msg_angles[1][j] + f*d;\n\t\t\t}\n\n\t\t}\n\t\t\n\t\tif (!(ent->effects & 0xFF800000))  //qbism based on DP model flags\n\t\t\tent->effects |= ent->model->flags;\n\t\t\n// rotate binary objects locally\n\t\tif (ent->effects & EF_ROTATE)\n\t\t{\n\t\t\tent->angles[1] = bobjrotate;\n\t\t\t// MUFF - makes them bob as well as rotate ;)\n\t\t\tent->origin[2] += (( sin(bobjrotate/90*M_PI) * 5) + 5 );\n\t\t}\n\n\t\tif (ent->effects & EF_BRIGHTFIELD)\n\t\t\tR_EntityParticles (ent);\n#ifdef QUAKE2\n\t\tif (ent->effects & EF_DARKFIELD)\n\t\t\tR_DarkFieldParticles (ent);\n#endif\n\t\tif (ent->effects & EF_MUZZLEFLASH)\n\t\t{\n\t\t\tvec3_t\t\tfv, rv, uv;\n\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->origin[2] += 16;\n\t\t\tAngleVectors (ent->angles, fv, rv, uv);\n\n\t\t\tVectorMA (dl->origin, 18, fv, dl->origin);\n\t\t\tdl->radius = 200 + (rand()&31);\n\t\t\tdl->minlight = 32;\n\t\t\tdl->die = cl.time + 0.1f;\n\t\t\tdl->color[0] = 0.2f;\n\t\t\tdl->color[1] = 0.1f;\n\t\t\tdl->color[2] = 0.05f;\n\t\t\tdl->alpha = 0.7f;\n\t\t}\n\t\tif (ent->effects & EF_BRIGHTLIGHT)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->origin[2] += 16;\n\t\t\tdl->radius = 400 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->color[0] = 0.2f;\n\t\t\tdl->color[1] = 0.1f;\n\t\t\tdl->color[2] = 0.05f;\n\t\t\tdl->alpha = 0.7f;\n\t\t}\n\t\tif (ent->effects & EF_DIMLIGHT)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->color[0] = 0.2f;\n\t\t\tdl->color[1] = 0.1f;\n\t\t\tdl->color[2] = 0.05f;\n\t\t\tdl->alpha = 0.7f;\n\t\t}\n\t\tif (ent->effects & EF_BLUE)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->color[0] = 0.05f;\n\t\t\tdl->color[1] = 0.05f;\n\t\t\tdl->color[2] = 0.3f;\n\t\t\tdl->alpha = 0.7f;\n\t\t}\n\t\tif (ent->effects & EF_RED)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->color[0] = 0.5f;\n\t\t\tdl->color[1] = 0.05f;\n\t\t\tdl->color[2] = 0.05f;\n\t\t\tdl->alpha = 0.7f;\n\t\t}\n\t\tif ((ent->effects & (EF_BLUE | EF_RED)) == (EF_BLUE | EF_RED))\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->color[0] = 0.5f;\n\t\t\tdl->color[1] = 0.05f;\n\t\t\tdl->color[2] = 0.4f;\n\t\t\tdl->alpha = 0.7f;\n\n\t\t}\n#ifdef QUAKE2\n\t\tif (ent->effects & EF_DARKLIGHT)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200.0 + (rand()&31);\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t\tdl->dark = true;\n\t\t}\n\t\tif (ent->effects & EF_LIGHT)\n\t\t{\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin,  dl->origin);\n\t\t\tdl->radius = 200;\n\t\t\tdl->die = cl.time + 0.001f;\n\t\t}\n#endif\n\n\t\tif (ent->effects & EF_GIB)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 2);\n\t\telse if (ent->effects & EF_ZOMGIB)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 4);\n\t\telse if (ent->effects & EF_TRACER)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 3);\n\t\telse if (ent->effects & EF_TRACER2)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 5);\n\t\telse if (ent->effects & EF_ROCKET)\n\t\t{\n\t\t\tR_RocketTrail (oldorg, ent->origin, 0);\n\t\t\tdl = CL_AllocDlight (i);\n\t\t\tVectorCopy (ent->origin, dl->origin);\n\t\t\tdl->radius = 200;\n\t\t\tdl->die = cl.time + 0.01;\n\t\t\tdl->color[0] = 0.2f;\n\t\t\tdl->color[1] = 0.1f;\n\t\t\tdl->color[2] = 0.05f;\n\t\t\tdl->color[3] = 0.7f;\n\t\t}\n\t\telse if (ent->effects & EF_GRENADE)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 1);\n\t\telse if (ent->effects & EF_TRACER3)\n\t\t\tR_RocketTrail (oldorg, ent->origin, 6);\n\n\t\tent->forcelink = false;\n\n\t\tif (i == cl.viewentity && !chase_active.value)\n\t\t\tcontinue;\n\n\t\tif ( ent->effects & EF_NODRAW )\n\t\t\tcontinue;\n\n\t\tif (cl_numvisedicts < MAX_VISEDICTS)\n\t\t{\n\t\t\tcl_visedicts[cl_numvisedicts] = ent;\n\t\t\tcl_numvisedicts++;\n\t\t}\n\t\t\n\t\tif (!ent->alpha)\n\t\t\tent->alpha = 1.0f;\n\t}\n\n}\n\n\n/*\n===============\nCL_ReadFromServer\n\nRead all incoming data from the server\n===============\n*/\nint CL_ReadFromServer (void)\n{\n\tint\t\tret;\n\n\tcl.oldtime = cl.time;\n\tcl.time += host_frametime;\n\n\tdo\n\t{\n\t\tret = CL_GetMessage ();\n\t\tif (ret == -1)\n\t\t\tHost_Error (\"CL_ReadFromServer: lost server connection\");\n\t\tif (!ret)\n\t\t\tbreak;\n\n\t\tcl.last_received_message = realtime;\n\t\tCL_ParseServerMessage ();\n\t} while (ret && cls.state == ca_connected);\n\n\tif (cl_shownet.value)\n\t\tCon_Printf (\"\\n\");\n\n\tCL_RelinkEntities ();\n\tCL_UpdateTEnts ();\n//\n// bring the links up to date\n//\n\treturn 0;\n}\n\n/*\n=================\nCL_SendCmd\n=================\n*/\nvoid CL_SendCmd (void)\n{\n\tusercmd_t\t\tcmd;\n\n\tif (cls.state != ca_connected)\n\t\treturn;\n\n\tif (cls.signon == SIGNONS)\n\t{\n\t// get basic movement from keyboard\n\t\tCL_BaseMove (&cmd);\n\n\t// allow mice or other external controllers to add to the move\n\t\tIN_Move (&cmd);\n\n\t// send the unreliable message\n\t\tCL_SendMove (&cmd);\n\n\t}\n\n\tif (cls.demoplayback)\n\t{\n\t\tSZ_Clear (&cls.message);\n\t\treturn;\n\t}\n\n// send the reliable message\n\tif (!cls.message.cursize)\n\t\treturn;\t\t// no message at all\n\n\tif (!NET_CanSendMessage (cls.netcon))\n\t{\n\t\tCon_DPrintf (\"CL_WriteToServer: can't send\\n\");\n\t\treturn;\n\t}\n\n\tif (NET_SendMessage (cls.netcon, &cls.message) == -1)\n\t\tHost_Error (\"CL_WriteToServer: lost server connection\");\n\n\tSZ_Clear (&cls.message);\n}\n\n/*\n=================\nCL_Init\n=================\n*/\nvoid CL_Init (void)\n{\n\tSZ_Alloc (&cls.message, 1024);\n\n\tCL_InitInput ();\n\tCL_InitTEnts ();\n\n//\n// register our commands\n//\n\tCvar_RegisterVariable (&cl_name);\n\tCvar_RegisterVariable (&cl_color);\n\tCvar_RegisterVariable (&cl_upspeed);\n\tCvar_RegisterVariable (&cl_forwardspeed);\n\tCvar_RegisterVariable (&cl_backspeed);\n\tCvar_RegisterVariable (&cl_sidespeed);\n\tCvar_RegisterVariable (&cl_movespeedkey);\n\tCvar_RegisterVariable (&cl_yawspeed);\n\tCvar_RegisterVariable (&cl_pitchspeed);\n\tCvar_RegisterVariable (&cl_anglespeedkey);\n\tCvar_RegisterVariable (&cl_shownet);\n\tCvar_RegisterVariable (&cl_nolerp);\n\tCvar_RegisterVariable (&lookspring);\n\tCvar_RegisterVariable (&lookstrafe);\n\tCvar_RegisterVariable (&sensitivity);\n\t\n\tCvar_RegisterVariable (&cl_web_download);\n\tCvar_RegisterVariable (&cl_web_download_url);\n\n\tCvar_RegisterVariable (&m_pitch);\n\tCvar_RegisterVariable (&m_yaw);\n\tCvar_RegisterVariable (&m_forward);\n\tCvar_RegisterVariable (&m_side);\n\n//\tCvar_RegisterVariable (&cl_autofire);\n\n\tCmd_AddCommand (\"entities\", CL_PrintEntities_f);\n\tCmd_AddCommand (\"disconnect\", CL_Disconnect_f);\n\tCmd_AddCommand (\"record\", CL_Record_f);\n\tCmd_AddCommand (\"stop\", CL_Stop_f);\n\tCmd_AddCommand (\"playdemo\", CL_PlayDemo_f);\n\tCmd_AddCommand (\"timedemo\", CL_TimeDemo_f);\n\tCmd_AddCommand (\"benchmark\", CL_Benchmark_f);\n}\n"
  },
  {
    "path": "source/cl_parse.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cl_parse.c  -- parse a message received from the server\n\n#include <vitasdk.h>\n\n#include \"quakedef.h\"\n#include \"webdownload.h\"\n\nchar *svc_strings[] =\n{\n\t\"svc_bad\",\n\t\"svc_nop\",\n\t\"svc_disconnect\",\n\t\"svc_updatestat\",\n\t\"svc_version\",\t\t// [long] server version\n\t\"svc_setview\",\t\t// [short] entity number\n\t\"svc_sound\",\t\t\t// <see code>\n\t\"svc_time\",\t\t\t// [float] server time\n\t\"svc_print\",\t\t\t// [string] null terminated string\n\t\"svc_stufftext\",\t\t// [string] stuffed into client's console buffer\n\t\t\t\t\t\t// the string should be \\n terminated\n\t\"svc_setangle\",\t\t// [vec3] set the view angle to this absolute value\n\n\t\"svc_serverinfo\",\t\t// [long] version\n\t\t\t\t\t\t// [string] signon string\n\t\t\t\t\t\t// [string]..[0]model cache [string]...[0]sounds cache\n\t\t\t\t\t\t// [string]..[0]item cache\n\t\"svc_lightstyle\",\t\t// [byte] [string]\n\t\"svc_updatename\",\t\t// [byte] [string]\n\t\"svc_updatefrags\",\t// [byte] [short]\n\t\"svc_clientdata\",\t\t// <shortbits + data>\n\t\"svc_stopsound\",\t\t// <see code>\n\t\"svc_updatecolors\",\t// [byte] [byte]\n\t\"svc_particle\",\t\t// [vec3] <variable>\n\t\"svc_damage\",\t\t\t// [byte] impact [byte] blood [vec3] from\n\n\t\"svc_spawnstatic\",\n\t\"OBSOLETE svc_spawnbinary\",\n\t\"svc_spawnbaseline\",\n\n\t\"svc_temp_entity\",\t\t// <variable>\n\t\"svc_setpause\",\n\t\"svc_signonnum\",\n\t\"svc_centerprint\",\n\t\"svc_killedmonster\",\n\t\"svc_foundsecret\",\n\t\"svc_spawnstaticsound\",\n\t\"svc_intermission\",\n\t\"svc_finale\",\t\t\t// [string] music [string] text\n\t\"svc_cdtrack\",\t\t\t// [byte] track [byte] looptrack\n\t\"svc_sellscreen\",\n\t\"svc_cutscene\"\n};\n\n//=============================================================================\n\n/*\n===============\nCL_EntityNum\n\nThis error checks and tracks the total number of entities\n===============\n*/\nentity_t\t*CL_EntityNum (int num)\n{\n\tif (num >= cl.num_entities)\n\t{\n\t\tif (num >= MAX_EDICTS)\n\t\t\tHost_Error (\"CL_EntityNum: %i is an invalid number\",num);\n\t\twhile (cl.num_entities<=num)\n\t\t{\n\t\t\tcl_entities[cl.num_entities].colormap = vid.colormap;\n\t\t\tcl.num_entities++;\n\t\t}\n\t}\n\n\treturn &cl_entities[num];\n}\n\n\n/*\n==================\nCL_ParseStartSoundPacket\n==================\n*/\nvoid CL_ParseStartSoundPacket(void)\n{\n    vec3_t  pos;\n    int \tchannel, ent;\n    int \tsound_num;\n    int \tvolume;\n    int \tfield_mask;\n    float \tattenuation;\n \tint\t\ti;\n\n    field_mask = MSG_ReadByte();\n\n    if (field_mask & SND_VOLUME)\n\t\tvolume = MSG_ReadByte ();\n\telse\n\t\tvolume = DEFAULT_SOUND_PACKET_VOLUME;\n\n    if (field_mask & SND_ATTENUATION)\n\t\tattenuation = MSG_ReadByte () / 64.0;\n\telse\n\t\tattenuation = DEFAULT_SOUND_PACKET_ATTENUATION;\n\n\tchannel = MSG_ReadShort ();\n\tsound_num = MSG_ReadByte ();\n\n\tent = channel >> 3;\n\tchannel &= 7;\n\n\tif (ent > MAX_EDICTS)\n\t\tHost_Error (\"CL_ParseStartSoundPacket: ent = %i\", ent);\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tpos[i] = MSG_ReadCoord ();\n\n    S_StartSound (ent, channel, cl.sound_precache[sound_num], pos, volume/255.0, attenuation);\n}\n\n/*\n==================\nCL_KeepaliveMessage\n\nWhen the client is taking a long time to load stuff, send keepalive messages\nso the server doesn't disconnect.\n==================\n*/\nvoid CL_KeepaliveMessage (void)\n{\n\tfloat\ttime;\n\tstatic float lastmsg;\n\tint\t\tret;\n\tsizebuf_t\told;\n\tbyte*\tolddata;\n\n\tif (sv.active)\n\t\treturn;\t\t// no need if server is local\n\tif (cls.demoplayback)\n\t\treturn;\n\n// read messages from server, should just be nops\n\told = net_message;\n\tolddata = Sys_BigStackAlloc(8192 * sizeof(byte), \"CL_KeepaliveMessage\");\n\tmemcpy (olddata, net_message.data, net_message.cursize);\n\n\tdo\n\t{\n\t\tret = CL_GetMessage ();\n\t\tswitch (ret)\n\t\t{\n\t\tdefault:\n\t\t\tHost_Error (\"CL_KeepaliveMessage: CL_GetMessage failed\");\n\t\tcase 0:\n\t\t\tbreak;\t// nothing waiting\n\t\tcase 1:\n\t\t\tHost_Error (\"CL_KeepaliveMessage: received a message\");\n\t\t\tbreak;\n\t\tcase 2:\n\t\t\tif (MSG_ReadByte() != svc_nop)\n\t\t\t\tHost_Error (\"CL_KeepaliveMessage: datagram wasn't a nop\");\n\t\t\tbreak;\n\t\t}\n\t} while (ret);\n\n\tnet_message = old;\n\tmemcpy (net_message.data, olddata, net_message.cursize);\n\n// check time\n\ttime = Sys_FloatTime ();\n\tif (time - lastmsg < 5)\n\t{\n\t\tSys_BigStackFree(8192 * sizeof(byte), \"CL_KeepaliveMessage\");\n\t\treturn;\n\t}\n\tlastmsg = time;\n\n// write out a nop\n\tCon_Printf (\"--> client to server keepalive\\n\");\n\n\tMSG_WriteByte (&cls.message, clc_nop);\n\tNET_SendMessage (cls.netcon, &cls.message);\n\tSZ_Clear (&cls.message);\n\n\tSys_BigStackFree(8192 * sizeof(byte), \"CL_KeepaliveMessage\");\n}\n\n/*\n=====================\nCL_WebDownloadProgress\nCallback function for webdownloads.\nSince Web_Get only returns once it's done, we have to do various things here:\nUpdate download percent, handle input, redraw UI and send net packets.\n=====================\n*/\nstatic int CL_WebDownloadProgress( double percent )\n{\n\tstatic double time, oldtime, newtime;\n\n\tcls.download.percent = percent;\n\tCL_KeepaliveMessage();\n\n\tnewtime = Sys_FloatTime ();\n\ttime = newtime - oldtime;\n\n\tHost_Frame (time);\n\n\toldtime = newtime;\n\n\treturn cls.download.disconnect; // abort if disconnect received\n}\n\n/*\n==================\nCL_ParseServerInfo\n==================\n*/\nvoid CL_ParseServerInfo (void)\n{\n\tchar\t*str;\n\tint\t\ti, maxlen;\n\tint\t\tnummodels, numsounds;\n\tchar**\tsound_precache;\n\tchar**\tmodel_precache;\n\tchar\ttempname[MAX_QPATH];\n\tCon_DPrintf (\"Serverinfo packet received.\\n\");\n\t\n\textern cvar_t cl_web_download;\n\textern cvar_t cl_web_download_url;\n\t\n//\n// wipe the client_state_t struct\n//\n\tCL_ClearState ();\n\n// parse protocol version number\n\ti = MSG_ReadLong ();\n\tif (i != PROTOCOL_NETQUAKE && i != PROTOCOL_FITZQUAKE)\n\t{\n\t\tHost_Error(\"Server returned version %i, not %i (Net/ProQuake) or %i (FitzQuake)\", i, PROTOCOL_NETQUAKE, PROTOCOL_FITZQUAKE);\n\t\tCon_Printf (\"Server returned version %i, not %i\", i, PROTOCOL_NETQUAKE);\n\t\treturn;\n\t}\n\n// parse maxclients\n\tcl.maxclients = MSG_ReadByte ();\n\tif (cl.maxclients < 1 || cl.maxclients > MAX_SCOREBOARD)\n\t{\n\t\tCon_Printf(\"Bad maxclients (%u) from server\\n\", cl.maxclients);\n\t\treturn;\n\t}\n\tcl.scores = Hunk_AllocName (cl.maxclients*sizeof(*cl.scores), \"scores\");\n\n// parse gametype\n\tcl.gametype = MSG_ReadByte ();\n\n// parse signon message\n\tstr = MSG_ReadString ();\n\tstrncpy (cl.levelname, str, sizeof(cl.levelname)-1);\n\n// seperate the printfs so the server message can have a color\n\tCon_Printf(\"\\n\\n\\35\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\37\\n\\n\");\n\tCon_Printf (\"%c%s\\n\", 2, str);\n\n//\n// first we go through and touch all of the precache data that still\n// happens to be in the cache, so precaching something else doesn't\n// needlessly purge it\n//\n\n\tmodel_precache = Sys_BigStackAlloc(MAX_MODELS * sizeof(char*), \"CL_ParseServerInfo\");\n\tfor (i = 0; i < MAX_MODELS; i++)\n\t{\n\t\tmodel_precache[i] = Sys_BigStackAlloc(MAX_QPATH, \"CL_ParseServerInfo\");\n\t};\n\n// precache models\n\tmemset (cl.model_precache, 0, sizeof(cl.model_precache));\n\tfor (nummodels=1 ; ; nummodels++)\n\t{\n\t\tstr = MSG_ReadString ();\n\t\tif (!str[0])\n\t\t\tbreak;\n\t\tif (nummodels == MAX_MODELS)\n\t\t{\n\t\t\tCon_Printf(\"Server sent too many model precaches\\n\");\n\t\t\tfor (i = MAX_MODELS - 1; i >= 0; i--) {\n\t\t\t\tfree(model_precache[i]);\n\t\t\t};\n\t\t\tfree(model_precache);\n\t\t\treturn;\n\t\t}\n\t\tstrcpy (model_precache[nummodels], str);\n\t\tMod_TouchModel (str);\n\t}\n\n// precache sounds\n\n\tsound_precache = Sys_BigStackAlloc(MAX_SOUNDS * sizeof(char*), \"CL_ParseServerInfo\");\n\tfor (i = 0; i < MAX_SOUNDS; i++)\n\t{\n\t\tsound_precache[i] = Sys_BigStackAlloc(MAX_QPATH, \"CL_ParseServerInfo\");\n\t};\n\n\tmemset (cl.sound_precache, 0, sizeof(cl.sound_precache));\n\tfor (numsounds=1 ; ; numsounds++)\n\t{\n\t\tstr = MSG_ReadString ();\n\t\tif (!str[0])\n\t\t\tbreak;\n\t\tif (numsounds == MAX_SOUNDS)\n\t\t{\n\t\t\tCon_Printf(\"Server sent too many sound precaches\\n\");\n\t\t\tSys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, \"CL_ParseServerInfo\");\n\t\t\treturn;\n\t\t}\n\t\tstrcpy (sound_precache[numsounds], str);\n\t\tS_TouchSound (str);\n\t}\n\n//\n// now we try to load everything else until a cache allocation fails\n//\n\tfor (i=1 ; i<nummodels ; i++)\n\t{\n\t\tcl.model_precache[i] = Mod_ForName (model_precache[i], false);\n\t\tif (cl.model_precache[i] == NULL)\n\t\t{\n\t\t\tif (cl_web_download.value && cl_web_download_url.string)\n\t\t\t{\n\t\t\t\tchar url[1024];\n\t\t\t\tbool success = false;\n\t\t\t\tchar download_tempname[MAX_QPATH], download_finalname[MAX_QPATH];\n\t\t\t\tchar folder[MAX_QPATH];\n\t\t\t\tchar name[MAX_QPATH];\n\t\t\t\textern char server_name[MAX_QPATH];\n\t\t\t\textern int net_hostport;\n\n\t\t\t\t//Create the FULL path where the file should be written\n\t\t\t\tsnprintf (download_tempname, MAX_OSPATH, \"%s/%s.tmp\", com_gamedir, model_precache[i]);\n\n\t\t\t\t//determine the proper folder and create it, the OS will ignore if already exsists\n\t\t\t\tCOM_GetFolder(model_precache[i],folder);// \"progs/\",\"maps/\"\n\t\t\t\tsnprintf (name, sizeof(name), \"%s/%s\", com_gamedir, folder);\n\t\t\t\tSys_mkdir (name);\n\n\t\t\t\tCon_Printf( \"Web downloading: %s from %s%s\\n\", model_precache[i], cl_web_download_url.string, model_precache[i]);\n\n\t\t\t\t//assign the url + path + file + extension we want\n\t\t\t\tsnprintf( url, sizeof( url ), \"%s%s\", cl_web_download_url.string, model_precache[i]);\n\n\t\t\t\tcls.download.web = true;\n\t\t\t\tcls.download.disconnect = false;\n\t\t\t\tcls.download.percent = 0.0;\n\n\t\t\t\t//let libCURL do it's magic!!\n\t\t\t\tsuccess = Web_Get(url, NULL, download_tempname, false, 600, 30, CL_WebDownloadProgress);\n\n\t\t\t\tcls.download.web = false;\n\n\t\t\t\tif (success)\n\t\t\t\t{\n\t\t\t\t\tCon_Printf(\"Web download successfull: %s\\n\", download_tempname);\n\t\t\t\t\t//Rename the .tmp file to the final precache filename\n\t\t\t\t\tsnprintf (download_finalname, MAX_OSPATH, \"%s/%s\", com_gamedir, model_precache[i]);\n\t\t\t\t\tsceIoRename(download_tempname, download_finalname);\n\n\t\t\t\t\tCbuf_AddText (va(\"connect %s:%u\\n\", server_name, net_hostport));//reconnect after each success\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tsceIoRemove(download_tempname);\n\t\t\t\t\tCon_Printf( \"Web download of %s failed\\n\", download_tempname );\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif( cls.download.disconnect ) //if the user type disconnect in the middle of the download\n\t\t\t\t{\n\t\t\t\t\tcls.download.disconnect = false;\n\t\t\t\t\tCL_Disconnect_f();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tCon_Printf(\"Model %s not found\\n\", model_precache[i]);\n\t\t\t\tSys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, \"CL_ParseServerInfo\");\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t\tCL_KeepaliveMessage ();\n\t}\n\n\tS_BeginPrecaching ();\n\tfor (i=1 ; i<numsounds ; i++)\n\t{\n\t\tcl.sound_precache[i] = S_PrecacheSound (sound_precache[i]);\n\t\tCL_KeepaliveMessage ();\n\t}\n\tS_EndPrecaching ();\n\n\n// local state\n\tcl_entities[0].model = cl.worldmodel = cl.model_precache[1];\n\tR_NewMap ();\n\tHunk_Check ();\t\t// make sure nothing is hurt\n\n\tnoclip_anglehack = false;\t\t// noclip is turned off at start\n\n\tSys_BigStackFree(MAX_MODELS * sizeof(char*) + MAX_MODELS * MAX_QPATH + MAX_SOUNDS * sizeof(char*) + MAX_SOUNDS * MAX_QPATH, \"CL_ParseServerInfo\");\n}\n\n\n/*\n==================\nCL_ParseUpdate\n\nParse an entity update message from the server\nIf an entities model or origin changes from frame to frame, it must be\nrelinked.  Other attributes can change without relinking.\n==================\n*/\nint\tbitcounts[16];\n\nvoid CL_ParseUpdate (int bits)\n{\n\tint\t\t\ti;\n\tmodel_t\t\t*model;\n\tint\t\t\tmodnum;\n\tbool\tforcelink;\n\tentity_t\t*ent;\n\tint\t\t\tnum;\n\tint\t\t\tskin;\n\n\tif (cls.signon == SIGNONS - 1)\n\t{\t// first update is the final signon stage\n\t\tcls.signon = SIGNONS;\n\t\tCL_SignonReply ();\n\t}\n\n\tif (bits & U_MOREBITS)\n\t\tbits |= MSG_ReadByte() << 8;\n\t\n\tif (bits & U_EXTEND1)\n\t{\n\t\tbits |= MSG_ReadByte() << 16;\n\n\t\tif (bits & U_EXTEND2)\n\t\t\tbits |= MSG_ReadByte() << 24;\n\t}\n\n\tif (bits & U_LONGENTITY)\n\t\tnum = MSG_ReadShort ();\n\telse\n\t\tnum = MSG_ReadByte ();\n\n\tent = CL_EntityNum (num);\n\n\tfor (i=0 ; i<16 ; i++)\n\t\tif (bits&(1<<i))\n\t\t\tbitcounts[i]++;\n\n\tif (ent->msgtime != cl.mtime[1])\n\t\tforcelink = true;\t// no previous frame to lerp from\n\telse\n\t\tforcelink = false;\n\n\tent->msgtime = cl.mtime[0];\n\n\tif (bits & U_MODEL)\n\t{\n\t\tmodnum = MSG_ReadByte ();\n\t\tif (modnum >= MAX_MODELS)\n\t\t\tHost_Error (\"CL_ParseModel: bad modnum\");\n\t}\n\telse\n\t\tmodnum = ent->baseline.modelindex;\n\n\tmodel = cl.model_precache[modnum];\n\tif (model != ent->model)\n\t{\n\t\tent->model = model;\n\t// automatic animation (torches, etc) can be either all together\n\t// or randomized\n\t\tif (model)\n\t\t{\n\t\t\tif (model->synctype == ST_RAND)\n\t\t\t\tent->syncbase = (float)(rand()&0x7fff) / 0x7fff;\n\t\t\telse\n\t\t\t\tent->syncbase = 0.0;\n\t\t}\n\t\telse\n\t\t\tforcelink = true;\t// hack to make null model players work\n#ifdef GLQUAKE\n\t\tif (num > 0 && num <= cl.maxclients)\n\t\t\tR_TranslatePlayerSkin (num - 1);\n#endif\n\t}\n\n\tif (bits & U_FRAME)\n\t\tent->frame = MSG_ReadByte ();\n\telse\n\t\tent->frame = ent->baseline.frame;\n\n\tif (bits & U_COLORMAP)\n\t\ti = MSG_ReadByte();\n\telse\n\t\ti = ent->baseline.colormap;\n\tif (!i)\n\t\tent->colormap = vid.colormap;\n\telse\n\t{\n\t\tif (i > cl.maxclients)\n\t\t\tSys_Error (\"i >= cl.maxclients\");\n\t\tent->colormap = cl.scores[i-1].translations;\n\t}\n\n\tif (bits & U_SKIN)\n\t\tskin = MSG_ReadByte();\n\telse\n\t\tskin = ent->baseline.skin;\n\tif (skin != ent->skinnum) {\n\t\tent->skinnum = skin;\n\t\tif (num > 0 && num <= cl.maxclients)\n\t\t\tR_TranslatePlayerSkin (num - 1);\n\t}\n\n\tif (bits & U_EFFECTS)\n\t\tent->effects = MSG_ReadByte();\n\telse\n\t\tent->effects = ent->baseline.effects;\n\n// shift the known values for interpolation\n\tVectorCopy (ent->msg_origins[0], ent->msg_origins[1]);\n\tVectorCopy (ent->msg_angles[0], ent->msg_angles[1]);\n\n\tif (bits & U_ORIGIN1)\n\t\tent->msg_origins[0][0] = MSG_ReadCoord ();\n\telse\n\t\tent->msg_origins[0][0] = ent->baseline.origin[0];\n\tif (bits & U_ANGLE1)\n\t\tent->msg_angles[0][0] = MSG_ReadAngle();\n\telse\n\t\tent->msg_angles[0][0] = ent->baseline.angles[0];\n\n\tif (bits & U_ORIGIN2)\n\t\tent->msg_origins[0][1] = MSG_ReadCoord ();\n\telse\n\t\tent->msg_origins[0][1] = ent->baseline.origin[1];\n\tif (bits & U_ANGLE2)\n\t\tent->msg_angles[0][1] = MSG_ReadAngle();\n\telse\n\t\tent->msg_angles[0][1] = ent->baseline.angles[1];\n\n\tif (bits & U_ORIGIN3)\n\t\tent->msg_origins[0][2] = MSG_ReadCoord ();\n\telse\n\t\tent->msg_origins[0][2] = ent->baseline.origin[2];\n\tif (bits & U_ANGLE3)\n\t\tent->msg_angles[0][2] = MSG_ReadAngle();\n\telse\n\t\tent->msg_angles[0][2] = ent->baseline.angles[2];\n\t\n\tif (bits & U_ALPHA)\n\t\tent->alpha = (float)(MSG_ReadByte()) / 255.0f;\n\t\n\tif (bits & U_RENDERAMT)\n\t\tent->alpha = (float)(MSG_ReadByte()) / 255.0f;\n\n\tif ( bits & U_NOLERP )\n\t\tent->forcelink = true;\n\n\tif ( forcelink )\n\t{\t// didn't have an update last message\n\t\tVectorCopy (ent->msg_origins[0], ent->msg_origins[1]);\n\t\tVectorCopy (ent->msg_origins[0], ent->origin);\n\t\tVectorCopy (ent->msg_angles[0], ent->msg_angles[1]);\n\t\tVectorCopy (ent->msg_angles[0], ent->angles);\n\t\tent->forcelink = true;\n\t}\n}\n\n/*\n==================\nCL_ParseBaseline\n==================\n*/\nvoid CL_ParseBaseline (entity_t *ent)\n{\n\tint\t\t\ti;\n\n\tent->baseline.modelindex = MSG_ReadByte ();\n\tent->baseline.frame = MSG_ReadByte ();\n\tent->baseline.colormap = MSG_ReadByte();\n\tent->baseline.skin = MSG_ReadByte();\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tent->baseline.origin[i] = MSG_ReadCoord ();\n\t\tent->baseline.angles[i] = MSG_ReadAngle ();\n\t}\n}\n\n\n/*\n==================\nCL_ParseClientdata\n\nServer information pertaining to this client only\n==================\n*/\nvoid CL_ParseClientdata (int bits)\n{\n\tint\t\ti, j;\n\n\tif (bits & SU_VIEWHEIGHT)\n\t\tcl.viewheight = MSG_ReadChar ();\n\telse\n\t\tcl.viewheight = DEFAULT_VIEWHEIGHT;\n\n\tif (bits & SU_IDEALPITCH)\n\t\tcl.idealpitch = MSG_ReadChar ();\n\telse\n\t\tcl.idealpitch = 0;\n\n\tVectorCopy (cl.mvelocity[0], cl.mvelocity[1]);\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (bits & (SU_PUNCH1<<i) )\n\t\t\tcl.punchangle[i] = MSG_ReadChar();\n\t\telse\n\t\t\tcl.punchangle[i] = 0;\n\t\tif (bits & (SU_VELOCITY1<<i) )\n\t\t\tcl.mvelocity[0][i] = MSG_ReadChar()*16;\n\t\telse\n\t\t\tcl.mvelocity[0][i] = 0;\n\t}\n\n// [always sent]\tif (bits & SU_ITEMS)\n\t\ti = MSG_ReadLong ();\n\n\tif (cl.items != i)\n\t{\t// set flash times\n\t\tSbar_Changed ();\n\t\tfor (j=0 ; j<32 ; j++)\n\t\t\tif ( (i & (1<<j)) && !(cl.items & (1<<j)))\n\t\t\t\tcl.item_gettime[j] = cl.time;\n\t\tcl.items = i;\n\t}\n\n\tcl.onground = (bits & SU_ONGROUND) != 0;\n\tcl.inwater = (bits & SU_INWATER) != 0;\n\n\tif (bits & SU_WEAPONFRAME)\n\t\tcl.stats[STAT_WEAPONFRAME] = MSG_ReadByte ();\n\telse\n\t\tcl.stats[STAT_WEAPONFRAME] = 0;\n\n\tif (bits & SU_ARMOR)\n\t\ti = MSG_ReadByte ();\n\telse\n\t\ti = 0;\n\tif (cl.stats[STAT_ARMOR] != i)\n\t{\n\t\tcl.stats[STAT_ARMOR] = i;\n\t\tSbar_Changed ();\n\t}\n\n\tif (bits & SU_WEAPON)\n\t\ti = MSG_ReadByte ();\n\telse\n\t\ti = 0;\n\tif (cl.stats[STAT_WEAPON] != i)\n\t{\n\t\tcl.stats[STAT_WEAPON] = i;\n\t\tSbar_Changed ();\n\t}\n\n\ti = MSG_ReadShort ();\n\tif (cl.stats[STAT_HEALTH] != i)\n\t{\n\t\tif (i < cl.stats[STAT_HEALTH]) IN_StartRumble();\n\t\tcl.stats[STAT_HEALTH] = i;\n\t\tSbar_Changed ();\n\t}\n\n\ti = MSG_ReadByte ();\n\tif (cl.stats[STAT_AMMO] != i)\n\t{\n\t\tcl.stats[STAT_AMMO] = i;\n\t\tSbar_Changed ();\n\t}\n\n\tfor (i=0 ; i<4 ; i++)\n\t{\n\t\tj = MSG_ReadByte ();\n\t\tif (cl.stats[STAT_SHELLS+i] != j)\n\t\t{\n\t\t\tcl.stats[STAT_SHELLS+i] = j;\n\t\t\tSbar_Changed ();\n\t\t}\n\t}\n\n\ti = MSG_ReadByte ();\n\n\tif (standard_quake)\n\t{\n\t\tif (cl.stats[STAT_ACTIVEWEAPON] != i)\n\t\t{\n\t\t\tcl.stats[STAT_ACTIVEWEAPON] = i;\n\t\t\tSbar_Changed ();\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (cl.stats[STAT_ACTIVEWEAPON] != (1<<i))\n\t\t{\n\t\t\tcl.stats[STAT_ACTIVEWEAPON] = (1<<i);\n\t\t\tSbar_Changed ();\n\t\t}\n\t}\n}\n\n/*\n=====================\nCL_NewTranslation\n=====================\n*/\nvoid CL_NewTranslation (int slot)\n{\n\tint\t\ti, j;\n\tint\t\ttop, bottom;\n\tbyte\t*dest, *source;\n\n\tif (slot > cl.maxclients)\n\t\tSys_Error (\"CL_NewTranslation: slot > cl.maxclients\");\n\tdest = cl.scores[slot].translations;\n\tsource = vid.colormap;\n\tmemcpy (dest, vid.colormap, sizeof(cl.scores[slot].translations));\n\ttop = cl.scores[slot].colors & 0xf0;\n\tbottom = (cl.scores[slot].colors &15)<<4;\n#ifdef GLQUAKE\n\tR_TranslatePlayerSkin (slot);\n#endif\n\n\tfor (i=0 ; i<VID_GRADES ; i++, dest += 256, source+=256)\n\t{\n\t\tif (top < 128)\t// the artists made some backwards ranges.  sigh.\n\t\t\tmemcpy (dest + TOP_RANGE, source + top, 16);\n\t\telse\n\t\t\tfor (j=0 ; j<16 ; j++)\n\t\t\t\tdest[TOP_RANGE+j] = source[top+15-j];\n\n\t\tif (bottom < 128)\n\t\t\tmemcpy (dest + BOTTOM_RANGE, source + bottom, 16);\n\t\telse\n\t\t\tfor (j=0 ; j<16 ; j++)\n\t\t\t\tdest[BOTTOM_RANGE+j] = source[bottom+15-j];\n\t}\n}\n\n/*\n=====================\nCL_ParseStatic\n=====================\n*/\nvoid CL_ParseStatic (void)\n{\n\tentity_t *ent;\n\n\t// mh - extended static entities begin\n\tent = (entity_t *) Hunk_Alloc (sizeof (entity_t));\n\tCL_ParseBaseline (ent);\n\t// mh - extended static entities end\n\n\t// copy it to the current state\n\tent->model = cl.model_precache[ent->baseline.modelindex];\n\tent->frame = ent->baseline.frame;\n\tent->colormap = vid.colormap;\n\tent->skinnum = ent->baseline.skin;\n\tent->effects = ent->baseline.effects;\n\n\tVectorCopy (ent->baseline.origin, ent->origin);\n\tVectorCopy (ent->baseline.angles, ent->angles);   \n\tR_AddEfrags (ent);\n}\n\n/*\n===================\nCL_ParseStaticSound\n===================\n*/\nvoid CL_ParseStaticSound (void)\n{\n\tvec3_t\t\torg;\n\tint\t\t\tsound_num, vol, atten;\n\tint\t\t\ti;\n\n\tfor (i=0 ; i<3 ; i++)\n\t\torg[i] = MSG_ReadCoord ();\n\tsound_num = MSG_ReadByte ();\n\tvol = MSG_ReadByte ();\n\tatten = MSG_ReadByte ();\n\n\tS_StaticSound (cl.sound_precache[sound_num], org, vol, atten);\n}\n\n\n#define SHOWNET(x) if(cl_shownet.value==2)Con_Printf (\"%3i:%s\\n\", msg_readcount-1, x);\n\n/*\n=====================\nCL_ParseServerMessage\n=====================\n*/\nvoid CL_ParseServerMessage (void)\n{\n\tint\t\t\tcmd;\n\tint\t\t\ti;\n\n//\n// if recording demos, copy the message out\n//\n\tif (cl_shownet.value == 1)\n\t\tCon_Printf (\"%i \",net_message.cursize);\n\telse if (cl_shownet.value == 2)\n\t\tCon_Printf (\"------------------\\n\");\n\n\tcl.onground = false;\t// unless the server says otherwise\n//\n// parse the message\n//\n\tMSG_BeginReading ();\n\n\twhile (1)\n\t{\n\t\tif (msg_badread)\n\t\t\tHost_Error (\"CL_ParseServerMessage: Bad server message\");\n\n\t\tcmd = MSG_ReadByte ();\n\t\tif (cmd == -1)\n\t\t{\n\t\t\tSHOWNET(\"END OF MESSAGE\");\n\t\t\treturn;\t\t// end of message\n\t\t}\n\n\t// if the high bit of the command byte is set, it is a fast update\n\t\tif (cmd & 128)\n\t\t{\n\t\t\tSHOWNET(\"fast update\");\n\t\t\tCL_ParseUpdate (cmd&127);\n\t\t\tcontinue;\n\t\t}\n\n\t\tSHOWNET(svc_strings[cmd]);\n\n\t// other commands\n\t\tswitch (cmd)\n\t\t{\n\t\tdefault:\n\t\t\tHost_Error (\"CL_ParseServerMessage: Illegible server message\\n\");\n\t\t\tbreak;\n\n\t\tcase svc_nop:\n//\t\t\tCon_Printf (\"svc_nop\\n\");\n\t\t\tbreak;\n\n\t\tcase svc_time:\n\t\t\tcl.mtime[1] = cl.mtime[0];\n\t\t\tcl.mtime[0] = MSG_ReadFloat ();\n\t\t\tbreak;\n\n\t\tcase svc_clientdata:\n\t\t\ti = MSG_ReadShort ();\n\t\t\tCL_ParseClientdata (i);\n\t\t\tbreak;\n\n\t\tcase svc_version:\n\t\t\ti = MSG_ReadLong ();\n\t\t\tif (i != PROTOCOL_NETQUAKE)\n\t\t\t\tHost_Error (\"CL_ParseServerMessage: Server is protocol %i instead of %i\\n\", i, PROTOCOL_NETQUAKE);\n\t\t\tbreak;\n\n\t\tcase svc_disconnect:\n\t\t\tHost_EndGame (\"Server disconnected\\n\");\n\n\t\tcase svc_print:\n\t\t\tCon_Printf (\"%s\", MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_centerprint:\n\t\t\tSCR_CenterPrint (MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_stufftext:\n\t\t\tCbuf_AddText (MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_damage:\n\t\t\tV_ParseDamage ();\n\t\t\tbreak;\n\n\t\tcase svc_serverinfo:\n\t\t\tCL_ParseServerInfo ();\n\t\t\tvid.recalc_refdef = true;\t// leave intermission full screen\n\t\t\tbreak;\n\n\t\tcase svc_setangle:\n\t\t\tfor (i=0 ; i<3 ; i++)\n\t\t\t\tcl.viewangles[i] = MSG_ReadAngle ();\n\t\t\tbreak;\n\n\t\tcase svc_setview:\n\t\t\tcl.viewentity = MSG_ReadShort ();\n\t\t\tbreak;\n\n\t\tcase svc_lightstyle:\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i >= MAX_LIGHTSTYLES)\n\t\t\t\tSys_Error (\"svc_lightstyle > MAX_LIGHTSTYLES\");\n\t\t\tstrcpy (cl_lightstyle[i].map,  MSG_ReadString());\n\t\t\tcl_lightstyle[i].length = strlen(cl_lightstyle[i].map);\n\t\t\tbreak;\n\n\t\tcase svc_sound:\n\t\t\tCL_ParseStartSoundPacket();\n\t\t\tbreak;\n\n\t\tcase svc_stopsound:\n\t\t\ti = MSG_ReadShort();\n\t\t\tS_StopSound(i>>3, i&7);\n\t\t\tbreak;\n\n\t\tcase svc_updatename:\n\t\t\tSbar_Changed ();\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i >= cl.maxclients)\n\t\t\t\tHost_Error (\"CL_ParseServerMessage: svc_updatename > MAX_SCOREBOARD\");\n\t\t\tstrcpy (cl.scores[i].name, MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_updatefrags:\n\t\t\tSbar_Changed ();\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i >= cl.maxclients)\n\t\t\t\tHost_Error (\"CL_ParseServerMessage: svc_updatefrags > MAX_SCOREBOARD\");\n\t\t\tcl.scores[i].frags = MSG_ReadShort ();\n\t\t\tbreak;\n\n\t\tcase svc_updatecolors:\n\t\t\tSbar_Changed ();\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i >= cl.maxclients)\n\t\t\t\tHost_Error (\"CL_ParseServerMessage: svc_updatecolors > MAX_SCOREBOARD\");\n\t\t\tcl.scores[i].colors = MSG_ReadByte ();\n\t\t\tCL_NewTranslation (i);\n\t\t\tbreak;\n\n\t\tcase svc_particle:\n\t\t\tR_ParseParticleEffect ();\n\t\t\tbreak;\n\n\t\tcase svc_spawnbaseline:\n\t\t\ti = MSG_ReadShort ();\n\t\t\t// must use CL_EntityNum() to force cl.num_entities up\n\t\t\tCL_ParseBaseline (CL_EntityNum(i));\n\t\t\tbreak;\n\t\tcase svc_spawnstatic:\n\t\t\tCL_ParseStatic ();\n\t\t\tbreak;\n\t\tcase svc_temp_entity:\n\t\t\tCL_ParseTEnt ();\n\t\t\tbreak;\n\n\t\tcase svc_setpause:\n\t\t\t{\n\t\t\t\tcl.paused = MSG_ReadByte ();\n\n\t\t\t\tif (cl.paused)\n\t\t\t\t{\n\t\t\t\t\tCDAudio_Pause ();\n#ifdef _WIN32\n\t\t\t\t\tVID_HandlePause (true);\n#endif\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCDAudio_Resume ();\n#ifdef _WIN32\n\t\t\t\t\tVID_HandlePause (false);\n#endif\n\t\t\t\t}\n\t\t\t}\n\t\t\tbreak;\n\n\t\tcase svc_signonnum:\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i <= cls.signon)\n\t\t\t\tHost_Error (\"Received signon %i when at %i\", i, cls.signon);\n\t\t\tcls.signon = i;\n\t\t\tCL_SignonReply ();\n\t\t\tbreak;\n\n\t\tcase svc_killedmonster:\n\t\t\tcl.stats[STAT_MONSTERS]++;\n\t\t\tbreak;\n\n\t\tcase svc_foundsecret:\n\t\t\tcl.stats[STAT_SECRETS]++;\n\t\t\tbreak;\n\n\t\tcase svc_updatestat:\n\t\t\ti = MSG_ReadByte ();\n\t\t\tif (i < 0 || i >= MAX_CL_STATS)\n\t\t\t\tSys_Error (\"svc_updatestat: %i is invalid\", i);\n\t\t\tcl.stats[i] = MSG_ReadLong ();;\n\t\t\tbreak;\n\n\t\tcase svc_spawnstaticsound:\n\t\t\tCL_ParseStaticSound ();\n\t\t\tbreak;\n\n\t\tcase svc_cdtrack:\n\t\t\tcl.cdtrack = MSG_ReadByte ();\n\t\t\tcl.looptrack = MSG_ReadByte ();\n\t\t\tif ( (cls.demoplayback || cls.demorecording) && (cls.forcetrack != -1) )\n\t\t\t\tCDAudio_Play ((byte)cls.forcetrack, true);\n\t\t\telse\n\t\t\t\tCDAudio_Play ((byte)cl.cdtrack, true);\n\t\t\tbreak;\n\n\t\tcase svc_intermission:\n\t\t\tcl.intermission = 1;\n\t\t\tcl.completed_time = cl.time;\n\t\t\tvid.recalc_refdef = true;\t// go to full screen\n\t\t\tbreak;\n\n\t\tcase svc_finale:\n\t\t\tcl.intermission = 2;\n\t\t\tcl.completed_time = cl.time;\n\t\t\tvid.recalc_refdef = true;\t// go to full screen\n\t\t\tSCR_CenterPrint (MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_cutscene:\n\t\t\tcl.intermission = 3;\n\t\t\tcl.completed_time = cl.time;\n\t\t\tvid.recalc_refdef = true;\t// go to full screen\n\t\t\tSCR_CenterPrint (MSG_ReadString ());\n\t\t\tbreak;\n\n\t\tcase svc_sellscreen:\n\t\t\tCmd_ExecuteString (\"help\", src_command);\n\t\t\tbreak;\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "source/cl_tent.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cl_tent.c -- client side temporary entities\n\n#include \"quakedef.h\"\n\nint\t\t\tnum_temp_entities;\nentity_t*\t\tcl_temp_entities;\nbeam_t\t\tcl_beams[MAX_BEAMS];\n\nsfx_t\t\t\t*cl_sfx_wizhit;\nsfx_t\t\t\t*cl_sfx_knighthit;\nsfx_t\t\t\t*cl_sfx_tink1;\nsfx_t\t\t\t*cl_sfx_ric1;\nsfx_t\t\t\t*cl_sfx_ric2;\nsfx_t\t\t\t*cl_sfx_ric3;\nsfx_t\t\t\t*cl_sfx_r_exp3;\n\n/*\n=================\nCL_ParseTEnt\n=================\n*/\nvoid CL_InitTEnts (void)\n{\n\tcl_sfx_wizhit = S_PrecacheSound (\"wizard/hit.wav\");\n\tcl_sfx_knighthit = S_PrecacheSound (\"hknight/hit.wav\");\n\tcl_sfx_tink1 = S_PrecacheSound (\"weapons/tink1.wav\");\n\tcl_sfx_ric1 = S_PrecacheSound (\"weapons/ric1.wav\");\n\tcl_sfx_ric2 = S_PrecacheSound (\"weapons/ric2.wav\");\n\tcl_sfx_ric3 = S_PrecacheSound (\"weapons/ric3.wav\");\n\tcl_sfx_r_exp3 = S_PrecacheSound (\"weapons/r_exp3.wav\");\n}\n\n/*\n=================\nCL_ParseBeam\n=================\n*/\nvoid CL_ParseBeam (model_t *m)\n{\n\tint\t\tent;\n\tvec3_t\tstart, end;\n\tbeam_t\t*b;\n\tint\t\ti;\n\t\n\tent = MSG_ReadShort ();\n\t\n\tstart[0] = MSG_ReadCoord ();\n\tstart[1] = MSG_ReadCoord ();\n\tstart[2] = MSG_ReadCoord ();\n\t\n\tend[0] = MSG_ReadCoord ();\n\tend[1] = MSG_ReadCoord ();\n\tend[2] = MSG_ReadCoord ();\n\n// override any beam with the same entity\n\tfor (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)\n\t\tif (b->entity == ent)\n\t\t{\n\t\t\tb->entity = ent;\n\t\t\tb->model = m;\n\t\t\tb->endtime = cl.time + 0.2;\n\t\t\tVectorCopy (start, b->start);\n\t\t\tVectorCopy (end, b->end);\n\t\t\treturn;\n\t\t}\n\n// find a free beam\n\tfor (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)\n\t{\n\t\tif (!b->model || b->endtime < cl.time)\n\t\t{\n\t\t\tb->entity = ent;\n\t\t\tb->model = m;\n\t\t\tb->endtime = cl.time + 0.2;\n\t\t\tVectorCopy (start, b->start);\n\t\t\tVectorCopy (end, b->end);\n\t\t\treturn;\n\t\t}\n\t}\n\tCon_Printf (\"beam list overflow!\\n\");\t\n}\n\n/*\n=================\nCL_ParseTEnt\n=================\n*/\nvoid CL_ParseTEnt (void)\n{\n\tint\t\ttype;\n\tvec3_t\tpos;\n#ifdef QUAKE2\n\tvec3_t\tendpos;\n#endif\n\tdlight_t\t*dl;\n\tint\t\trnd;\n\tint\t\tcolorStart, colorLength;\n\n\ttype = MSG_ReadByte ();\n\tswitch (type)\n\t{\n\tcase TE_WIZSPIKE:\t\t\t// spike hitting wall\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_RunParticleEffect (pos, vec3_origin, 20, 30);\n\t\tS_StartSound (-1, 0, cl_sfx_wizhit, pos, 1, 1);\n\t\tbreak;\n\t\t\n\tcase TE_KNIGHTSPIKE:\t\t\t// spike hitting wall\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_RunParticleEffect (pos, vec3_origin, 226, 20);\n\t\tS_StartSound (-1, 0, cl_sfx_knighthit, pos, 1, 1);\n\t\tbreak;\n\t\t\n\tcase TE_SPIKE:\t\t\t// spike hitting wall\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n#ifdef GLTEST\n\t\tTest_Spawn (pos);\n#else\n\t\tR_RunParticleEffect (pos, vec3_origin, 0, 10);\n#endif\n\t\tif ( rand() % 5 )\n\t\t\tS_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);\n\t\telse\n\t\t{\n\t\t\trnd = rand() & 3;\n\t\t\tif (rnd == 1)\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);\n\t\t\telse if (rnd == 2)\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);\n\t\t\telse\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);\n\t\t}\n\t\tbreak;\n\tcase TE_SUPERSPIKE:\t\t\t// super spike hitting wall\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_RunParticleEffect (pos, vec3_origin, 0, 20);\n\n\t\tif ( rand() % 5 )\n\t\t\tS_StartSound (-1, 0, cl_sfx_tink1, pos, 1, 1);\n\t\telse\n\t\t{\n\t\t\trnd = rand() & 3;\n\t\t\tif (rnd == 1)\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric1, pos, 1, 1);\n\t\t\telse if (rnd == 2)\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric2, pos, 1, 1);\n\t\t\telse\n\t\t\t\tS_StartSound (-1, 0, cl_sfx_ric3, pos, 1, 1);\n\t\t}\n\t\tbreak;\n\t\t\n\tcase TE_GUNSHOT:\t\t\t// bullet hitting wall\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_RunParticleEffect (pos, vec3_origin, 0, 20);\n\t\tbreak;\n\t\t\n\tcase TE_EXPLOSION:\t\t\t// rocket explosion\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_ParticleExplosion (pos);\n\t\tdl = CL_AllocDlight (0);\n\t\tVectorCopy (pos, dl->origin);\n\t\tdl->radius = 350;\n\t\tdl->die = cl.time + 0.5;\n\t\tdl->decay = 300;\n\t\tS_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);\n\t\tbreak;\n\t\t\n\tcase TE_TAREXPLOSION:\t\t\t// tarbaby explosion\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_BlobExplosion (pos);\n\n\t\tS_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);\n\t\tbreak;\n\n\tcase TE_LIGHTNING1:\t\t\t\t// lightning bolts\n\t\tCL_ParseBeam (Mod_ForName(\"progs/bolt.mdl\", true));\n\t\tbreak;\n\t\n\tcase TE_LIGHTNING2:\t\t\t\t// lightning bolts\n\t\tCL_ParseBeam (Mod_ForName(\"progs/bolt2.mdl\", true));\n\t\tbreak;\n\t\n\tcase TE_LIGHTNING3:\t\t\t\t// lightning bolts\n\t\tCL_ParseBeam (Mod_ForName(\"progs/bolt3.mdl\", true));\n\t\tbreak;\n\t\n// PGM 01/21/97 \n\tcase TE_BEAM:\t\t\t\t// grappling hook beam\n\t\tCL_ParseBeam (Mod_ForName(\"progs/beam.mdl\", true));\n\t\tbreak;\n// PGM 01/21/97\n\n\tcase TE_LAVASPLASH:\t\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_LavaSplash (pos);\n\t\tbreak;\n\t\n\tcase TE_TELEPORT:\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tR_TeleportSplash (pos);\n\t\tbreak;\n\t\t\n\tcase TE_EXPLOSION2:\t\t\t\t// color mapped explosion\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tcolorStart = MSG_ReadByte ();\n\t\tcolorLength = MSG_ReadByte ();\n\t\tR_ParticleExplosion2 (pos, colorStart, colorLength);\n\t\tdl = CL_AllocDlight (0);\n\t\tVectorCopy (pos, dl->origin);\n\t\tdl->radius = 350;\n\t\tdl->die = cl.time + 0.5;\n\t\tdl->decay = 300;\n\t\tS_StartSound (-1, 0, cl_sfx_r_exp3, pos, 1, 1);\n\t\tbreak;\n\t\t\n#ifdef QUAKE2\n\tcase TE_IMPLOSION:\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tS_StartSound (-1, 0, cl_sfx_imp, pos, 1, 1);\n\t\tbreak;\n\n\tcase TE_RAILTRAIL:\n\t\tpos[0] = MSG_ReadCoord ();\n\t\tpos[1] = MSG_ReadCoord ();\n\t\tpos[2] = MSG_ReadCoord ();\n\t\tendpos[0] = MSG_ReadCoord ();\n\t\tendpos[1] = MSG_ReadCoord ();\n\t\tendpos[2] = MSG_ReadCoord ();\n\t\tS_StartSound (-1, 0, cl_sfx_rail, pos, 1, 1);\n\t\tS_StartSound (-1, 1, cl_sfx_r_exp3, endpos, 1, 1);\n\t\tR_RocketTrail (pos, endpos, 0+128);\n\t\tR_ParticleExplosion (endpos);\n\t\tdl = CL_AllocDlight (-1);\n\t\tVectorCopy (endpos, dl->origin);\n\t\tdl->radius = 350;\n\t\tdl->die = cl.time + 0.5;\n\t\tdl->decay = 300;\n\t\tbreak;\n#endif\n\n\tdefault:\n\t\tSys_Error (\"CL_ParseTEnt: bad type\");\n\t}\n}\n\n\n/*\n=================\nCL_NewTempEntity\n=================\n*/\nentity_t *CL_NewTempEntity (void)\n{\n\tentity_t\t*ent;\n\n\tif (cl_numvisedicts == MAX_VISEDICTS)\n\t\treturn NULL;\n\tif (num_temp_entities == MAX_TEMP_ENTITIES)\n\t\treturn NULL;\n\tent = &cl_temp_entities[num_temp_entities];\n\tmemset (ent, 0, sizeof(*ent));\n\tnum_temp_entities++;\n\tcl_visedicts[cl_numvisedicts] = ent;\n\tcl_numvisedicts++;\n\n\tent->colormap = vid.colormap;\n\treturn ent;\n}\n\n\n/*\n=================\nCL_UpdateTEnts\n=================\n*/\nvoid CL_UpdateTEnts (void)\n{\n\tint\t\t\ti;\n\tbeam_t\t\t*b;\n\tvec3_t\t\tdist, org;\n\tfloat\t\td;\n\tentity_t\t*ent;\n\tfloat\t\tyaw, pitch;\n\tfloat\t\tforward;\n\n\tnum_temp_entities = 0;\n\n// update lightning\n\tfor (i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++)\n\t{\n\t\tif (!b->model || b->endtime < cl.time)\n\t\t\tcontinue;\n\n\t// if coming from the player, update the start position\n\t\tif (b->entity == cl.viewentity)\n\t\t{\n\t\t\tVectorCopy (cl_entities[cl.viewentity].origin, b->start);\n\t\t}\n\n\t// calculate pitch and yaw\n\t\tVectorSubtract (b->end, b->start, dist);\n\n\t\tif (dist[1] == 0 && dist[0] == 0)\n\t\t{\n\t\t\tyaw = 0;\n\t\t\tif (dist[2] > 0)\n\t\t\t\tpitch = 90;\n\t\t\telse\n\t\t\t\tpitch = 270;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tyaw = (int) (atan2(dist[1], dist[0]) * 180 / M_PI);\n\t\t\tif (yaw < 0)\n\t\t\t\tyaw += 360;\n\t\n\t\t\tforward = sqrt (dist[0]*dist[0] + dist[1]*dist[1]);\n\t\t\tpitch = (int) (atan2(dist[2], forward) * 180 / M_PI);\n\t\t\tif (pitch < 0)\n\t\t\t\tpitch += 360;\n\t\t}\n\n\t// add new entities for the lightning\n\t\tVectorCopy (b->start, org);\n\t\td = VectorNormalize(dist);\n\t\twhile (d > 0)\n\t\t{\n\t\t\tent = CL_NewTempEntity ();\n\t\t\tif (!ent)\n\t\t\t\treturn;\n\t\t\tVectorCopy (org, ent->origin);\n\t\t\tent->model = b->model;\n\t\t\tent->angles[0] = pitch;\n\t\t\tent->angles[1] = yaw;\n\t\t\tent->angles[2] = rand()%360;\n\n\t\t\tfor (i=0 ; i<3 ; i++)\n\t\t\t\torg[i] += dist[i]*30;\n\t\t\td -= 30;\n\t\t}\n\t}\n\t\n}\n\n\n"
  },
  {
    "path": "source/client.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// client.h\n\ntypedef struct\n{\n\tvec3_t\tviewangles;\n\n// intended velocities\n\tfloat\tforwardmove;\n\tfloat\tsidemove;\n\tfloat\tupmove;\n#ifdef QUAKE2\n\tbyte\tlightlevel;\n#endif\n} usercmd_t;\n\ntypedef struct\n{\n\tint\t\tlength;\n\tchar\tmap[MAX_STYLESTRING];\n} lightstyle_t;\n\ntypedef struct\n{\n\tchar\tname[MAX_SCOREBOARDNAME];\n\tfloat\tentertime;\n\tint\t\tfrags;\n\tint\t\tcolors;\t\t\t// two 4 bit fields\n\tbyte\ttranslations[VID_GRADES*256];\n} scoreboard_t;\n\ntypedef struct\n{\n\tint\t\tdestcolor[3];\n\tint\t\tpercent;\t\t// 0-256\n} cshift_t;\n\n#define\tCSHIFT_CONTENTS\t0\n#define\tCSHIFT_DAMAGE\t1\n#define\tCSHIFT_BONUS\t2\n#define\tCSHIFT_POWERUP\t3\n#define\tNUM_CSHIFTS\t\t4\n\n#define\tNAME_LENGTH\t64\n\n\n//\n// client_state_t should hold all pieces of the client state\n//\n\n#define\tSIGNONS\t\t4\t\t\t// signon messages to receive before connected\n\n#define\tMAX_DLIGHTS\t\t128\ntypedef struct\n{\n\tvec3_t\torigin;\n\tfloat\tradius;\n\tfloat\tdie;\t\t\t\t// stop lighting after this time\n\tfloat\tdecay;\t\t\t\t// drop this each second\n\tfloat\tminlight;\t\t\t// don't add when contributing less\n\tint\t\tkey;\n#ifdef QUAKE2\n\tbool\tdark;\t\t\t// subtracts light instead of adding\n#endif\n\tvec3_t color; //LordHavoc Lit. Support\n\tfloat alpha;\n} dlight_t;\n\n\n#define\tMAX_BEAMS\t24\ntypedef struct\n{\n\tint\t\tentity;\n\tstruct model_s\t*model;\n\tfloat\tendtime;\n\tvec3_t\tstart, end;\n} beam_t;\n\n#define\tMAX_EFRAGS\t\t640\n\n#define\tMAX_MAPSTRING\t2048\n#define\tMAX_DEMOS\t\t8\n#define\tMAX_DEMONAME\t16\n\ntypedef enum {\n\tca_dedicated, \t\t// a dedicated server with no ability to start a client\n\tca_disconnected, \t// full screen console with no connection\n\tca_connected\t\t// valid netcon, talking to a server\n} cactive_t;\n\ntypedef struct\n{\n\tbool web;\n\tchar *name;\n\tdouble percent;\n\tbool disconnect; // set when user tries to disconnect, to allow cleaning up webdownload\n} download_t;\n\n//\n// the client_static_t structure is persistant through an arbitrary number\n// of server connections\n//\ntypedef struct\n{\n\tcactive_t\tstate;\n\n// personalization data sent to server\t\n\tchar\t\tmapstring[MAX_QPATH];\n\tchar\t\tspawnparms[MAX_MAPSTRING];\t// to restart a level\n\n// demo loop control\n\tint\t\t\tdemonum;\t\t// -1 = don't play demos\n\tchar\t\tdemos[MAX_DEMOS][MAX_DEMONAME];\t\t// when not playing\n\n// demo recording info must be here, because record is started before\n// entering a map (and clearing client_state_t)\n\tbool\tdemorecording;\n\tbool\tdemoplayback;\n\tbool\ttimedemo;\n\tint\t\t\tforcetrack;\t\t\t// -1 = use normal cd track\n\tFILE\t\t*demofile;\n\tint\t\t\ttd_lastframe;\t\t// to meter out one message a frame\n\tint\t\t\ttd_startframe;\t\t// host_framecount at start\n\tfloat\t\ttd_starttime;\t\t// realtime at second frame of timedemo\n\n\n// connection information\n\tint\t\t\tsignon;\t\t\t// 0 to SIGNONS\n\tstruct qsocket_s\t*netcon;\n\tsizebuf_t\tmessage;\t\t// writing buffer to send to server\n\tdownload_t\tdownload;\n} client_static_t;\n\nextern client_static_t\tcls;\n\n//\n// the client_state_t structure is wiped completely at every\n// server signon\n//\ntypedef struct\n{\n\tint\t\t\tmovemessages;\t// since connecting to this server\n\t\t\t\t\t\t\t\t// throw out the first couple, so the player\n\t\t\t\t\t\t\t\t// doesn't accidentally do something the \n\t\t\t\t\t\t\t\t// first frame\n\tusercmd_t\tcmd;\t\t\t// last command sent to the server\n\n// information for local display\n\tint\t\t\tstats[MAX_CL_STATS];\t// health, etc\n\tint\t\t\titems;\t\t\t// inventory bit flags\n\tfloat\titem_gettime[32];\t// cl.time of aquiring item, for blinking\n\tfloat\t\tfaceanimtime;\t// use anim frame if cl.time < this\n\n\tcshift_t\tcshifts[NUM_CSHIFTS];\t// color shifts for damage, powerups\n\tcshift_t\tprev_cshifts[NUM_CSHIFTS];\t// and content types\n\n// the client maintains its own idea of view angles, which are\n// sent to the server each frame.  The server sets punchangle when\n// the view is temporarliy offset, and an angle reset commands at the start\n// of each level and after teleporting.\n\tvec3_t\t\tmviewangles[2];\t// during demo playback viewangles is lerped\n\t\t\t\t\t\t\t\t// between these\n\tvec3_t\t\tviewangles;\n\t\n\tvec3_t\t\tmvelocity[2];\t// update by server, used for lean+bob\n\t\t\t\t\t\t\t\t// (0 is newest)\n\tvec3_t\t\tvelocity;\t\t// lerped between mvelocity[0] and [1]\n\n\tvec3_t\t\tpunchangle;\t\t// temporary offset\n\t\n// pitch drifting vars\n\tfloat\t\tidealpitch;\n\tfloat\t\tpitchvel;\n\tbool\tnodrift;\n\tfloat\t\tdriftmove;\n\tdouble\t\tlaststop;\n\n\tfloat\t\tviewheight;\n\tfloat\t\tcrouch;\t\t\t// local amount for smoothing stepups\n\n\tbool\tpaused;\t\t\t// send over by server\n\tbool\tonground;\n\tbool\tinwater;\n\t\n\tint\t\t\tintermission;\t// don't change view angle, full screen, etc\n\tint\t\t\tcompleted_time;\t// latched at intermission start\n\t\n\tdouble\t\tmtime[2];\t\t// the timestamp of last two messages\t\n\tdouble\t\ttime;\t\t\t// clients view of time, should be between\n\t\t\t\t\t\t\t\t// servertime and oldservertime to generate\n\t\t\t\t\t\t\t\t// a lerp point for other data\n\tdouble\t\toldtime;\t\t// previous cl.time, time-oldtime is used\n\t\t\t\t\t\t\t\t// to decay light values and smooth step ups\n\t\n\n\tfloat\t\tlast_received_message;\t// (realtime) for net trouble icon\n\n//\n// information that is static for the entire time connected to a server\n//\n\tstruct model_s\t\t*model_precache[MAX_MODELS];\n\tstruct sfx_s\t\t*sound_precache[MAX_SOUNDS];\n\n\tchar\t\tlevelname[40];\t// for display on solo scoreboard\n\tint\t\t\tviewentity;\t\t// cl_entitites[cl.viewentity] = player\n\tint\t\t\tmaxclients;\n\tint\t\t\tgametype;\n\n// refresh related state\n\tstruct model_s\t*worldmodel;\t// cl_entitites[0].model\n\tstruct efrag_s\t*free_efrags;\n\tint\t\t\tnum_entities;\t// held in cl_entities array\n\tentity_t\tviewent;\t\t\t// the gun model\n\n\tint\t\t\tcdtrack, looptrack;\t// cd audio\n\n// frag scoreboard\n\tscoreboard_t\t*scores;\t\t// [cl.maxclients]\n\n} client_state_t;\n\n\n//\n// cvars\n//\nextern\tcvar_t\tcl_name;\nextern\tcvar_t\tcl_color;\n\nextern\tcvar_t\tcl_upspeed;\nextern\tcvar_t\tcl_forwardspeed;\nextern\tcvar_t\tcl_backspeed;\nextern\tcvar_t\tcl_sidespeed;\n\nextern\tcvar_t\tcl_movespeedkey;\n\nextern\tcvar_t\tcl_yawspeed;\nextern\tcvar_t\tcl_pitchspeed;\n\nextern\tcvar_t\tcl_anglespeedkey;\n\nextern\tcvar_t\tcl_autofire;\n\nextern\tcvar_t\tcl_shownet;\nextern\tcvar_t\tcl_nolerp;\n\nextern\tcvar_t\tcl_pitchdriftspeed;\nextern\tcvar_t\tlookspring;\nextern\tcvar_t\tlookstrafe;\nextern\tcvar_t\tsensitivity;\n\nextern\tcvar_t\tm_pitch;\nextern\tcvar_t\tm_yaw;\nextern\tcvar_t\tm_forward;\nextern\tcvar_t\tm_side;\n\n\n#define\tMAX_TEMP_ENTITIES\t64\t\t\t// lightning bolts, etc\n\nextern\tclient_state_t\tcl;\n\n// FIXME, allocate dynamically\nextern\tefrag_t*\t\t\tcl_efrags;\nextern\tentity_t*\t\tcl_entities;\nextern\tlightstyle_t\tcl_lightstyle[MAX_LIGHTSTYLES];\nextern\tdlight_t\t\tcl_dlights[MAX_DLIGHTS];\nextern\tentity_t*\t\tcl_temp_entities;\nextern\tbeam_t\t\t\tcl_beams[MAX_BEAMS];\n\n//=============================================================================\n\n//\n// cl_main\n//\ndlight_t *CL_AllocDlight (int key);\nvoid\tCL_DecayLights (void);\n\nvoid CL_Init (void);\n\nvoid CL_EstablishConnection (char *host);\nvoid CL_Signon1 (void);\nvoid CL_Signon2 (void);\nvoid CL_Signon3 (void);\nvoid CL_Signon4 (void);\n\nvoid CL_Disconnect (void);\nvoid CL_Disconnect_f (void);\nvoid CL_NextDemo (void);\n\n#define\t\t\tMAX_VISEDICTS\t256\nextern\tint\t\t\t\tcl_numvisedicts;\nextern\tentity_t\t\t*cl_visedicts[MAX_VISEDICTS];\n\n//\n// cl_input\n//\ntypedef struct\n{\n\tint\t\tdown[2];\t\t// key nums holding it down\n\tint\t\tstate;\t\t\t// low bit is down state\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_SendMove (usercmd_t *cmd);\n\nvoid CL_ParseTEnt (void);\nvoid CL_UpdateTEnts (void);\n\nvoid CL_ClearState (void);\n\n\nint  CL_ReadFromServer (void);\nvoid CL_WriteToServer (usercmd_t *cmd);\nvoid CL_BaseMove (usercmd_t *cmd);\n\n\nfloat CL_KeyState (kbutton_t *key);\nchar *Key_KeynumToString (int keynum);\n\n//\n// cl_demo.c\n//\nvoid CL_StopPlayback (void);\nint CL_GetMessage (void);\n\nvoid CL_Stop_f (void);\nvoid CL_Record_f (void);\nvoid CL_PlayDemo_f (void);\nvoid CL_TimeDemo_f (void);\nvoid CL_Benchmark_f (void);\n\n//\n// cl_parse.c\n//\nvoid CL_ParseServerMessage (void);\nvoid CL_NewTranslation (int slot);\n\n//\n// view\n//\nvoid V_StartPitchDrift (void);\nvoid V_StopPitchDrift (void);\n\nvoid V_RenderView (void);\nvoid V_UpdatePalette (void);\nvoid V_Register (void);\nvoid V_ParseDamage (void);\nvoid V_SetContentsColor (int contents);\n\n\n//\n// cl_tent\n//\nvoid CL_InitTEnts (void);\nvoid CL_SignonReply (void);\n"
  },
  {
    "path": "source/cmd.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cmd.c -- Quake script command processing module\n\n#include \"quakedef.h\"\n\nvoid Cmd_ForwardToServer (void);\nextern byte *COM_LoadFile (const char *path, int usehunk);\n\n#define\tMAX_ALIAS_NAME\t32\n\ntypedef struct cmdalias_s\n{\n\tstruct cmdalias_s\t*next;\n\tchar\tname[MAX_ALIAS_NAME];\n\tchar\t*value;\n} cmdalias_t;\n\ncmdalias_t\t*cmd_alias;\n\nint trashtest;\nint *trashspot;\n\nbool\tcmd_wait;\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 \"impulse 5 ; +attack ; wait ; -attack ; impulse 2\"\n============\n*/\nvoid Cmd_Wait_f (void)\n{\n\tcmd_wait = true;\n}\n\n/*\n=============================================================================\n\n\t\t\t\t\t\tCOMMAND BUFFER\n\n=============================================================================\n*/\n\nsizebuf_t\tcmd_text;\n\n/*\n============\nCbuf_Init\n============\n*/\nvoid Cbuf_Init (void)\n{\n\tSZ_Alloc (&cmd_text, 8192);\t\t// space for commands and script files\n}\n\n\n/*\n============\nCbuf_AddText\n\nAdds command text at the end of the buffer\n============\n*/\nvoid Cbuf_AddText (const char *text)\n{\n\tint\t\tl;\n\n\tl = strlen (text);\n\n\tif (cmd_text.cursize + l >= cmd_text.maxsize)\n\t{\n\t\tCon_Printf (\"Cbuf_AddText: overflow\\n\");\n\t\treturn;\n\t}\n\n\tSZ_Write (&cmd_text, text, strlen (text));\n}\n\n\n/*\n============\nCbuf_InsertText\nAdds command text immediately after the current command\nAdds a \\n to the text\nFIXME: actually change the command buffer to do less copying\n============\n*/\nvoid Cbuf_InsertText(char *text)\n{\n\tchar *temp = NULL;\n\tint templen = cmd_text.cursize;\n\n\t// copy off any commands still remaining in the exec buffer\n\tif (templen) {\n\t\ttemp = Z_Malloc(templen);\n\t\tmemcpy(temp, cmd_text.data, templen);\n\t\tSZ_Clear(&cmd_text);\n\t}\n\n\t// add the entire text of the file\n\tCbuf_AddText(text);\n\n\t// add the copied off data\n\tif (templen) {\n\t\tSZ_Write(&cmd_text, temp, templen);\n\t\tZ_Free(temp);\n\t}\n}\n\n/*\n============\nCbuf_Execute\n============\n*/\nvoid Cbuf_Execute(void)\n{\n\tint i;\n\tchar *text;\n\tchar*\tline = Sys_BigStackAlloc(1024, \"Cbuf_Execute\");\n\tint quotes;\n\tint notcmd;\t// JPG - so that the ENTIRE line can be forwarded\n\n\twhile (cmd_text.cursize) {\n\t\t// find a \\n or ; line break\n\t\ttext = (char *)cmd_text.data;\n\n\t\tquotes = 0;\n\t\tnotcmd = strncmp(text, \"cmd \", 4);  // JPG - so that the ENTIRE line can be forwarded\n\t\tfor (i = 0; i < cmd_text.cursize; i++) {\n\t\t\tif (text[i] == '\"')\n\t\t\t\tquotes++;\n\t\t\tif (!(quotes & 1) && text[i] == ';' && notcmd) // JPG - added && cmd so that the ENTIRE line can be forwareded\n\t\t\t\tbreak;\t// don't break if inside a quoted string\n\t\t\tif (text[i] == '\\n')\n\t\t\t\tbreak;\n\t\t}\n\n\t\tmemmove(line, text, i);\n\t\tline[i] = 0;\n\n\t\t// delete the text from the command buffer and move remaining commands down\n\t\t// this is necessary because commands (exec, alias) can insert data at the\n\t\t// 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\ti++;\n\t\t\tcmd_text.cursize -= i;\n\t\t\tmemmove(text, text + i, cmd_text.cursize);\n\t\t}\n\n\t\t// execute the command line\n\t\tCmd_ExecuteString(line, src_command);\n\n\t\tif (cmd_wait) {\n\t\t\t// skip out while text still remains in buffer, leaving it for next frame\n\t\t\tcmd_wait = false;\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tSys_BigStackFree(1024, \"Cbuf_Execute\");\n}\n\n\n/*\n==============================================================================\n\n\t\t\t\t\t\tSCRIPT COMMANDS\n\n==============================================================================\n*/\n\n/*\n===============\nCmd_StuffCmds_f\n\nAdds command line parameters as script statements\nCommands lead with a +, and continue until a - or another +\nquake +prog jctest.qp +cmd amlev1\nquake -nosound +cmd amlev1\n===============\n*/\nvoid Cmd_StuffCmds_f (void)\n{\n\tint\t\ti, j;\n\tint\t\ts;\n\tchar\t*text, *build, c;\n\n\tif (Cmd_Argc () != 1)\n\t{\n\t\tCon_Printf (\"stuffcmds : execute command line parameters\\n\");\n\t\treturn;\n\t}\n\n// build the combined string to parse from\n\ts = 0;\n\tfor (i=1 ; i<com_argc ; i++)\n\t{\n\t\tif (!com_argv[i])\n\t\t\tcontinue;\t\t// NEXTSTEP nulls out -NXHost\n\t\ts += strlen (com_argv[i]) + 1;\n\t}\n\tif (!s)\n\t\treturn;\n\n\ttext = Z_Malloc (s+1);\n\ttext[0] = 0;\n\tfor (i=1 ; i<com_argc ; i++)\n\t{\n\t\tif (!com_argv[i])\n\t\t\tcontinue;\t\t// NEXTSTEP nulls out -NXHost\n\t\tstrcat (text,com_argv[i]);\n\t\tif (i != com_argc-1)\n\t\t\tstrcat (text, \" \");\n\t}\n\n// pull out the commands\n\tbuild = Z_Malloc (s+1);\n\tbuild[0] = 0;\n\n\tfor (i=0 ; i<s-1 ; i++)\n\t{\n\t\tif (text[i] == '+')\n\t\t{\n\t\t\ti++;\n\n\t\t\tfor (j=i ; (text[j] != '+') && (text[j] != '-') && (text[j] != 0) ; j++)\n\t\t\t\t;\n\n\t\t\tc = text[j];\n\t\t\ttext[j] = 0;\n\n\t\t\tstrcat (build, text+i);\n\t\t\tstrcat (build, \"\\n\");\n\t\t\ttext[j] = c;\n\t\t\ti = j-1;\n\t\t}\n\t}\n\n\tif (build[0])\n\t\tCbuf_InsertText (build);\n\n\tZ_Free (text);\n\tZ_Free (build);\n}\n\n\n/*\n===============\nCmd_Exec_f\n===============\n*/\nvoid Cmd_Exec_f (void)\n{\n\tchar\t*f;\n\tint\t\tmark;\n\n\tif (Cmd_Argc () != 2)\n\t{\n\t\tCon_Printf (\"exec <filename> : execute a script file\\n\");\n\t\treturn;\n\t}\n\n\tmark = Hunk_LowMark ();\n\tf = (char *)COM_LoadFile (Cmd_Argv(1),0);\n\tif (!f)\n\t{\n\t\tCon_Printf (\"couldn't exec %s\\n\",Cmd_Argv(1));\n\t\treturn;\n\t}\n\n\tCon_Printf (\"execing %s\\n\",Cmd_Argv(1));\n\tCbuf_InsertText (f);\n\tHunk_FreeToLowMark (mark);\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\n\tfor (i=1 ; i<Cmd_Argc() ; i++)\n\t\tCon_Printf (\"%s \",Cmd_Argv(i));\n\tCon_Printf (\"\\n\");\n}\n\n/*\n===============\nCmd_Alias_f\n\nCreates a new command that executes a command string (possibly ; seperated)\n===============\n*/\n\nchar *CopyString (char *in)\n{\n\tchar\t*out;\n\n\tout = Z_Malloc (strlen(in)+1);\n\tstrcpy (out, in);\n\treturn out;\n}\n\nvoid Cmd_Alias_f (void)\n{\n\tcmdalias_t\t*a;\n\tchar*\t\tcmd;\n\tint\t\t\ti, c;\n\tchar\t\t*s;\n\n\tif (Cmd_Argc() == 1)\n\t{\n\t\tCon_Printf (\"Current alias commands:\\n\");\n\t\tfor (a = cmd_alias ; a ; a=a->next)\n\t\t\tCon_Printf (\"%s : %s\\n\", a->name, a->value);\n\t\treturn;\n\t}\n\n\ts = Cmd_Argv(1);\n\tif (strlen(s) >= MAX_ALIAS_NAME)\n\t{\n\t\tCon_Printf (\"Alias name is too long\\n\");\n\t\treturn;\n\t}\n\n\t// if the alias already exists, reuse it\n\tfor (a = cmd_alias ; a ; a=a->next)\n\t{\n\t\tif (!strcmp(s, a->name))\n\t\t{\n\t\t\tZ_Free (a->value);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (!a)\n\t{\n\t\ta = Z_Malloc (sizeof(cmdalias_t));\n\t\ta->next = cmd_alias;\n\t\tcmd_alias = a;\n\t}\n\tstrcpy (a->name, s);\n\n\tcmd = Sys_BigStackAlloc(1024, \"Cmd_Alias_f\");\n\n// copy the rest of the command line\n\tcmd[0] = 0;\t\t// start out with a null string\n\tc = Cmd_Argc();\n\tfor (i=2 ; i< c ; i++)\n\t{\n\t\tstrcat (cmd, Cmd_Argv(i));\n\t\tif (i != c)\n\t\t\tstrcat (cmd, \" \");\n\t}\n\tstrcat (cmd, \"\\n\");\n\n\ta->value = CopyString (cmd);\n\n\tSys_BigStackFree(1024, \"Cmd_Alias_f\");\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\n#define\tMAX_ARGS\t\t80\n\nstatic\tint\t\t\tcmd_argc;\nstatic\tchar\t\t*cmd_argv[MAX_ARGS];\nstatic\tchar\t\t*cmd_null_string = \"\";\nstatic\tchar\t\t*cmd_args = NULL;\n\ncmd_source_t\tcmd_source;\n\n\nstatic\tcmd_function_t\t*cmd_functions;\t\t// possible commands to execute\n\n/*\n============\nCmd_Init\n============\n*/\nvoid Cmd_Init (void)\n{\n//\n// register our commands\n//\n\tCmd_AddCommand (\"stuffcmds\",Cmd_StuffCmds_f);\n\tCmd_AddCommand (\"exec\",Cmd_Exec_f);\n\tCmd_AddCommand (\"echo\",Cmd_Echo_f);\n\tCmd_AddCommand (\"alias\",Cmd_Alias_f);\n\tCmd_AddCommand (\"cmd\", Cmd_ForwardToServer);\n\tCmd_AddCommand (\"wait\", Cmd_Wait_f);\n\tCmd_AddCommand (\"set\", Cvar_Set_f);\n\tCmd_AddCommand (\"seta\", Cvar_Seta_f);\n}\n\n/*\n============\nCmd_Argc\n============\n*/\nint\t\tCmd_Argc (void)\n{\n\treturn cmd_argc;\n}\n\n/*\n============\nCmd_Argv\n============\n*/\nchar\t*Cmd_Argv (int arg)\n{\n\tif ( (unsigned)arg >= cmd_argc )\n\t\treturn cmd_null_string;\n\treturn cmd_argv[arg];\n}\n\n/*\n============\nCmd_Args\n============\n*/\nchar\t\t*Cmd_Args (void)\n{\n\treturn cmd_args;\n}\n\n\n/*\n============\nCmd_TokenizeString\n\nParses the given string into command line tokens.\n============\n*/\nvoid Cmd_TokenizeString (const char *text)\n{\n\tint\t\ti;\n\n// clear the args from the last string\n\tfor (i=0 ; i<cmd_argc ; i++)\n\t\tZ_Free (cmd_argv[i]);\n\n\tcmd_argc = 0;\n\tcmd_args = NULL;\n\n\twhile (1)\n\t{\n// skip whitespace up to a /n\n\t\twhile (*text && *text <= ' ' && *text != '\\n')\n\t\t{\n\t\t\ttext++;\n\t\t}\n\n\t\tif (*text == '\\n')\n\t\t{\t// a newline seperates commands in the buffer\n\t\t\ttext++;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!*text)\n\t\t\treturn;\n\n\t\tif (cmd_argc == 1)\n\t\t\t cmd_args = (char*)text;\n\n\t\ttext = COM_Parse (text);\n\t\tif (!text)\n\t\t\treturn;\n\n\t\tif (cmd_argc < MAX_ARGS)\n\t\t{\n\t\t\tcmd_argv[cmd_argc] = Z_Malloc (strlen(com_token)+1);\n\t\t\tstrcpy (cmd_argv[cmd_argc], com_token);\n\t\t\tcmd_argc++;\n\t\t}\n\t}\n\n}\n\n\n/*\n============\nCmd_AddCommand\n============\n*/\nvoid\tCmd_AddCommand (const char *cmd_name, xcommand_t function)\n{\n\tcmd_function_t\t*cmd;\n\n\tif (host_initialized)\t// because hunk allocation would get stomped\n\t\tSys_Error (\"Cmd_AddCommand after host_initialized\");\n\n// fail if the command is a variable name\n\tif (Cvar_VariableString(cmd_name)[0])\n\t{\n\t\tCon_Printf (\"Cmd_AddCommand: %s already defined as a var\\n\", cmd_name);\n\t\treturn;\n\t}\n\n// fail if the command already exists\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next)\n\t{\n\t\tif (!strcmp (cmd_name, cmd->name))\n\t\t{\n\t\t\tCon_Printf (\"Cmd_AddCommand: %s already defined\\n\", cmd_name);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tcmd = Hunk_Alloc (sizeof(cmd_function_t));\n\tcmd->name = (char*)cmd_name;\n\tcmd->function = function;\n\tcmd->next = cmd_functions;\n\tcmd_functions = cmd;\n}\n\n/*\n============\nCmd_Exists\n============\n*/\nbool\tCmd_Exists (const char *cmd_name)\n{\n\tcmd_function_t\t*cmd;\n\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next)\n\t{\n\t\tif (!strcmp (cmd_name,cmd->name))\n\t\t\treturn true;\n\t}\n\n\treturn false;\n}\n\n\n\n/*\n============\nCmd_CompleteCommand\n============\n*/\nchar *Cmd_CompleteCommand (char *partial)\n{\n\tcmd_function_t\t*cmd;\n\tint\t\t\t\tlen;\n\n\tlen = strlen(partial);\n\n\tif (!len)\n\t\treturn NULL;\n\n// check functions\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next)\n\t\tif (!strncmp (partial,cmd->name, len))\n\t\t\treturn cmd->name;\n\n\treturn NULL;\n}\n\n/*\n============\nCmd_ExecuteString\n\nA complete command line has been parsed, so try to execute it\nFIXME: lookupnoadd the token to speed search?\n============\n*/\nvoid\tCmd_ExecuteString (char *text, cmd_source_t src)\n{\n\tcmd_function_t\t*cmd;\n\tcmdalias_t\t\t*a;\n\n\tcmd_source = src;\n\tCmd_TokenizeString (text);\n\n// execute the command line\n\tif (!Cmd_Argc())\n\t\treturn;\t\t// no tokens\n\n// check functions\n\tfor (cmd=cmd_functions ; cmd ; cmd=cmd->next)\n\t{\n\t\tif (!strcasecmp (cmd_argv[0],cmd->name))\n\t\t{\n\t\t\tcmd->function ();\n\t\t\treturn;\n\t\t}\n\t}\n\n// check alias\n\tfor (a=cmd_alias ; a ; a=a->next)\n\t{\n\t\tif (!strcasecmp (cmd_argv[0], a->name))\n\t\t{\n\t\t\tCbuf_InsertText (a->value);\n\t\t\treturn;\n\t\t}\n\t}\n\n// check cvars\n\tif (!Cvar_Command ())\n\t\tCon_Printf (\"Unknown command \\\"%s\\\"\\n\", Cmd_Argv(0));\n\n}\n\n\n/*\n===================\nCmd_ForwardToServer\n\nSends the entire command line over to the server\n===================\n*/\nvoid Cmd_ForwardToServer (void)\n{\n\tif (cls.state != ca_connected)\n\t{\n\t\tCon_Printf (\"You have to be connected to be able to use %s.\\n\", Cmd_Argv(0));\n\t\treturn;\n\t}\n\n\tif (cls.demoplayback)\n\t\treturn;\t\t// not really connected\n\n\tMSG_WriteByte (&cls.message, clc_stringcmd);\n\tif (strcasecmp(Cmd_Argv(0), \"cmd\") != 0)\n\t{\n\t\tSZ_Print (&cls.message, Cmd_Argv(0));\n\t\tSZ_Print (&cls.message, \" \");\n\t}\n\t\n\tSZ_Print (&cls.message, Cmd_Argc() > 1 ? Cmd_Args() : \"\\n\");\n}\n\n\n/*\n================\nCmd_CheckParm\n\nReturns the position (1 to argc-1) in the command's argument list\nwhere the given parameter apears, or 0 if not present\n================\n*/\n\nint Cmd_CheckParm (char *parm)\n{\n\tint i;\n\n\tif (!parm)\n\t\tSys_Error (\"Cmd_CheckParm: NULL\");\n\n\tfor (i = 1; i < Cmd_Argc (); i++)\n\t\tif (! strcasecmp (parm, Cmd_Argv (i)))\n\t\t\treturn i;\n\n\treturn 0;\n}\n"
  },
  {
    "path": "source/cmd.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// cmd.h -- Command buffer and command execution\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 remote\nservers can also send across commands and entire text files can be execed.\n\nThe + command line options are also added to the command buffer.\n\nThe game starts with a Cbuf_AddText (\"exec quake.rc\\n\"); Cbuf_Execute ();\n\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// as new commands are generated from the console or keybindings,\n// the text is added to the end of the command buffer.\n\nvoid Cbuf_InsertText (char *text);\n// when a command wants to issue other commands immediately, the text is\n// inserted at the beginning of the buffer, before any remaining unexecuted\n// commands.\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!\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\nCommands can come from three sources, but the handler functions may choose\nto dissallow the action or forward it to a remote server if the source is\nnot apropriate.\n\n*/\n\ntypedef void (*xcommand_t) (void);\n\ntypedef enum\n{\n\tsrc_client,\t\t// came in over a net connection as a clc_stringcmd\n\t\t\t\t\t// host_client will be valid during this state.\n\tsrc_command\t\t// from the command buffer\n} cmd_source_t;\n\nextern\tcmd_source_t\tcmd_source;\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\nbool Cmd_Exists (const char *cmd_name);\n// used by the cvar code to check for cvar / command name overlap\n\nchar \t*Cmd_CompleteCommand (char *partial);\n// attempts to match a partial command for automatic command line completion\n// returns NULL if nothing fits\n\nint\t\tCmd_Argc (void);\nchar\t*Cmd_Argv (int arg);\nchar\t*Cmd_Args (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 always safe.\n\nint Cmd_CheckParm (char *parm);\n// Returns the position (1 to argc-1) in the command's argument list\n// where the given parameter apears, or 0 if not present\n\nvoid Cmd_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 (char *text, cmd_source_t src);\n// Parses a single line of text into arguments and tries to execute it.\n// The text can come from the command buffer, a remote client, or stdin.\n\nvoid\tCmd_ForwardToServer (void);\n// adds the current command line as a clc_stringcmd 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\tCmd_Print (char *text);\n// used by command functions to send output to either the graphics console or\n// passed as a print message to the client\n\n"
  },
  {
    "path": "source/common.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// common.c -- misc functions used in client and server\n#define _GNU_SOURCE\n#include <string.h>\n#include \"quakedef.h\"\n#include <assert.h>\n#include <ctype.h>\n#include <vitasdk.h>\n\nCVAR (registered, 0, CVAR_ROM)\nCVAR (platform, 0, CVAR_ROM)\nCVAR (cmdline, 0, CVAR_SERVERINFO)\n\n\n#define NUM_SAFE_ARGVS  7\n\nstatic char     *largv[MAX_NUM_ARGVS + NUM_SAFE_ARGVS + 1];\nstatic char     *argvdummy = \" \";\n\nstatic char     *safeargvs[NUM_SAFE_ARGVS] =\n\t{\"-stdvid\", \"-nolan\", \"-nosound\", \"-nocdaudio\", \"-nojoy\", \"-nomouse\", \"-dibonly\"};\n\n\nbool        com_modified;   // set true if using non-id files\n\nbool\t\tproghack;\n\nint com_nummissionpacks; //johnfitz\n\nint             static_registered = 1;  // only for startup check, then set\n\nbool\t\tmsg_suppress_1 = 0;\n\nvoid COM_InitFilesystem (void);\n\n// if a packfile directory differs from this, it is assumed to be hacked\n#define PAK0_COUNT              339\n#define PAK0_CRC                32981\n\nchar\tcom_token[1024];\nint\t\tcom_argc;\nchar\t**com_argv;\n\n#define CMDLINE_LENGTH\t256\nchar\tcom_cmdline[CMDLINE_LENGTH];\n\nbool\t\tstandard_quake = true, rogue, hipnotic;\n\n// this graphic needs to be in the pak file to use registered features\nunsigned short pop[] =\n{\n 0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000\n,0x0000,0x0000,0x6600,0x0000,0x0000,0x0000,0x6600,0x0000\n,0x0000,0x0066,0x0000,0x0000,0x0000,0x0000,0x0067,0x0000\n,0x0000,0x6665,0x0000,0x0000,0x0000,0x0000,0x0065,0x6600\n,0x0063,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6563\n,0x0064,0x6561,0x0000,0x0000,0x0000,0x0000,0x0061,0x6564\n,0x0064,0x6564,0x0000,0x6469,0x6969,0x6400,0x0064,0x6564\n,0x0063,0x6568,0x6200,0x0064,0x6864,0x0000,0x6268,0x6563\n,0x0000,0x6567,0x6963,0x0064,0x6764,0x0063,0x6967,0x6500\n,0x0000,0x6266,0x6769,0x6a68,0x6768,0x6a69,0x6766,0x6200\n,0x0000,0x0062,0x6566,0x6666,0x6666,0x6666,0x6562,0x0000\n,0x0000,0x0000,0x0062,0x6364,0x6664,0x6362,0x0000,0x0000\n,0x0000,0x0000,0x0000,0x0062,0x6662,0x0000,0x0000,0x0000\n,0x0000,0x0000,0x0000,0x0061,0x6661,0x0000,0x0000,0x0000\n,0x0000,0x0000,0x0000,0x0000,0x6500,0x0000,0x0000,0x0000\n,0x0000,0x0000,0x0000,0x0000,0x6400,0x0000,0x0000,0x0000\n};\n\n/*\n\n\nAll of Quake's data access is through a hierchal file system, but the contents of the file system can be transparently merged from several sources.\n\nThe \"base directory\" is the path to the directory holding the quake.exe and all game directories.  The sys_* files pass this to host_init in quakeparms_t->basedir.  This can be overridden with the \"-basedir\" command line parm to allow code debugging in a different directory.  The base directory is\nonly used during filesystem initialization.\n\nThe \"game directory\" is the first tree on the search path and directory that all generated files (savegames, screenshots, demos, config files) will be saved to.  This can be overridden with the \"-game\" command line parameter.  The game directory can never be changed while quake is executing.  This is a precacution against having a malicious server instruct clients to write files over areas they shouldn't.\n\nThe \"cache directory\" is only used during development to save network bandwidth, especially over ISDN / T1 lines.  If there is a cache directory\nspecified, when a file is found by the normal search path, it will be mirrored\ninto the cache directory, then opened there.\n\n\n\nFIXME:\nThe file \"parms.txt\" will be read out of the game directory and appended to the current command line arguments to allow different games to initialize startup parms differently.  This could be used to add a \"-sspeed 22050\" for the high quality sound edition.  Because they are added at the end, they will not override an explicit setting on the original command line.\n\n*/\n\n//============================================================================\n\n\n// ClearLink is used for new headnodes\nvoid ClearLink (link_t *l)\n{\n\tl->prev = l->next = l;\n}\n\nvoid RemoveLink (link_t *l)\n{\n\tl->next->prev = l->prev;\n\tl->prev->next = l->next;\n}\n\nvoid InsertLinkBefore (link_t *l, link_t *before)\n{\n\tl->next = before;\n\tl->prev = before->prev;\n\tl->prev->next = l;\n\tl->next->prev = l;\n}\nvoid InsertLinkAfter (link_t *l, link_t *after)\n{\n\tl->next = after->next;\n\tl->prev = after;\n\tl->prev->next = l;\n\tl->next->prev = l;\n}\n\n/*\n============================================================================\n\n\t\t\t\t\tLIBRARY REPLACEMENT FUNCTIONS\n\n============================================================================\n*/\n\nvoid strncpyz (char *dest, const char *src, size_t size)\n{\n   strncpy (dest, src, size - 1);\n   dest[size-1] = 0;\n}\n\n/*\n============================================================================\n\n\t\t\t\t\tBYTE ORDER FUNCTIONS\n\n============================================================================\n*/\n\nbool        bigendien;\n\nshort   (*BigShort) (short l);\nshort   (*LittleShort) (short l);\nint     (*BigLong) (int l);\nint     (*LittleLong) (int l);\nfloat   (*BigFloat) (float l);\nfloat   (*LittleFloat) (float l);\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   ShortNoSwap(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     LongNoSwap(int l)\n{\n\treturn l;\n}\n\nfloat FloatSwap(float f)\n{\n\tunion\n\t{\n\t\tfloat   f;\n\t\tbyte    b[4];\n\t} dat1, dat2;\n\n\n\tdat1.f = f;\n\tdat2.b[0] = dat1.b[3];\n\tdat2.b[1] = dat1.b[2];\n\tdat2.b[2] = dat1.b[1];\n\tdat2.b[3] = dat1.b[0];\n\treturn dat2.f;\n}\n\nfloat FloatNoSwap(float f)\n{\n\treturn f;\n}\n/*\n==============================================================================\n\n\t\t\tMESSAGE IO FUNCTIONS\n\nHandles byte ordering and avoids alignment errors\n==============================================================================\n*/\n\n//\n// writing functions\n//\n\nvoid MSG_WriteChar (sizebuf_t *sb, int c)\n{\n\tbyte    *buf;\n\n#ifdef PARANOID\n\tif (c < -128 || c > 127)\n\t\tSys_Error (\"MSG_WriteChar: range error\");\n#endif\n\n\tbuf = SZ_GetSpace (sb, 1);\n\tbuf[0] = c;\n}\n\nvoid MSG_WriteByte (sizebuf_t *sb, int c)\n{\n\tbyte    *buf;\n\n#ifdef PARANOID\n\tif (c < 0 || c > 255)\n\t\tSys_Error (\"MSG_WriteByte: range error\");\n#endif\n\n\tbuf = SZ_GetSpace (sb, 1);\n\tbuf[0] = c;\n}\n\nvoid MSG_WriteShort (sizebuf_t *sb, int c)\n{\n\tbyte    *buf;\n\n#ifdef PARANOID\n\tif (c < ((short)0x8000) || c > (short)0x7fff)\n\t\tSys_Error (\"MSG_WriteShort: range error\");\n#endif\n\n\tbuf = SZ_GetSpace (sb, 2);\n\tbuf[0] = c&0xff;\n\tbuf[1] = c>>8;\n}\n\nvoid MSG_WriteLong (sizebuf_t *sb, int c)\n{\n\tbyte    *buf;\n\n\tbuf = SZ_GetSpace (sb, 4);\n\tbuf[0] = c&0xff;\n\tbuf[1] = (c>>8)&0xff;\n\tbuf[2] = (c>>16)&0xff;\n\tbuf[3] = c>>24;\n}\n\nvoid MSG_WriteFloat (sizebuf_t *sb, float f)\n{\n\tunion\n\t{\n\t\tfloat   f;\n\t\tint     l;\n\t} dat;\n\n\n\tdat.f = f;\n\tdat.l = LittleLong (dat.l);\n\n\tSZ_Write (sb, &dat.l, 4);\n}\n\nvoid MSG_WriteString (sizebuf_t *sb, const char *s)\n{\n\tif (!s)\n\t\tSZ_Write (sb, \"\", 1);\n\telse\n\t\tSZ_Write (sb, s, strlen(s)+1);\n}\n\nvoid MSG_WriteCoord (sizebuf_t *sb, float f)\n{\n\tMSG_WriteShort (sb, (int)(f*8));\n}\n\nvoid MSG_WriteAngle (sizebuf_t *sb, float f)\n{\n\tMSG_WriteByte (sb, ((int)f*256/360) & 255);\n}\n\n// JPG - precise aim for ProQuake!\nvoid MSG_WritePreciseAngle(sizebuf_t *sb, float f)\n{\n\n\tint val = (int) f * 65536 / 360;\n\tMSG_WriteShort(sb, val & 65535);\n\n}\n\n//\n// reading functions\n//\nint                     msg_readcount;\nbool        msg_badread;\n\nvoid MSG_BeginReading (void)\n{\n\tmsg_readcount = 0;\n\tmsg_badread = false;\n}\n\n// returns -1 and sets msg_badread if no more characters are available\nint MSG_ReadChar (void)\n{\n\tint     c;\n\n\tif (msg_readcount+1 > net_message.cursize)\n\t{\n\t\tmsg_badread = true;\n\t\treturn -1;\n\t}\n\n\tc = (signed char)net_message.data[msg_readcount];\n\tmsg_readcount++;\n\n\treturn c;\n}\n\nint MSG_ReadByte (void)\n{\n\tint     c;\n\n\tif (msg_readcount+1 > net_message.cursize)\n\t{\n\t\tmsg_badread = true;\n\t\treturn -1;\n\t}\n\n\tc = (unsigned char)net_message.data[msg_readcount];\n\tmsg_readcount++;\n\n\treturn c;\n}\n\nint MSG_ReadShort (void)\n{\n\tint     c;\n\n\tif (msg_readcount+2 > net_message.cursize)\n\t{\n\t\tmsg_badread = true;\n\t\treturn -1;\n\t}\n\n\tc = (short)(net_message.data[msg_readcount]\n\t+ (net_message.data[msg_readcount+1]<<8));\n\n\tmsg_readcount += 2;\n\n\treturn c;\n}\n\nint MSG_ReadLong (void)\n{\n\tint     c;\n\n\tif (msg_readcount+4 > net_message.cursize)\n\t{\n\t\tmsg_badread = true;\n\t\treturn -1;\n\t}\n\n\tc = net_message.data[msg_readcount]\n\t+ (net_message.data[msg_readcount+1]<<8)\n\t+ (net_message.data[msg_readcount+2]<<16)\n\t+ (net_message.data[msg_readcount+3]<<24);\n\n\tmsg_readcount += 4;\n\n\treturn c;\n}\n\nfloat MSG_ReadFloat (void)\n{\n\tunion\n\t{\n\t\tbyte    b[4];\n\t\tfloat   f;\n\t\tint     l;\n\t} dat;\n\n\tdat.b[0] =      net_message.data[msg_readcount];\n\tdat.b[1] =      net_message.data[msg_readcount+1];\n\tdat.b[2] =      net_message.data[msg_readcount+2];\n\tdat.b[3] =      net_message.data[msg_readcount+3];\n\tmsg_readcount += 4;\n\n\tdat.l = LittleLong (dat.l);\n\n\treturn dat.f;\n}\n\nchar *MSG_ReadString (void)\n{\n\tstatic char     string[2048];\n\tint             l,c;\n\n\tl = 0;\n\tdo\n\t{\n\t\tc = MSG_ReadChar ();\n\t\tif (c == -1 || c == 0)\n\t\t\tbreak;\n\t\tstring[l] = c;\n\t\tl++;\n\t} while (l < sizeof(string)-1);\n\n\tstring[l] = 0;\n\n\treturn string;\n}\n\nfloat MSG_ReadCoord (void)\n{\n\treturn MSG_ReadShort() * (1.0/8);\n}\n\nfloat MSG_ReadAngle (void)\n{\n\treturn MSG_ReadChar() * (360.0/256);\n}\n\n// JPG - exact aim for proquake!\nfloat MSG_ReadPreciseAngle(void)\n{\n\treturn MSG_ReadShort() * (360.0 / 65536);\n}\n\n//===========================================================================\n\nvoid SZ_Alloc (sizebuf_t *buf, int startsize)\n{\n\tif (startsize < 256)\n\t\tstartsize = 256;\n\tbuf->data = Hunk_AllocName (startsize, \"sizebuf\");\n\tbuf->maxsize = startsize;\n\tbuf->cursize = 0;\n}\n\n\nvoid SZ_Free (sizebuf_t *buf)\n{\n//      Z_Free (buf->data);\n//      buf->data = NULL;\n//      buf->maxsize = 0;\n\tbuf->cursize = 0;\n}\n\nvoid SZ_Clear (sizebuf_t *buf)\n{\n\tbuf->cursize = 0;\n}\n\nvoid *SZ_GetSpace (sizebuf_t *buf, int length)\n{\n\tvoid    *data;\n\n\tif (buf->cursize + length > buf->maxsize)\n\t{\n\t\tif (!buf->allowoverflow)\n\t\t\tSys_Error(\"%s: overflow without allowoverflow set (%d > %d)\", __func__, buf->cursize + length, buf->maxsize);\n\n\t\tif (length > buf->maxsize)\n\t\t\tSys_Error(\"%s: %d is > full buffer size\", __func__, length);\n\n\t\tbuf->overflowed = true;\n\t\tCon_Printf (\"SZ_GetSpace: overflow\");\n\t\tSZ_Clear (buf);\n\t}\n\n\tdata = buf->data + buf->cursize;\n\tbuf->cursize += length;\n\n\treturn data;\n}\n\nvoid SZ_Write (sizebuf_t *buf, const void *data, int length)\n{\n\tmemcpy (SZ_GetSpace(buf,length),data,length);\n}\n\nvoid SZ_Print (sizebuf_t *buf, char *data)\n{\n\tint             len;\n\n\tlen = strlen(data)+1;\n\n// byte * cast to keep VC++ happy\n\tif (buf->data[buf->cursize-1])\n\t\tmemcpy ((byte *)SZ_GetSpace(buf, len),data,len); // no trailing 0\n\telse\n\t\tmemcpy ((byte *)SZ_GetSpace(buf, len-1)-1,data,len); // write over trailing 0\n}\n\n\n//============================================================================\n\n\n/*\n============\nCOM_SkipPath\n============\n*/\nchar *COM_SkipPath (char *pathname)\n{\n\tchar    *last;\n\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(char *in, char *out)\n{\n\tchar\t*dot;\n\n\tif (!(dot = strrchr(in, '.')))\n\t{\n\t\tstrlcpy(out, in, strlen(in) + 1);\n\t\treturn;\n\t}\n\n\twhile (*in && in != dot)\n\t\t*out++ = *in++;\n\n\t*out = 0;\n}\n\n/*\n============\nCOM_FileExtension - Baker 3.76 - Stronger version from ezQuake 1.8\n============\n*/\nchar *COM_FileExtension(char *in)\n{\n\tstatic char exten[8];\n\tint             i;\n\n\tif (!(in = strrchr(in, '.')))\n\t\treturn \"\";\n\tin++;\n\tfor (i = 0; i<7 && *in; i++, in++)\n\t\texten[i] = *in;\n\texten[i] = 0;\n\treturn exten;\n}\n\n/*\n============\nCOM_FileBase\n============\n*/\nvoid COM_FileBase (const char *in, char *out)\n{\n\tchar *s, *s2;\n\n\ts = (char*)in + strlen(in) - 1;\n\n\twhile (s != in && *s != '.')\n\t\ts--;\n\n\tfor (s2 = s ; *s2 && *s2 != '/' ; s2--)\n\t;\n\n\tif (s-s2 < 2)\n\t\tstrcpy (out,\"?model?\");\n\telse\n\t{\n\t\ts--;\n\t\tstrncpy (out,s2+1, s-s2);\n\t\tout[s-s2] = 0;\n\t}\n}\n\n/*\n==================\nCOM_ForceExtension\nIf path doesn't have an extension or has a different extension, append(!) specified extension\nExtension should include the .\n==================\n*/\nvoid COM_ForceExtension(char *path, char *extension)\n{\n\tchar *src;\n\n\tsrc = path + strlen(path) - 1;\n\n\twhile (*src != '/' && src != path)\n\t{\n\t\tif (*src-- == '.')\n\t\t{\n\t\t\tCOM_StripExtension(path, path);\n\t\t\tstrlcat(path, extension, sizeof(path));\n\t\t\treturn;\n\t\t}\n\t}\n\n\tstrlcat(path, extension, MAX_OSPATH);\n}\n\n/*\n==================\nCOM_DefaultExtension\n==================\n*/\nvoid COM_DefaultExtension (char *path, char *extension)\n{\n\tchar    *src;\n//\n// if path doesn't have a .EXT, append extension\n// (extension should include the .)\n//\n\tsrc = path + strlen(path) - 1;\n\n\twhile (*src != '/' && src != path)\n\t{\n\t\tif (*src == '.')\n\t\t\treturn;                 // it has an extension\n\t\tsrc--;\n\t}\n\n\tstrcat (path, extension);\n}\n\n\n/*\n==============\nCOM_Parse\n\nParse a token out of a string\n==============\n*/\nchar *COM_Parse (const char *data)\n{\n\tint             c;\n\tint             len;\n\n\tlen = 0;\n\tcom_token[0] = 0;\n\n\tif (!data)\n\t\treturn NULL;\n\n// skip whitespace\nskipwhite:\n\twhile ( (c = *data) <= ' ')\n\t{\n\t\tif (c == 0)\n\t\t\treturn NULL;                    // end of file;\n\t\tdata++;\n\t}\n\n// skip // comments\n\tif (c=='/' && data[1] == '/')\n\t{\n\t\twhile (*data && *data != '\\n')\n\t\t\tdata++;\n\t\tgoto skipwhite;\n\t}\n\n\n// handle quoted strings specially\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\treturn (char*)data;\n\t\t\t}\n\t\t\tcom_token[len] = c;\n\t\t\tlen++;\n\t\t}\n\t}\n\n// parse single characters\n\tif (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\\'' || c==':')\n\t{\n\t\tcom_token[len] = c;\n\t\tlen++;\n\t\tcom_token[len] = 0;\n\t\treturn (char*)data+1;\n\t}\n\n// parse a regular word\n\tdo\n\t{\n\t\tcom_token[len] = c;\n\t\tdata++;\n\t\tlen++;\n\t\tc = *data;\n\n\tif (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\\'')\n\t\t\tbreak;\n\t} while (c>32);\n\n\tcom_token[len] = 0;\n\treturn (char*)data;\n}\n\n\n/*\n================\nCOM_CheckParm\n\nReturns the position (1 to argc-1) in the program's argument list\nwhere the given parameter apears, or 0 if not present\n================\n*/\nint COM_CheckParm (const char *parm)\n{\n\tint             i;\n\n\tfor (i=1 ; i<com_argc ; i++)\n\t{\n\t\tif (!com_argv[i])\n\t\t\tcontinue;               // NEXTSTEP sometimes clears appkit vars.\n\t\tif (!strcmp (parm,com_argv[i]))\n\t\t\treturn i;\n\t}\n\n\treturn 0;\n}\n\n/*\n================\nCOM_CheckRegistered\n\nLooks for the pop.txt file and verifies it.\nSets the \"registered\" cvar.\nImmediately exits out if an alternate game was attempted to be started without\nbeing registered.\n================\n*/\nvoid COM_CheckRegistered (void)\n{\n\tint             h;\n\tunsigned short  check[128];\n\tint                     i;\n\n\tCOM_OpenFile(\"gfx/pop.lmp\", &h, NULL);\n\tstatic_registered = 0;\n\n\tif (h == -1)\n\t{\n\t\tCon_Printf (\"Playing shareware version.\\n\");\n\t\tif (com_modified)\n\t\t\tCon_Printf (\"Warning: Modified game with shareware version detected.\\n\");\n\t\treturn;\n\t}\n\n\tSys_FileRead (h, check, sizeof(check));\n\tCOM_CloseFile (h);\n\n\tfor (i=0 ; i<128 ; i++)\n\t\tif (pop[i] != (unsigned short)BigShort (check[i]))\n\t\t\tSys_Error (\"Corrupted data file.\");\n\n\tCvar_Set (\"cmdline\", com_cmdline);\n\tCvar_ForceSet (\"registered\", \"1\");\n\tstatic_registered = 1;\n\tCon_Printf (\"Playing registered version.\\n\");\n}\n\n\nvoid COM_Path_f (void);\n\n\n/*\n================\nCOM_InitArgv\n================\n*/\nvoid COM_InitArgv (int argc, char **argv)\n{\n\tbool        safe;\n\tint             i, j, n;\n\n// reconstitute the command line for the cmdline externally visible cvar\n\tn = 0;\n\n\tfor (j=0 ; (j<MAX_NUM_ARGVS) && (j< argc) ; j++)\n\t{\n\t\ti = 0;\n\n\t\twhile ((n < (CMDLINE_LENGTH - 1)) && argv[j][i])\n\t\t{\n\t\t\tcom_cmdline[n++] = argv[j][i++];\n\t\t}\n\n\t\tif (n < (CMDLINE_LENGTH - 1))\n\t\t\tcom_cmdline[n++] = ' ';\n\t\telse\n\t\t\tbreak;\n\t}\n\n\tcom_cmdline[n] = 0;\n\n\tsafe = false;\n\n\tfor (com_argc=0 ; (com_argc<MAX_NUM_ARGVS) && (com_argc < argc) ;\n\t\t com_argc++)\n\t{\n\t\tlargv[com_argc] = argv[com_argc];\n\t\tif (!strcmp (\"-safe\", argv[com_argc]))\n\t\t\tsafe = true;\n\t}\n\n\tif (safe)\n\t{\n\t// force all the safe-mode switches. Note that we reserved extra space in\n\t// case we need to add these, so we don't need an overflow check\n\t\tfor (i=0 ; i<NUM_SAFE_ARGVS ; i++)\n\t\t{\n\t\t\tlargv[com_argc] = safeargvs[i];\n\t\t\tcom_argc++;\n\t\t}\n\t}\n\n\tlargv[com_argc] = argvdummy;\n\tcom_argv = largv;\n\n\tif (COM_CheckParm (\"-rogue\"))\n\t{\n\t\trogue = true;\n\t\tstandard_quake = false;\n\t}\n\n\tif (COM_CheckParm (\"-hipnotic\"))\n\t{\n\t\thipnotic = true;\n\t\tstandard_quake = false;\n\t}\n}\n\n\n/*\n================\nCOM_Init\n================\n*/\nvoid COM_Init (char *basedir)\n{\n\t//byte    swaptest[2] = {1,0};\n\n/*\n=====================================\nSINCE VITAQUAKE IS LITTLE ENDIAN...\n=====================================\n*/\n\n// set the byte swapping variables in a portable manner\n/*\tif ( *(short *)swaptest == 1)\n\t{*/\n\t\t//bigendien = false;\n\t\tBigShort\t= ShortSwap;\n\t\tBigLong\t\t= LongSwap;\n\t\tBigFloat\t= FloatSwap;\n\t\tLittleShort = ShortNoSwap;\n\t\tLittleLong\t= LongNoSwap;\n\t\tLittleFloat = FloatNoSwap;\n/*\t}\n\telse\n\t{\n\t\tbigendien = true;\n\t\tBigShort = ShortNoSwap;\n\t\tLittleShort = ShortSwap;\n\t\tBigLong = LongNoSwap;\n\t\tLittleLong = LongSwap;\n\t\tBigFloat = FloatNoSwap;\n\t\tLittleFloat = FloatSwap;\n\t}*/\n\n\tCvar_RegisterVariable (&registered);\n\tCvar_RegisterVariable (&cmdline);\n\tCvar_RegisterVariable (&platform);\n\tCmd_AddCommand (\"path\", COM_Path_f);\n\tCOM_InitFilesystem ();\n\tCOM_CheckRegistered ();\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    *va(char *format, ...)\n{\n\tva_list         argptr;\n\tstatic char             string[1024];\n\n\tva_start (argptr, format);\n\tvsprintf (string, format,argptr);\n\tva_end (argptr);\n\n\treturn string;\n}\n\n\n/// just for debugging\nint     memsearch (byte *start, int count, int search)\n{\n\tint             i;\n\n\tfor (i=0 ; i<count ; i++)\n\t\tif (start[i] == search)\n\t\t\treturn i;\n\treturn -1;\n}\n\n/*\n=============================================================================\n\nQUAKE FILESYSTEM\n\n=============================================================================\n*/\n\nint     com_filesize;\n\n//\n// on disk\n//\ntypedef struct\n{\n\tchar    name[56];\n\tint             filepos, filelen;\n} dpackfile_t;\n\ntypedef struct\n{\n\tchar    id[4];\n\tint             dirofs;\n\tint             dirlen;\n} dpackheader_t;\n\n#define MAX_FILES_IN_PACK       4096\n\nchar    com_cachedir[MAX_OSPATH];\nchar    com_gamedir[MAX_OSPATH];\n\nsearchpath_t    *com_searchpaths = NULL;\t// JPG 3.20 - added NULL\nsearchpath_t\t*com_verifypaths = NULL;\t// JPG 3.20 - use original game directory for verify path\n\n/*\n============\nCOM_Path_f\n\n============\n*/\nvoid COM_Path_f (void)\n{\n\tsearchpath_t    *s;\n\n\tCon_Printf (\"Current search path:\\n\");\n\tfor (s=com_searchpaths ; s ; s=s->next)\n\t{\n\t\tif (s->pack)\n\t\t{\n\t\t\tCon_Printf (\"%s (%i files)\\n\", s->pack->filename, s->pack->numfiles);\n\t\t}\n\t\telse\n\t\t\tCon_Printf (\"%s\\n\", s->filename);\n\t}\n}\n\n/*\n============\nCOM_WriteFile\n\nThe filename will be prefixed by the current game directory\n============\n*/\nvoid COM_WriteFile(char *filename, void *data, int len)\n{\n\tint             handle;\n\tchar    name[MAX_OSPATH];\n\n\tSys_mkdir(com_gamedir); //johnfitz -- if we've switched to a nonexistant gamedir, create it now so we don't crash\n\n\tsnprintf(name, sizeof(name), \"%s/%s\", com_gamedir, filename);\n\n\thandle = Sys_FileOpenWrite(name);\n\tif (handle == -1)\n\t{\n\t\tSys_Printf(\"COM_WriteFile: failed on %s\\n\", name);\n\t\treturn;\n\t}\n\n\tSys_Printf(\"COM_WriteFile: %s\\n\", name);\n\tSys_FileWrite(handle, data, len);\n\tSys_FileClose(handle);\n}\n\n\n/*\n============\nCOM_CreatePath\n\nOnly used for CopyFile\n============\n*/\nvoid    COM_CreatePath (char *path)\n{\n\tchar    *ofs;\n\n\n\tfor (ofs = path+1 ; *ofs ; ofs++)\n\t{\n\t\tif (*ofs == '/')\n\t\t{       // create the directory\n\t\t\t*ofs = 0;\n\t\t\tSys_mkdir (path);\n\t\t\t*ofs = '/';\n\t\t}\n\t}\n}\n\n\n/*\n===========\nCOM_CopyFile\n\nCopies a file over from the net to the local cache, creating any directories\nneeded.  This is for the convenience of developers using ISDN from home.\n===========\n*/\nvoid COM_CopyFile (char *netpath, char *cachepath)\n{\n\tint             in, out;\n\tint             remaining, count;\n\tchar*\t\t\tbuf = Sys_BigStackAlloc(4096, \"COM_CopyFile\");\n\n\tremaining = Sys_FileOpenRead (netpath, &in);\n\tCOM_CreatePath (cachepath);     // create directories up to the cache file\n\tout = Sys_FileOpenWrite (cachepath);\n\n\twhile (remaining)\n\t{\n\t\tif (remaining < sizeof(buf))\n\t\t\tcount = remaining;\n\t\telse\n\t\t\tcount = sizeof(buf);\n\t\tSys_FileRead (in, buf, count);\n\t\tSys_FileWrite (out, buf, count);\n\t\tremaining -= count;\n\t}\n\n\tSys_FileClose (in);\n\tSys_FileClose (out);\n\n\tSys_BigStackFree(4096, \"COM_CopyFile\");\n}\n\n/*\n===========\nCOM_FindFile\n\nFinds the file in the search path.\nSets com_filesize and one of handle or file\n===========\n*/\nint COM_FindFile (const char *filename, int *handle, FILE **file, unsigned int *path_id)\n{\n\tsearchpath_t    *search;\n\tchar            netpath[MAX_OSPATH];\n\tchar            cachepath[MAX_OSPATH];\n\tpack_t          *pak;\n\tint                     i;\n\tint                     findtime, cachetime;\n\n\tif (file && handle)\n\t\tSys_Error (\"COM_FindFile: both handle and file set\");\n\tif (!file && !handle)\n\t\tSys_Error (\"COM_FindFile: neither handle or file set\");\n\n//\n// search through the path, one element at a time\n//\n\tsearch = com_searchpaths;\n\tif (proghack)\n\t{\t// gross hack to use quake 1 progs with quake 2 maps\n\t\tif (!strcmp(filename, \"progs.dat\"))\n\t\t\tsearch = search->next;\n\t}\n\n\tfor ( ; search ; search = search->next)\n\t{\n\t// is the element a pak file?\n\t\tif (search->pack)\n\t\t{\n\t\t// look through all the pak file elements\n\t\t\tpak = search->pack;\n\t\t\tfor (i=0 ; i<pak->numfiles ; i++)\n\t\t\t\tif (!strcmp (pak->files[i].name, filename))\n\t\t\t\t{       // found it!\n\t\t\t\t\tSys_Printf (\"PackFile: %s : %s\\n\",pak->filename, filename);\n\t\t\t\t\tif (path_id)\n\t\t\t\t\t\t*path_id = search->path_id;\n\t\t\t\t\tif (handle)\n\t\t\t\t\t{\n\t\t\t\t\t\t*handle = pak->handle;\n\t\t\t\t\t\tSys_FileSeek (pak->handle, pak->files[i].filepos);\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t{       // open a new file on the pakfile\n\t\t\t\t\t\t*file = fopen (pak->filename, \"rb\");\n\t\t\t\t\t\tif (*file)\n\t\t\t\t\t\t\tfseek (*file, pak->files[i].filepos, SEEK_SET);\n\t\t\t\t\t}\n\t\t\t\t\tcom_filesize = pak->files[i].filelen;\n\t\t\t\t\treturn com_filesize;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t// check a file in the directory tree\n\t\t\tif (!static_registered)\n\t\t\t{       // if not a registered version, don't ever go beyond base\n\t\t\t\tif ( strchr (filename, '/') || strchr (filename,'\\\\'))\n\t\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tsnprintf(netpath, sizeof(netpath), \"%s/%s\", search->filename, filename);\n\n\t\t\tfindtime = Sys_FileTime (netpath);\n\t\t\tif (findtime == -1)\n\t\t\t\tcontinue;\n\n\t\t// see if the file needs to be updated in the cache\n\t\t\tif (!com_cachedir[0])\n\t\t\t\tstrcpy (cachepath, netpath);\n\t\t\telse\n\t\t\t{\n\t\t\t\tsprintf (cachepath,\"%s%s\", com_cachedir, netpath);\n\n\t\t\t\tcachetime = Sys_FileTime (cachepath);\n\n\t\t\t\tif (cachetime < findtime)\n\t\t\t\t\tCOM_CopyFile (netpath, cachepath);\n\t\t\t\tstrcpy (netpath, cachepath);\n\t\t\t}\n\n\t\t\tSys_Printf (\"FindFile: %s\\n\",netpath);\n\t\t\tcom_filesize = Sys_FileOpenRead (netpath, &i);\n\t\t\tif (path_id)\n\t\t\t\t*path_id = search->path_id;\n\t\t\tif (handle)\n\t\t\t\t*handle = i;\n\t\t\telse\n\t\t\t{\n\t\t\t\tSys_FileClose (i);\n\t\t\t\t*file = fopen (netpath, \"rb\");\n\t\t\t}\n\t\t\treturn com_filesize;\n\t\t}\n\n\t}\n\n\tSys_Printf (\"FindFile: can't find %s\\n\", filename);\n\n\tif (handle)\n\t\t*handle = -1;\n\telse\n\t\t*file = NULL;\n\tcom_filesize = -1;\n\treturn -1;\n}\n\n\n/*\n===========\nCOM_OpenFile\n\nfilename never has a leading slash, but may contain directory walks\nreturns a handle and a length\nit may actually be inside a pak file\n===========\n*/\nint COM_OpenFile (const char *filename, int *handle, unsigned int *path_id)\n{\n\treturn COM_FindFile (filename, handle, NULL, path_id);\n}\n\n/*\n===========\nCOM_FOpenFile\n\nIf the requested file is inside a packfile, a new FILE * will be opened\ninto the file.\n===========\n*/\nint COM_FOpenFile (char *filename, FILE **file, unsigned int *path_id)\n{\n\treturn COM_FindFile (filename, NULL, file, path_id);\n}\n\n/*\n============\nCOM_CloseFile\n\nIf it is a pak file handle, don't really close it\n============\n*/\nvoid COM_CloseFile (int h)\n{\n\tsearchpath_t    *s;\n\n\tfor (s = com_searchpaths ; s ; s=s->next)\n\t\tif (s->pack && s->pack->handle == h)\n\t\t\treturn;\n\n\tSys_FileClose (h);\n}\n\n\n/*\n============\nCOM_LoadFile\n\nFilename are reletive to the quake directory.\nAlways appends a 0 byte.\n============\n*/\n#define\tLOADFILE_ZONE\t\t0\n#define\tLOADFILE_HUNK\t\t1\n#define\tLOADFILE_TEMPHUNK\t2\n#define\tLOADFILE_STACK\t\t3\n\ncache_user_t *loadcache;\nbyte    *loadbuf;\nint             loadsize;\nbyte *COM_LoadFile (const char *path, int usehunk, unsigned int *path_id)\n{\n\tint             h;\n\tbyte    *buf;\n\tchar    base[32];\n\tint             len;\n\n\tbuf = NULL;     // quiet compiler warning\n\n// look for it in the filesystem or pack files\n\tlen = COM_OpenFile (path, &h, path_id);\n\tif (h == -1)\n\t\treturn NULL;\n\n// extract the filename base name for hunk tag\n\tCOM_FileBase (path, base);\n\t\n\tswitch (usehunk)\n\t{\n\t\tcase LOADFILE_HUNK:\n\t\t\tbuf = Hunk_AllocName (len+1, base);\n\t\t\tbreak;\n\t\tcase LOADFILE_TEMPHUNK:\n\t\t\tbuf = Hunk_TempAlloc (len+1);\n\t\t\tbreak;\n\t\tcase LOADFILE_ZONE:\n\t\t\tbuf = Z_Malloc (len+1);\n\t\t\tbreak;\n\t\tcase LOADFILE_STACK:\n\t\t\tif (len+1 > loadsize)\n\t\t\t\tbuf = Hunk_TempAlloc (len+1);\n\t\t\telse\n\t\t\t\tbuf = loadbuf;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tSys_Error (\"COM_LoadFile: bad usehunk\");\n\t\t\tbreak;\n\t}\n\n\tif (!buf)\n\t\tSys_Error (\"COM_LoadFile: not enough space for %s\", path);\n\n\t((byte *)buf)[len] = 0;\n\tSys_FileRead (h, buf, len);\n\tCOM_CloseFile (h);\n\treturn buf;\n}\n\nbyte *COM_LoadHunkFile (const char *path, unsigned int *path_id)\n{\n\treturn COM_LoadFile (path, LOADFILE_HUNK, path_id);\n}\n\nbyte *COM_LoadTempFile (const char *path, unsigned int *path_id)\n{\n\treturn COM_LoadFile (path, LOADFILE_TEMPHUNK, path_id);\n}\n\n// uses temp hunk if larger than bufsize\nbyte *COM_LoadStackFile (char *path, void *buffer, int bufsize, unsigned int *path_id)\n{\n\tbyte    *buf;\n\n\tloadbuf = (byte *)buffer;\n\tloadsize = bufsize;\n\tbuf = COM_LoadFile (path, LOADFILE_STACK, path_id);\n\n\treturn buf;\n}\n\n/*\n=================\nCOM_LoadPackFile -- johnfitz -- modified based on topaz's tutorial\n\nTakes an explicit (not game tree related) path to a pak file.\n\nLoads the header and directory, adding the files at the beginning\nof the list so they override previous pack files.\n=================\n*/\npack_t *COM_LoadPackFile(char *packfile)\n{\n\tdpackheader_t   header;\n\tint                     i;\n\tpackfile_t              *newfiles;\n\tint                     numpackfiles;\n\tpack_t                  *pack;\n\tint                     packhandle;\n\tdpackfile_t*\t\t\tinfo;\n\tunsigned short          crc;\n\n\tif (Sys_FileOpenRead(packfile, &packhandle) == -1)\n\t\treturn NULL;\n\t\n\tSys_FileRead(packhandle, (void *)&header, sizeof(header));\n\tif (header.id[0] != 'P' || header.id[1] != 'A' || header.id[2] != 'C' || header.id[3] != 'K')\n\t\tSys_Error(\"%s is not a packfile\", packfile);\n\theader.dirofs = LittleLong(header.dirofs);\n\theader.dirlen = LittleLong(header.dirlen);\n\n\tnumpackfiles = header.dirlen / sizeof(dpackfile_t);\n\n\tif (numpackfiles > MAX_FILES_IN_PACK)\n\t\tSys_Error(\"%s has %i files\", packfile, numpackfiles);\n\n\tif (numpackfiles != PAK0_COUNT)\n\t\tcom_modified = true;    // not the original file\n\n\tinfo = Sys_BigStackAlloc(MAX_FILES_IN_PACK * sizeof(dpackfile_t), \"COM_LoadPackFile\");\n\n\t//johnfitz -- dynamic gamedir loading\n\tnewfiles = Z_Malloc(numpackfiles * sizeof(packfile_t));\n\t//johnfitz\n\n\tSys_FileSeek(packhandle, header.dirofs);\n\tSys_FileRead(packhandle, (void *)info, header.dirlen);\n\n\t// crc the directory to check for modifications\n\tCRC_Init(&crc);\n\tfor (i = 0; i<header.dirlen; i++)\n\t\tCRC_ProcessByte(&crc, ((byte *)info)[i]);\n\tif (crc != PAK0_CRC)\n\t\tcom_modified = true;\n\n\t// parse the directory\n\tfor (i = 0; i<numpackfiles; i++)\n\t{\n\t\tstrcpy(newfiles[i].name, info[i].name);\n\t\tnewfiles[i].filepos = LittleLong(info[i].filepos);\n\t\tnewfiles[i].filelen = LittleLong(info[i].filelen);\n\t}\n\n\t//johnfitz -- dynamic gamedir loading\n\tpack = Z_Malloc(sizeof(pack_t));\n\t//johnfitz\n\n\tstrcpy(pack->filename, packfile);\n\tpack->handle = packhandle;\n\tpack->numfiles = numpackfiles;\n\tpack->files = newfiles;\n\n\t// FitzQuake has this commented out\n\tCon_Printf(\"Added packfile %s (%i files)\\n\", packfile, numpackfiles);\n\tinfo = Sys_BigStackAlloc(MAX_FILES_IN_PACK * sizeof(dpackfile_t), \"COM_LoadPackFile\");\n\treturn pack;\n}\n\n\n/*\n================\nCOM_AddGameDirectory -- johnfitz -- modified based on topaz's tutorial\n\nSets com_gamedir, adds the directory to the head of the path,\nthen loads and adds pak1.pak pak2.pak ...\n================\n*/\nvoid COM_AddGameDirectory(char *dir)\n{\n\tint i;\n\tsearchpath_t *search;\n\tpack_t *pak;\n\tchar pakfile[MAX_OSPATH];\n\tunsigned int path_id;\n \n\tstrcpy(com_gamedir, dir);\n\t\n\t// assign a path_id to this game directory\n\tif (com_searchpaths)\n\t\tpath_id = com_searchpaths->path_id + 1;\n\telse\n\t\tpath_id = 1;\n\n\t// add the directory to the search path\n\tsearch = Z_Malloc(sizeof(searchpath_t));\n\tsearch->path_id = path_id;\n\tstrcpy(search->filename, dir);\n\tsearch->next = com_searchpaths;\n\tcom_searchpaths = search;\n\t\n\tSceUID d = sceIoDopen(dir);\n\tif (d >= 0) {\n\t\tSceIoDirent file;\n\t\twhile (sceIoDread(d, &file) > 0) {\n\t\t\tif (strcasestr(file.d_name, \".pak\") != 0) {\n\t\t\t\tsprintf(pakfile,\"%s/%s\", dir, file.d_name);\n\t\t\t\tpak = COM_LoadPackFile (pakfile);\n\t\t\t\tif (!pak)\n\t\t\t\t\tcontinue;\n\t\t\t\tsearch = Z_Malloc (sizeof(searchpath_t));\n\t\t\t\tsearch->pack = pak;\n\t\t\t\tsearch->next = com_searchpaths;\n\t\t\t\tsearch->path_id = path_id;\n\t\t\t\tcom_searchpaths = search;\n\t\t\t}\n\t\t}\n\t\tsceIoDclose(d);\n\t}\n\n}\n\n/*\n============\nCOM_GetFolder\n============\n*/\nvoid COM_GetFolder (char *in, char *out)\n{\n\tchar *last = NULL;\n\n\twhile (*in)\n\t{\n\t\tif (*in == '/')\n\t\tlast = out;\n\t\t*out++ = *in++;\n\t}\n\tif (last)\n\t\t*last = 0;\n\telse\n\t\t*out = 0;\n}\n\n/*\n================\nCOM_InitFilesystem\n================\n*/\nvoid COM_InitFilesystem (void)\n{\n\tint             i, j;\n\tchar    basedir[MAX_OSPATH];\n\tsearchpath_t    *search;\n\n//\n// -basedir <path>\n// Overrides the system supplied base directory (under GAMENAME)\n//\n\ti = COM_CheckParm (\"-basedir\");\n\tif (i && i < com_argc-1)\n\t\tstrcpy (basedir, com_argv[i+1]);\n\telse\n\t\tstrcpy (basedir, host_parms.basedir);\n\n\tj = strlen (basedir);\n\n\tif (j > 0)\n\t{\n\t\tif ((basedir[j-1] == '\\\\') || (basedir[j-1] == '/'))\n\t\t\tbasedir[j-1] = 0;\n\t}\n\n//\n// -cachedir <path>\n// Overrides the system supplied cache directory (NULL or /qcache)\n// -cachedir - will disable caching.\n//\n\ti = COM_CheckParm (\"-cachedir\");\n\tif (i && i < com_argc-1)\n\t{\n\t\tif (com_argv[i+1][0] == '-')\n\t\t\tcom_cachedir[0] = 0;\n\t\telse\n\t\t\tstrcpy (com_cachedir, com_argv[i+1]);\n\t}\n\telse if (host_parms.cachedir)\n\t\tstrcpy (com_cachedir, host_parms.cachedir);\n\telse\n\t\tcom_cachedir[0] = 0;\n\n//\n// start up with GAMENAME by default (referenced by GAMENAME_DIR)\n//\n\tCOM_AddGameDirectory (va(\"%s/\"GAMENAME_DIR, basedir) );\n\tstrcpy (com_gamedir, va(\"%s/\"GAMENAME_DIR, basedir));\n\t\n\t//johnfitz -- track number of mission packs added\n\t//since we don't want to allow the \"game\" command to strip them away\n\tcom_nummissionpacks = 0;\n\tif (COM_CheckParm (\"-rogue\")){\n\t\tCOM_AddGameDirectory (va(\"%s/rogue\", basedir) );\n\t\tcom_nummissionpacks++;\n\t}\n\tif (COM_CheckParm (\"-hipnotic\")){\n\t\tCOM_AddGameDirectory (va(\"%s/hipnotic\", basedir) );\n\t\tcom_nummissionpacks++;\n\t}\n//\n// -game <gamedir>\n// Adds basedir/gamedir as an override game\n//\n\ti = COM_CheckParm (\"-game\");\n\tif (i && i < com_argc-1)\n\t{\n\t\tcom_modified = true;\n\t\tCOM_AddGameDirectory (va(\"%s/%s\", basedir, com_argv[i+1]));\n\t}\n\n//\n// -path <dir or packfile> [<dir or packfile>] ...\n// Fully specifies the exact serach path, overriding the generated one\n//\n\ti = COM_CheckParm (\"-path\");\n\tif (i)\n\t{\n\t\tcom_modified = true;\n\t\tcom_searchpaths = NULL;\n\t\twhile (++i < com_argc)\n\t\t{\n\t\t\tif (!com_argv[i] || com_argv[i][0] == '+' || com_argv[i][0] == '-')\n\t\t\t\tbreak;\n\n\t\t\tsearch = Hunk_Alloc (sizeof(searchpath_t));\n\t\t\tif ( !strcmp(COM_FileExtension(com_argv[i]), \"pak\") )\n\t\t\t{\n\t\t\t\tsearch->pack = COM_LoadPackFile (com_argv[i]);\n\t\t\t\tif (!search->pack)\n\t\t\t\t\tSys_Error (\"Couldn't load packfile: %s\", com_argv[i]);\n\t\t\t}\n\t\t\telse\n\t\t\t\tstrcpy (search->filename, com_argv[i]);\n\t\t\tsearch->next = com_searchpaths;\n\t\t\tcom_searchpaths = search;\n\t\t}\n\t}\n\n\tif (COM_CheckParm (\"-proghack\"))\n\t\tproghack = true;\n}\n\nfloat COM_Clamp(float value, float min, float max)\n{\n\treturn value < min ? min : (value > max ? max : value);\n}\n\n//========================================================\n// strlcat and strlcpy, from OpenBSD\n\n/*\n* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>\n*\n* Permission to use, copy, modify, and distribute this software for any\n* purpose with or without fee is hereby granted, provided that the above\n* copyright notice and this permission notice appear in all copies.\n*\n* THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n*/\n\n/*\t$OpenBSD: strlcat.c,v 1.11 2003/06/17 21:56:24 millert Exp $\t*/\n/*\t$OpenBSD: strlcpy.c,v 1.8 2003/06/17 21:56:24 millert Exp $\t*/\n\n\n#ifndef HAVE_STRLCAT\nsize_t strlcat(char *dst, const char *src, size_t siz)\n{\n\tregister char *d = dst;\n\tregister const char *s = src;\n\tregister size_t n = siz;\n\tsize_t dlen;\n\n\t/* Find the end of dst and adjust bytes left but don't go past end */\n\twhile (n-- != 0 && *d != '\\0')\n\t\td++;\n\tdlen = d - dst;\n\tn = siz - dlen;\n\n\tif (n == 0)\n\t\treturn(dlen + strlen(s));\n\twhile (*s != '\\0') {\n\t\tif (n != 1) {\n\t\t\t*d++ = *s;\n\t\t\tn--;\n\t\t}\n\t\ts++;\n\t}\n\t*d = '\\0';\n\n\treturn(dlen + (s - src));\t/* count does not include NUL */\n}\n#endif  // #ifndef HAVE_STRLCAT\n\n// Baker: strip leading spaces from string\nchar *strltrim(char *s) {\n\tchar *t;\n\n\tassert(s != NULL);\n\tfor (t = s; isspace(*t); ++t)\n\t\tcontinue;\n\tmemmove(s, t, strlen(t) + 1);\t/* +1 so that '\\0' is moved too */\n\treturn s;\n}\n\n// Lower string\nchar* strtolower(char* s) {\n\tassert(s != NULL);\n\n\tchar* p = s;\n\twhile (*p != '\\0') {\n\t\t*p = tolower(*p);\n\t\tp++;\n\t}\n\n\treturn s;\n}"
  },
  {
    "path": "source/common.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// comndef.h  -- general definitions\n\n#include <stdbool.h>\n\n#if !defined BYTE_DEFINED\ntypedef unsigned char \t\tbyte;\n#define BYTE_DEFINED 1\n#endif\n\n#ifndef min\n#define min(a, b) ((a) < (b) ? (a) : (b))\n#endif\n#ifndef max\n#define max(a, b) ((a) > (b) ? (a) : (b))\n#endif\n\n#define stringify__(x) #x\n#define stringify(x) stringify__(x)\n\ntypedef struct\n{\n\tchar    name[MAX_QPATH];\n\tint             filepos, filelen;\n} packfile_t;\n\ntypedef struct pack_s\n{\n\tchar    filename[MAX_OSPATH];\n\tint             handle;\n\tint             numfiles;\n\tpackfile_t      *files;\n} pack_t;\n\ntypedef struct searchpath_s\n{\n\tunsigned int path_id;\n\tchar    filename[MAX_OSPATH];\n\tpack_t  *pack;          // only one of filename / pack will be used\n\tstruct searchpath_s *next;\n} searchpath_t;\n\n//============================================================================\n\ntypedef struct sizebuf_s\n{\n\tbool\tallowoverflow;\t// if false, do a Sys_Error\n\tbool\toverflowed;\t\t// set to true if the buffer size failed\n\tbyte\t*data;\n\tint\t\tmaxsize;\n\tint\t\tcursize;\n} sizebuf_t;\n\nvoid SZ_Alloc (sizebuf_t *buf, int startsize);\nvoid SZ_Free (sizebuf_t *buf);\nvoid SZ_Clear (sizebuf_t *buf);\nvoid *SZ_GetSpace (sizebuf_t *buf, int length);\nvoid SZ_Write (sizebuf_t *buf, const void *data, int length);\nvoid SZ_Print (sizebuf_t *buf, char *data);\t// strcats onto the sizebuf\n\n//============================================================================\n\ntypedef struct link_s\n{\n\tstruct link_s\t*prev, *next;\n} link_t;\n\n\nvoid ClearLink (link_t *l);\nvoid RemoveLink (link_t *l);\nvoid InsertLinkBefore (link_t *l, link_t *before);\nvoid InsertLinkAfter (link_t *l, link_t *after);\n\n// (type *)STRUCT_FROM_LINK(link_t *link, type, member)\n// ent = STRUCT_FROM_LINK(link,entity_t,order)\n// FIXME: remove this mess!\n#define\tSTRUCT_FROM_LINK(l,t,m) ((t *)((byte *)l - (int)&(((t *)0)->m)))\n\n//============================================================================\n\n#ifndef NULL\n#define NULL ((void *)0)\n#endif\n\n#define Q_MAXCHAR ((char)0x7f)\n#define Q_MAXSHORT ((short)0x7fff)\n#define Q_MAXINT\t((int)0x7fffffff)\n#define Q_MAXLONG ((int)0x7fffffff)\n#define Q_MAXFLOAT ((int)0x7fffffff)\n\n#define Q_MINCHAR ((char)0x80)\n#define Q_MINSHORT ((short)0x8000)\n#define Q_MININT \t((int)0x80000000)\n#define Q_MINLONG ((int)0x80000000)\n#define Q_MINFLOAT ((int)0x7fffffff)\n\n#define\tQ_CLAMP(_minval, x, _maxval)\t\\\n\t((x) < (_minval) ? (_minval) :\t\t\\\n\t(x) > (_maxval) ? (_maxval) : (x))\n\n//============================================================================\n\nextern\tbool\t\tbigendien;\n\nextern\tshort\t(*BigShort) (short l);\nextern\tshort\t(*LittleShort) (short l);\nextern\tint\t(*BigLong) (int l);\nextern\tint\t(*LittleLong) (int l);\nextern\tfloat\t(*BigFloat) (float l);\nextern\tfloat\t(*LittleFloat) (float l);\n\n//============================================================================\n\nvoid MSG_WriteChar (sizebuf_t *sb, int c);\nvoid MSG_WriteByte (sizebuf_t *sb, int c);\nvoid MSG_WriteShort (sizebuf_t *sb, int c);\nvoid MSG_WriteLong (sizebuf_t *sb, int c);\nvoid MSG_WriteFloat (sizebuf_t *sb, float f);\nvoid MSG_WriteString (sizebuf_t *sb, const char *s);\nvoid MSG_WriteCoord (sizebuf_t *sb, float f);\nvoid MSG_WriteAngle (sizebuf_t *sb, float f);\nvoid MSG_WritePreciseAngle(sizebuf_t *sb, float f); // JPG - precise aim!!\n\nextern\tint\t\t\tmsg_readcount;\nextern\tbool\tmsg_badread;\t\t// set if a read goes beyond end of message\n\nvoid MSG_BeginReading (void);\nint MSG_ReadChar (void);\nint MSG_ReadByte (void);\nint MSG_ReadShort (void);\nint MSG_ReadLong (void);\nfloat MSG_ReadFloat (void);\nchar *MSG_ReadString (void);\n\nfloat MSG_ReadCoord (void);\nfloat MSG_ReadAngle (void);\nfloat MSG_ReadPreciseAngle(void); // JPG - precise aim!!\n\n//============================================================================\n\nvoid strncpyz (char *dest, const char *src, size_t size);\n\n//============================================================================\n\nextern\tchar\t\tcom_token[1024];\nextern\tbool\tcom_eof;\n\nchar *COM_Parse (const char *data);\n\n\nextern\tint\t\tcom_argc;\nextern\tchar\t**com_argv;\n\nint COM_CheckParm (const char *parm);\nvoid COM_Init (char *path);\nvoid COM_InitArgv (int argc, char **argv);\n\nchar *COM_SkipPath (char *pathname);\nvoid COM_StripExtension (char *in, char *out);\nvoid COM_FileBase (const char *in, char *out);\nvoid COM_DefaultExtension (char *path, char *extension);\nvoid COM_GetFolder (char *in, char *out);\n\nchar\t*va(char *format, ...);\n// does a varargs printf into a temp buffer\n\n\n//============================================================================\n\nextern int com_filesize;\nstruct cache_user_s;\n\nextern\tchar\tcom_gamedir[MAX_OSPATH];\n\nvoid COM_WriteFile (char *filename, void *data, int len);\nint COM_OpenFile (const char *filename, int *hndl, unsigned int *path_id);\nint COM_FOpenFile (char *filename, FILE **file, unsigned int *path_id);\nvoid COM_CloseFile (int h);\n\nbyte *COM_LoadStackFile (char *path, void *buffer, int bufsize, unsigned int *path_id);\nbyte *COM_LoadTempFile (const char *path, unsigned int *path_id);\nbyte *COM_LoadHunkFile (const char *path, unsigned int *path_id);\n\nfloat COM_Clamp(float value, float min, float max);\n\nextern\tstruct cvar_s\tregistered;\n\nextern bool\t\tstandard_quake, rogue, hipnotic;\n\n//============================================================================\n\n#ifndef HAVE_STRLCAT\nsize_t strlcat(char *dst, const char *src, size_t siz);\n#endif\n\nchar *strltrim(char *s);\nchar* strtolower(char* s);"
  },
  {
    "path": "source/console.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// console.c\n\n#ifdef NeXT\n#include <libc.h>\n#endif\n#ifndef _MSC_VER\n#include <unistd.h>\n#endif\n#include <fcntl.h>\n#include \"quakedef.h\"\n\nint \t\tcon_linewidth;\n\nfloat\t\tcon_cursorspeed = 4;\n\n#define\t\tCON_TEXTSIZE\t65536\n\nbool \tcon_forcedup;\t\t// because no entities to refresh\n\nint\t\t\tcon_totallines;\t\t// total lines in console scrollback\nint\t\t\tcon_backscroll;\t\t// lines up from bottom to display\nint\t\t\tcon_current;\t\t// where next message will be printed\nint\t\t\tcon_x;\t\t\t\t// offset in current line for next print\nchar\t\t*con_text=0;\n\nCVAR\t(con_notifytime, 3, CVAR_ARCHIVE)\t\t//seconds\n\n#define\tNUM_CON_TIMES 4\nfloat\t\tcon_times[NUM_CON_TIMES];\t// realtime time the line was generated\n\t\t\t\t\t\t\t\t// for transparent notify lines\n\nint\t\t\tcon_vislines;\n\nbool\tcon_debuglog;\n\n#define\t\tMAXCMDLINE\t256\nextern\tchar\tkey_lines[32][MAXCMDLINE];\nextern\tint\t\tedit_line;\nextern\tint\t\tkey_linepos;\n\n\nbool\tcon_initialized;\n\nint\t\t\tcon_notifylines;\t\t// scan lines to clear for notify lines\n\nextern void M_Menu_Main_f (void);\n\n/*\n================\nCon_ToggleConsole_f\n================\n*/\nvoid Con_ToggleConsole_f (void)\n{\n\tif (key_dest == key_console)\n\t{\n\t\tif (cls.state == ca_connected)\n\t\t{\n\t\t\tkey_dest = key_game;\n\t\t\tkey_lines[edit_line][1] = 0;\t// clear any typing\n\t\t\tkey_linepos = 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tM_Menu_Main_f ();\n\t\t}\n\t}\n\telse\n\t\tkey_dest = key_console;\n\n\tSCR_EndLoadingPlaque ();\n\tmemset (con_times, 0, sizeof(con_times));\n}\n\n/*\n================\nCon_Clear_f\n================\n*/\nvoid Con_Clear_f (void)\n{\n\tif (con_text)\n\t\tmemset (con_text, ' ', CON_TEXTSIZE);\n}\n\n\n/*\n================\nCon_ClearNotify\n================\n*/\nvoid Con_ClearNotify (void)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<NUM_CON_TIMES ; i++)\n\t\tcon_times[i] = 0;\n}\n\n\n/*\n================\nCon_MessageMode_f\n================\n*/\nextern bool team_message;\n\nvoid Con_MessageMode_f (void)\n{\n\tkey_dest = key_message;\n\tteam_message = false;\n}\n\n\n/*\n================\nCon_MessageMode2_f\n================\n*/\nvoid Con_MessageMode2_f (void)\n{\n\tkey_dest = key_message;\n\tteam_message = true;\n}\n\n/*\n================\nCon_CheckResize\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\tchar*\ttbuf;\n\n\twidth = (vid.width >> 3) - 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 = 78;\n\t\tcon_linewidth = width;\n\t\tcon_totallines = CON_TEXTSIZE / con_linewidth;\n\t\tmemset(con_text, ' ', CON_TEXTSIZE);\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\n\t\tif (con_linewidth < numchars)\n\t\t\tnumchars = con_linewidth;\n\n\t\ttbuf = Sys_BigStackAlloc(CON_TEXTSIZE, \"Con_CheckResize\");\n\n\t\tmemcpy(tbuf, con_text, CON_TEXTSIZE);\n\t\tmemset(con_text, ' ', CON_TEXTSIZE);\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] = tbuf[((con_current - i + oldtotallines) % oldtotallines) * oldwidth + j];\n\t\t\t}\n\t\t}\n\n\t\tSys_BigStackFree(CON_TEXTSIZE, \"Con_CheckResize\");\n\t\tCon_ClearNotify();\n\t}\n\n\tcon_backscroll = 0;\n\tcon_current = con_totallines - 1;\n}\n\n\n/*\n================\nCon_Init\n================\n*/\nvoid Con_Init (void)\n{\n#define MAXGAMEDIRLEN\t1000\n\tchar*\ttemp = Sys_BigStackAlloc(MAXGAMEDIRLEN + 1, \"Con_Init\");\n\tchar\t*t2 = \"/qconsole.log\";\n\n\tcon_debuglog = COM_CheckParm(\"-condebug\");\n\n\tif (con_debuglog)\n\t{\n\t\tif (strlen (com_gamedir) < (MAXGAMEDIRLEN - strlen (t2)))\n\t\t{\n\t\t\tsprintf (temp, \"%s%s\", com_gamedir, t2);\n\t\t\tunlink (temp);\n\t\t}\n\t}\n\n\tcon_text = Hunk_AllocName (CON_TEXTSIZE, \"context\");\n\tmemset (con_text, ' ', CON_TEXTSIZE);\n\tcon_linewidth = -1;\n\tCon_CheckResize ();\n\n//\n// register our commands\n//\n\tCvar_RegisterVariable (&con_notifytime);\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 (\"clear\", Con_Clear_f);\n\n\tSys_BigStackFree(MAXGAMEDIRLEN + 1, \"Con_Init\");\n\n\tcon_initialized = true;\n\tCon_Printf(\"Console initialized.\\n\");\n}\n\n\n/*\n===============\nCon_Linefeed\n===============\n*/\nvoid Con_Linefeed (void)\n{\n\tcon_x = 0;\n\tcon_current++;\n\tmemset (&con_text[(con_current%con_totallines)*con_linewidth]\n\t, ' ', con_linewidth);\n}\n\n/*\n================\nCon_Print\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 notify window will pop up.\n================\n*/\nvoid Con_Print (char *txt)\n{\n\tint\t\ty;\n\tint\t\tc, l;\n\tstatic int\tcr;\n\tint\t\tmask;\n\n\tcon_backscroll = 0;\n\n\tif (txt[0] == 1)\n\t{\n\t\tmask = 128;\t\t// go to colored text\n\t\tS_LocalSound (\"misc/talk.wav\");\n\t// play talk wav\n\t\ttxt++;\n\t}\n\telse if (txt[0] == 2)\n\t{\n\t\tmask = 128;\t\t// go to colored text\n\t\ttxt++;\n\t}\n\telse\n\t\tmask = 0;\n\n\n\twhile ( (c = *txt) )\n\t{\n\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\n\t// word wrap\n\t\tif (l != con_linewidth && (con_x + l > con_linewidth) )\n\t\t\tcon_x = 0;\n\n\t\ttxt++;\n\n\t\tif (cr)\n\t\t{\n\t\t\tcon_current--;\n\t\t\tcr = false;\n\t\t}\n\n\n\t\tif (!con_x)\n\t\t{\n\t\t\tCon_Linefeed ();\n\t\t// mark time for transparent overlay\n\t\t\tif (con_current >= 0)\n\t\t\t\tcon_times[con_current % NUM_CON_TIMES] = realtime;\n\t\t}\n\n\t\tswitch (c)\n\t\t{\n\t\tcase '\\n':\n\t\t\tcon_x = 0;\n\t\t\tbreak;\n\n\t\tcase '\\r':\n\t\t\tcon_x = 0;\n\t\t\tcr = 1;\n\t\t\tbreak;\n\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] = c | mask;\n\t\t\tcon_x++;\n\t\t\tif (con_x >= con_linewidth)\n\t\t\t\tcon_x = 0;\n\t\t\tbreak;\n\t\t}\n\n\t}\n}\n\n\n/*\n================\nCon_DebugLog\n================\n*/\nvoid Con_DebugLog(char *file, char *fmt, ...)\n{\n    va_list argptr;\n    static char data[1024];\n    int fd;\n\n    va_start(argptr, fmt);\n    vsprintf(data, fmt, argptr);\n    va_end(argptr);\n    fd = open(file, O_WRONLY | O_CREAT | O_APPEND, 0666);\n    write(fd, data, strlen(data));\n    close(fd);\n}\n\n\n/*\n================\nCon_Printf\n\nHandles cursor positioning, line wrapping, etc\n================\n*/\n#define\tMAXPRINTMSG\t16384\n// FIXME: make a buffer size safe vsprintf?\nvoid Con_Printf (const char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tmsg = Sys_BigStackAlloc(MAXPRINTMSG, \"Con_Printf\");\n\tstatic bool\tinupdate;\n\n\tva_start (argptr,fmt);\n\tvsprintf (msg,fmt,argptr);\n\tva_end (argptr);\n\n// also echo to debugging console\n\tSys_Printf (\"%s\", msg);\t// also echo to debugging console\n\n// log all messages to file\n\tif (con_debuglog)\n\t\tCon_DebugLog(va(\"%s/qconsole.log\",com_gamedir), \"%s\", msg);\n\n\tif (!con_initialized)\n\t{\n\t\tSys_BigStackFree(MAXPRINTMSG, \"Con_Printf\");\n\t\treturn;\n\t}\n\n\tif (cls.state == ca_dedicated)\n\t\treturn;\t\t// no graphics mode\n\n// write it to the scrollable buffer\n\tCon_Print (msg);\n\n// update the screen if the console is displayed\n\tif (cls.signon != SIGNONS && !scr_disabled_for_loading )\n\t{\n\t// protect against infinite loop if something in SCR_UpdateScreen calls\n\t// Con_Printd\n\t\tif (!inupdate)\n\t\t{\n\t\t\tinupdate = true;\n\t\t\tSCR_UpdateScreen ();\n\t\t\tinupdate = false;\n\t\t}\n\t}\n\n\tSys_BigStackFree(MAXPRINTMSG, \"Con_Printf\");\n}\n\n/*\n================\nCon_DPrintf\n\nA Con_Printf that only shows up if the \"developer\" cvar is set\n================\n*/\nvoid Con_DPrintf (char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tmsg;\n\n\tif (!developer.value)\n\t\treturn;\t\t\t// don't confuse non-developers with techie stuff...\n\n\tmsg = Sys_BigStackAlloc(MAXPRINTMSG, \"Con_DPrintf\");\n\n\tva_start (argptr,fmt);\n\tvsprintf (msg,fmt,argptr);\n\tva_end (argptr);\n\n\tCon_Printf (\"%s\", msg);\n\n\tSys_BigStackFree(MAXPRINTMSG, \"Con_DPrintf\");\n}\n\n\n/*\n==================\nCon_SafePrintf\n\nOkay to call even when the screen can't be updated\n==================\n*/\nvoid Con_SafePrintf (char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar* msg = Sys_BigStackAlloc(1024, \"Con_SafePrintf\");\n\tint\t\t\ttemp;\n\n\tva_start (argptr,fmt);\n\tvsprintf (msg,fmt,argptr);\n\tva_end (argptr);\n\n\ttemp = scr_disabled_for_loading;\n\tscr_disabled_for_loading = true;\n\tCon_Printf (\"%s\", msg);\n\tscr_disabled_for_loading = temp;\n\n\tSys_BigStackFree(1024, \"Con_SafePrintf\");\n}\n\n\n/*\n==============================================================================\n\nDRAWING\n\n==============================================================================\n*/\n\n\n/*\n================\nCon_DrawInput\n\nThe input line scrolls horizontally if typing goes beyond the right edge\n================\n*/\nvoid Con_DrawInput (void)\n{\n\tint\t\ti;\n\tchar\t*text;\n\n\tif (key_dest != key_console && !con_forcedup)\n\t\treturn;\t\t// don't draw anything\n\n\ttext = key_lines[edit_line];\n\n// add the cursor frame\n\ttext[key_linepos] = 10+((int)(realtime*con_cursorspeed)&1);\n\n// fill out remainder with spaces\n\tfor (i=key_linepos+1 ; i< con_linewidth ; i++)\n\t\ttext[i] = ' ';\n\n//\tprestep if horizontally scrolling\n\tif (key_linepos >= con_linewidth)\n\t\ttext += 1 + key_linepos - con_linewidth;\n\n// draw it\n\tfor (i=0 ; i<con_linewidth ; i++)\n\t\tBatch_Character ( (i+1)<<3, vid.conheight - 16, text[i]);\n\n// remove cursor\n\tkey_lines[edit_line][key_linepos] = 0;\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\tchar\t*text;\n\tint\t\ti;\n\tfloat\ttime;\n\textern char chat_buffer[];\n\n\tGL_SetCanvas (CANVAS_CONSOLE); //johnfitz\n\tv = vid.conheight;\n\t\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 = realtime - time;\n\t\tif (time > con_notifytime.value)\n\t\t\tcontinue;\n\t\ttext = con_text + (i % con_totallines)*con_linewidth;\n\n\t\tclearnotify = 0;\n\t\tscr_copytop = 1;\n\n\t\tfor (x = 0 ; x < con_linewidth ; x++)\n\t\t\tBatch_Character ( (x+1)<<3, v, text[x]);\n\n\t\tv += 8;\n\t}\n\n\n\tif (key_dest == key_message)\n\t{\n\t\tclearnotify = 0;\n\t\tscr_copytop = 1;\n\n\t\tx = 0;\n\n\t\tBatch_String (8, v, \"say:\", 0);\n\t\tBatch_String(40, v, chat_buffer, 0);\n\t\tx += strlen(chat_buffer);\n\t\tBatch_Character ( (x+5)<<3, v, 10+((int)(realtime*con_cursorspeed)&1));\n\t\tv += 8;\n\t}\n\t\n\tDraw_Batched();\n\n\tif (v > con_notifylines)\n\t\tcon_notifylines = v;\n}\n\n/*\n================\nCon_DrawConsole\n\nDraws the console with the solid background\nThe typing input line at the bottom should only be drawn if typing is allowed\n================\n*/\nvoid Con_DrawConsole (int lines, bool drawinput)\n{\n\tint\t\t\t\ti, sb, x, y;\n\tint\t\t\t\trows;\n\tchar\t\t\t*text;\n\tint\t\t\t\tj;\n\tchar\tver[32];\n\t\n\tif (lines <= 0)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_CONSOLE);\n\n// draw the background\n\tDraw_ConsoleBackground ();\n\n// draw the text\n\tcon_vislines = lines * vid.conheight / glheight;\n\n\trows = (con_vislines +7)/8;\n\ty = vid.conheight - rows*8;\n\trows -= 2; //for input and version lines\n\tsb = (con_backscroll) ? 2 : 0;\n\n\tfor (i = con_current - rows + 1; i <= con_current - sb; i++, y += 8)\n\t{\n\t\tj = i - con_backscroll;\n\t\tif (j < 0)\n\t\t\tj = 0;\n\t\ttext = con_text + (j % con_totallines)*con_linewidth;\n\t\t\n\t\tfor (x = 0 ; x < con_linewidth ; x++)\n\t\t\tBatch_Character ( (x+1)<<3, y, text[x]);\n\t}\n\n// draw scrollback arrows\n\tif (con_backscroll)\n\t{\n\t\ty += 8; // blank line\n\t\tfor (x = 0; x < con_linewidth; x += 4)\n\t\t\tBatch_Character ((x + 1)<<3, y, '^');\n\t\ty += 8;\n\t}\n\n// draw the input prompt, user text, and cursor\n\tif (drawinput)\n\t\tCon_DrawInput ();\n\n//draw version number in bottom right\n\ty += 8;\n\tsnprintf (ver, sizeof(ver), \"vitaQuake v.%.2f\", VERSION);\n\tBatch_String((con_linewidth - strlen(ver) + 2)<<3, y, ver, 0);\n\t\n\tDraw_Batched();\n}\n\n\n/*\n==================\nCon_NotifyBox\n==================\n*/\nvoid Con_NotifyBox (char *text)\n{\n\tdouble\t\tt1, t2;\n\n// during startup for sound / cd warnings\n\tCon_Printf(\"\\n\\n\\35\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\37\\n\");\n\n\tCon_Printf (text);\n\n\tCon_Printf (\"Press a key.\\n\");\n\tCon_Printf(\"\\35\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\37\\n\");\n\n\tkey_count = -2;\t\t// wait for a key down and up\n\tkey_dest = key_console;\n\n\tdo\n\t{\n\t\tt1 = Sys_FloatTime ();\n\t\tSCR_UpdateScreen ();\n\t\tSys_SendKeyEvents ();\n\t\tt2 = Sys_FloatTime ();\n\t\trealtime += t2-t1;\t\t// make the cursor blink\n\t} while (key_count < 0);\n\n\tCon_Printf (\"\\n\");\n\tkey_dest = key_game;\n\trealtime = 0;\t\t\t\t// put the cursor back to invisible\n}\n"
  },
  {
    "path": "source/console.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n//\n// console\n//\nextern int con_totallines;\nextern int con_backscroll;\nextern\tbool con_forcedup;\t// because no entities to refresh\nextern bool con_initialized;\nextern byte *con_chars;\nextern\tint\tcon_notifylines;\t\t// scan lines to clear for notify lines\n\nvoid Con_DrawCharacter (int cx, int line, int num);\n\nvoid Con_CheckResize (void);\nvoid Con_Init (void);\nvoid Con_DrawConsole (int lines, bool drawinput);\nvoid Con_Print (char *txt);\nvoid Con_Printf (const char *fmt, ...);\nvoid Con_DPrintf (char *fmt, ...);\nvoid Con_SafePrintf (char *fmt, ...);\nvoid Con_Clear_f (void);\nvoid Con_DrawNotify (void);\nvoid Con_ClearNotify (void);\nvoid Con_ToggleConsole_f (void);\n\nvoid Con_NotifyBox (char *text);\t// during startup for sound / cd warnings\n\n"
  },
  {
    "path": "source/crc.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n/* crc.c */\n\n#include \"quakedef.h\"\n#include \"crc.h\"\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\nstatic unsigned short crctable[256] =\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\nvoid CRC_Init(unsigned short *crcvalue)\n{\n\t*crcvalue = CRC_INIT_VALUE;\n}\n\nvoid CRC_ProcessByte(unsigned short *crcvalue, byte data)\n{\n\t*crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data];\n}\n\nunsigned short CRC_Value(unsigned short crcvalue)\n{\n\treturn crcvalue ^ CRC_XOR_VALUE;\n}\n\nunsigned short CRC_Block(byte *data, int size)\n{\n\tunsigned short crc = CRC_INIT_VALUE;\n\n\twhile (size--)\n\t\tcrc = (crc << 8) ^ crctable[(crc >> 8) ^ (*data++)];\n\n\treturn crc ^ CRC_XOR_VALUE;\n}"
  },
  {
    "path": "source/crc.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n/* crc.h */\n\nvoid CRC_Init(unsigned short *crcvalue);\nvoid CRC_ProcessByte(unsigned short *crcvalue, byte data);\nunsigned short CRC_Value(unsigned short crcvalue);\n"
  },
  {
    "path": "source/cvar.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cvar.c -- dynamic variable tracking\n\n#include \"quakedef.h\"\n\ncvar_t\t*cvar_vars;\nchar\t*cvar_null_string = \"\";\n\n/*\n============\nCvar_FindVar\n============\n*/\ncvar_t *Cvar_FindVar (const char *var_name)\n{\n\tcvar_t\t*var;\n\t\n\tfor (var=cvar_vars ; var ; var=var->next)\n\t\tif (!strcmp (var_name, var->name))\n\t\t\treturn var;\n\n\treturn NULL;\n}\n\n/*\n============\nCvar_VariableValue\n============\n*/\nfloat\tCvar_VariableValue (const char *var_name)\n{\n\tcvar_t\t*var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t\treturn 0;\n\treturn atof (var->string);\n}\n\n\n/*\n============\nCvar_VariableString\n============\n*/\nchar *Cvar_VariableString (const char *var_name)\n{\n\tcvar_t *var;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t\treturn cvar_null_string;\n\treturn var->string;\n}\n\n\n/*\n============\nCvar_CompleteVariable\n============\n*/\nchar *Cvar_CompleteVariable (char *partial)\n{\n\tcvar_t\t\t*cvar;\n\tint\t\t\tlen;\n\t\n\tlen = strlen(partial);\n\t\n\tif (!len)\n\t\treturn NULL;\n\t\t\n// check functions\n\tfor (cvar=cvar_vars ; cvar ; cvar=cvar->next)\n\t\tif (!strncmp (partial,cvar->name, len))\n\t\t\treturn (char*)cvar->name;\n\n\treturn NULL;\n}\n\n\n/*\n============\nCvar_Set\n============\n*/\nvoid Cvar_SetFull (const char *var_name, const char *value, bool forced)\n{\n\tcvar_t\t*var;\n\tbool changed;\n\t\n\tvar = Cvar_FindVar (var_name);\n\tif (!var)\n\t{\t// there is an error in C code if this happens\n\t\tCon_Printf (\"Cvar_Set: variable %s not found\\n\", var_name);\n\t\treturn;\n\t}\n\n\tif (var->flags & CVAR_ROM && !forced)\n\t{\n\t\tCon_Printf (\"%s is read-only.\\n\", var_name);\n\t\treturn;\n\t}\n\t\n\tchanged = strcmp(var->string, value);\n\t\n\tZ_Free (var->string);\t// free the old value string\n\t\n\tvar->string = Z_Malloc (strlen(value)+1);\n\tstrcpy (var->string, value);\n\tvar->value = atof (var->string);\n\tif (var->flags & CVAR_SERVERINFO && changed)\n\t{\n\t\tif (sv.active)\n\t\t\tSV_BroadcastPrintf (\"\\\"%s\\\" changed to \\\"%s\\\"\\n\", var->name, var->string);\n\t}\n\n\tif (var->callback)\n\t\tvar->callback(var);\n}\n\nvoid Cvar_Set (const char *var_name, const char *value)\n{\n\tCvar_SetFull (var_name, value, false);\n}\n\nvoid Cvar_ForceSet (const char *var_name, const char *value)\n{\n\tCvar_SetFull (var_name, value, true);\n}\n\n/*\n============\nCvar_SetValue\n============\n*/\nvoid Cvar_SetValue (const char *var_name, float value)\n{\n\tchar\tval[32];\n\t\n\tsprintf (val, \"%f\",value);\n\tCvar_Set (var_name, val);\n}\n\nvoid\tCvar_ToggleValue(cvar_t *cvar)\n{\n\tchar val[32];\n\tsprintf(val, \"%i\", !cvar->value);\n\n\tCvar_Set(cvar->name, val);\n}\n\n/*\n============\nCvar_RegisterVariable\n\nAdds a freestanding variable to the variable list.\n============\n*/\nvoid Cvar_RegisterVariable (cvar_t *variable)\n{\n\tchar\t*oldstr;\n\t\n// first check to see if it has already been defined\n\tif (Cvar_FindVar (variable->name))\n\t{\n\t\tCon_Printf (\"Can't register variable %s, already defined\\n\", variable->name);\n\t\treturn;\n\t}\n\t\n// Check for DEBUG-only CVARs.\n\tif (variable->flags & CVAR_DEBUG)\n\t{\n#ifndef DEBUG\n\t\treturn;\n#endif\n\t}\n\t\n// check for overlap with a command\n\tif (Cmd_Exists (variable->name))\n\t{\n\t\tCon_Printf (\"Cvar_RegisterVariable: %s is a command\\n\", variable->name);\n\t\treturn;\n\t}\n\t\t\n// copy the value off, because future sets will Z_Free it\n\toldstr = variable->string;\n\tvariable->string = Z_Malloc (strlen(variable->string)+1);\t\n\tstrcpy (variable->string, oldstr);\n\tvariable->value = atof (variable->string);\n\t\n\tif (!(variable->flags & CVAR_CALLBACK))\n\t\tvariable->callback = NULL;\n\n// link the variable in\n\tvariable->next = cvar_vars;\n\tcvar_vars = variable;\n}\n\n/*\n============\nCvar_SetCallback\nSet a callback function to the var\n============\n*/\nvoid Cvar_SetCallback(cvar_t *var, cvarcallback_t func)\n{\n\tvar->callback = func;\n\tif (func)\n\t\tvar->flags |= CVAR_CALLBACK;\n\telse\tvar->flags &= ~CVAR_CALLBACK;\n}\n\n/*\n============\nCvar_Command\n\nHandles variable inspection and changing from the console\n============\n*/\nbool\tCvar_Command (void)\n{\n\tcvar_t\t\t\t*v;\n\n// check variables\n\tv = Cvar_FindVar (Cmd_Argv(0));\n\tif (!v)\n\t\treturn false;\n\t\t\n// perform a variable print or set\n\tif (Cmd_Argc() == 1)\n\t{\n\t\tCon_Printf (\"\\\"%s\\\" is \\\"%s\\\"\\n\", v->name, v->string);\n\t\treturn true;\n\t}\n\n\tCvar_Set (v->name, Cmd_Argv(1));\n\treturn true;\n}\n\n\n/*\n============\nCvar_WriteVariables\n\nWrites lines containing \"set variable value\" for all variables\nwith the archive flag set to true.\n============\n*/\nvoid Cvar_WriteVariables (FILE *f)\n{\n\tcvar_t\t*var;\n\t\n\tfprintf(f, \"// CVARs\\n\");\n\tfor (var = cvar_vars ; var ; var = var->next)\n\t\tif (var->flags & CVAR_ARCHIVE)\n\t\t\tfprintf (f, \"%s \\\"%s\\\"\\n\", var->name, var->string);\n}\n\n\nvoid Cvar_Set_f(void)\n{\n\tchar *cvarname;\n\tchar *cvarvalue;\n\tcvar_t *var;\n\n\tcvarname = Cmd_Argv(1);\n\tcvarvalue = Cmd_Argv(2);\n\n\tvar = Cvar_FindVar(cvarname);\n\tif (!var)\n\t{\n\t\tif (Cmd_Exists(cvarname))\n\t\t{\n\t\t\tCon_Printf(\"%s exists as a command\\n\", cvarname);\n\t\t\treturn;\n\t\t}\n\t\tvar = malloc(sizeof(*var));\n\t\tif (!var)\n\t\t\treturn;\n\t\tmemset(var, 0, sizeof(*var));\n\t\tvar->name = strdup(cvarname);\n\t\tvar->string = \"\";\n\t\tCvar_RegisterVariable(var);\n\t}\n\n\tCvar_Set(cvarname, cvarvalue);\n}\n\nvoid Cvar_Seta_f(void)\n{\n\tchar *cvarname;\n\tchar *cvarvalue;\n\tcvar_t *var;\n\n\tcvarname = Cmd_Argv(1);\n\tcvarvalue = Cmd_Argv(2);\n\n\tvar = Cvar_FindVar(cvarname);\n\tif (!var)\n\t{\n\t\tif (Cmd_Exists(cvarname))\n\t\t{\n\t\t\tCon_Printf(\"%s exists as a command\\n\", cvarname);\n\t\t\treturn;\n\t\t}\n\t\tvar = malloc(sizeof(*var));\n\t\tif (!var)\n\t\t\treturn;\n\t\tmemset(var, 0, sizeof(*var));\n\t\tvar->name = strdup(cvarname);\n\t\tvar->string = \"\";\n\t\tvar->flags = CVAR_ARCHIVE;\n\t\tCvar_RegisterVariable(var);\n\t}\n\n\tCvar_Set(cvarname, cvarvalue);\n}\n"
  },
  {
    "path": "source/cvar.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// cvar.h\n\n/*\n\ncvar_t variables are used to hold scalar or string variables that can be changed or displayed at the console or prog code as well as accessed directly\nin C code.\n\nit is sufficient to initialize a cvar_t with just the first two fields, or\nyou can add a CVAR_ARCHIVE flag for variables that you want saved to the configuration\nfile when the game is quit:\n\ncvar_t\tr_draworder = {\"r_draworder\",\"1\"};\ncvar_t\tscr_screensize = {\"screensize\",\"1\",CVAR_ARCHIVE};\n\nCvars must be registered before use, or they will have a 0 value instead of the float interpretation of the string.  Generally, all cvar_t declarations should be registered in the apropriate init function before any console commands are executed:\nCvar_RegisterVariable (&host_framerate);\n\n\nC code usually just references a cvar in place:\nif ( r_draworder.value )\n\nIt could optionally ask for the value to be looked up for a string name:\nif (Cvar_VariableValue (\"r_draworder\"))\n\nInterpreted prog code can access cvars with the cvar(name) or\ncvar_set (name, value) internal functions:\nteamplay = cvar(\"teamplay\");\ncvar_set (\"registered\", \"1\");\n\nThe user can access cvars from the console in two ways:\nr_draworder\t\t\tprints the current value\nr_draworder 0\t\tsets the current value to 0\nCvars are restricted from having the same names as commands to keep this\ninterface from being ambiguous.\n*/\n\n#define CVAR_NONE \t\tBIT(0) \t// No property (can be omitted)\n#define CVAR_ARCHIVE \tBIT(1)\t// CVAR saved on the CFG.\n#define CVAR_SERVERINFO BIT(2)\t// Informative CVAR from the server.\n#define CVAR_ROM\t \tBIT(3) \t// Only set by the engine.\n#define CVAR_DEBUG\t\tBIT(4)\t// CVARs only enabled if the DEBUG flag is set.\n#define\tCVAR_CALLBACK\tBIT(5)\t// CVAR has a callback\n\ntypedef void(*cvarcallback_t) (struct cvar_s *);\n\ntypedef struct cvar_s\n{\n\tconst char\t*name;\n\tchar\t*string;\n\tunsigned int flags;\n\tfloat\tvalue;\n\tcvarcallback_t\tcallback;\n\tstruct cvar_s *next;\n} cvar_t;\n\n#define CVAR(name, defaultvalue, flags) cvar_t name = {#name, (char*)#defaultvalue, flags};\n#define STATIC_CVAR(name, defaultvalue, flags) static cvar_t name = {#name, #defaultvalue, flags};\n\nvoid \tCvar_RegisterVariable (cvar_t *variable);\n// registers a cvar that already has the name, string, and optionally the\n// archive elements set.\n\n// equivelant to \"<name> <variable>\" typed at the console\nvoid \tCvar_Set (const char *var_name, const char *value);\nvoid \tCvar_ForceSet (const char *var_name, const char *value);\n\n// set a callback function to the var\nvoid\tCvar_SetCallback(cvar_t *var, cvarcallback_t func);\n\n// expands value to a string and calls Cvar_Set\nvoid\tCvar_SetValue (const char *var_name, float value);\n\n// Toggles a value\nvoid\tCvar_ToggleValue(cvar_t *cvar);\n\n// returns 0 if not defined or non numeric\nfloat\tCvar_VariableValue (const char *var_name);\n\n// returns an empty string if not defined\nchar\t*Cvar_VariableString (const char *var_name);\n\n// attempts to match a partial variable name for command line completion\n// returns NULL if nothing fits\nchar \t*Cvar_CompleteVariable (char *partial);\n\nbool 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 (FILE *f);\n// Writes lines containing \"set variable value\" for all variables\n// with the archive flag set to true.\n\ncvar_t *Cvar_FindVar (const char *var_name);\n\nvoid Cvar_Set_f(void);\nvoid Cvar_Seta_f(void);\n\nextern cvar_t\t*cvar_vars;\n"
  },
  {
    "path": "source/draw.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// draw.h -- these are the only functions outside the refresh allowed\n// to touch the vid buffer\n\nextern\tqpic_t\t\t*draw_disc;\t// also used on sbar\n\nvoid Draw_Init (void);\nvoid Draw_Character (int x, int y, int num);\nvoid Draw_DebugChar (signed char num);\nvoid Draw_Pic (int x, int y, qpic_t *pic);\nvoid Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha);\nvoid Draw_TransPic (int x, int y, qpic_t *pic);\nvoid Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation);\nvoid Draw_ConsoleBackground (void);\nvoid Draw_BeginDisc (void);\nvoid Draw_EndDisc (void);\nvoid Draw_TileClear (int x, int y, int w, int h);\nvoid Draw_Fill (int x, int y, int w, int h, int c);\nvoid Draw_FadeScreen (void);\nvoid Draw_String (int x, int y, const char *str, int delta);\nvoid Draw_Crosshair(void);\nqpic_t *Draw_PicFromWad (const char *name);\nqpic_t *Draw_CachePic (char *path);\n\nvoid Batch_Character (int x, int y, int num);\nvoid Batch_String (int x, int y, const char *str, int delta);\nvoid Draw_Batched();\n"
  },
  {
    "path": "source/gl_draw.cpp",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// draw.c -- this is the only file outside the refresh that touches the\n// vid buffer\n\nextern \"C\"{\n#include <vitasdk.h>\n#include \"quakedef.h\"\nextern unsigned short CRC_Block(byte *data, int size);\n}\n\n#define GL_COLOR_INDEX8_EXT     0x80E5\n\nextern unsigned char d_15to8table[65536];\n\nint\t\t\tcs_texture;\n\nstatic byte cs_data[64]  = {\n\t0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,\n\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,\n\t0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xff,\n\t0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,\n\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,\n\t0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,\n\t0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff\n};\n\nCVAR\t(gl_nobind, 0, CVAR_NONE)\nCVAR\t(gl_max_size, 4096, CVAR_NONE)\nCVAR\t(gl_picmip, 0, CVAR_NONE)\nCVAR\t(gl_bilinear, 1, CVAR_ARCHIVE)\nCVAR\t(gl_compress, 0, CVAR_ARCHIVE)\n\nextern cvar_t crosshaircolor_r;\nextern cvar_t crosshaircolor_g;\nextern cvar_t crosshaircolor_b;\nextern cvar_t cl_crossx;\nextern cvar_t cl_crossy;\nextern cvar_t crosshair;\nextern cvar_t gl_mipmap;\nextern cvar_t scr_crosshairscale;\nextern cvar_t scr_conalpha;\nextern cvar_t scr_menuscale;\nextern cvar_t scr_sbarscale;\n\nextern int tex_cache;\n\nbyte\t\t*draw_chars;\t\t\t\t// 8*8 graphic characters\nqpic_t\t\t*draw_disc;\nqpic_t\t\t*draw_backtile;\n\nint\t\t\ttranslate_texture;\nint\t\t\tchar_texture;\nint \t\tcurrentcanvas = -1;\n\ntypedef struct\n{\n\tint\t\ttexnum;\n\tfloat\tsl, tl, sh, th;\n} glpic_t;\n\nbyte\t\tconback_buffer[sizeof(qpic_t) + sizeof(glpic_t)];\nqpic_t\t*conback = (qpic_t *)&conback_buffer;\n\nint\t\tgl_lightmap_format = GL_RGBA;\nint\t\tgl_solid_format = 3;\nint\t\tgl_alpha_format = 4;\n\nint\t\tgl_filter_min = GL_LINEAR;\nint\t\tgl_filter_max = GL_LINEAR;\n\n\nint\t\ttexels;\n\ntypedef struct\n{\n\tint\t\ttexnum;\n\tchar identifier[64];\n\tint\t\twidth, height;\n\tbool\tmipmap;\n} gltexture_t;\n\n#define\tMAX_GLTEXTURES\t1024\ngltexture_t\tgltextures[MAX_GLTEXTURES];\nint numgltextures = 0;\n\nstatic int LoadExternalPic(char *identifier)\n{\n\tchar fname[512];\n\tCOM_StripExtension (identifier, fname);\n\tint w, h;\n\tbyte *data = Image_LoadImage (fname, &w, &h);\n\tif (data) {\n\t\tint r = GL_LoadTexture32 (\"\", w, h, data, false, true, false);\n\t\tfree(data);\n\t\treturn r;\n\t}\n\treturn -1;\n}\n\n// FIXME: It seems the texture manager fails with Half Life BSPs\n\n/*\n * Texture Manager - derived from glesquake\n */\nclass textureStore {\n\nprivate:\n    static const GLuint UNUSED = (GLuint) -2;\n    static const GLuint PAGED_OUT = (GLuint) -1;\n\n    struct entry\n    {\n        entry* next;\n        entry* prev;\n        GLuint real_texnum;    // UNUSED, PAGED_OUT\n\t\tbool is32;\n        byte* pData; // 0 ==> not created by us.\n        size_t size;\n        bool alpha;\n        int width;\n        int height;\n        bool mipmap;\n\n        entry() {\n            next = 0;\n            prev = 0;\n            real_texnum = UNUSED;\n            pData = 0;\n        }\n\n\n        void unlink() {\n            if (next) {\n                next->prev = prev;\n            }\n            if (prev) {\n                prev->next = next;\n            }\n            next = 0;\n            prev = 0;\n        }\n\n        void insertBefore(entry* e){\n            if (e) {\n                prev = e->prev;\n                if ( prev ) {\n                    prev->next = this;\n                }\n                next = e;\n                e->prev = this;\n            }\n            else {\n                prev = 0;\n                next = 0;\n            }\n        }\n    };\n\npublic:\n\n    static textureStore* get() {\n        if (g_pTextureCache == 0) {\n            g_pTextureCache = new textureStore();\n        }\n        return g_pTextureCache;\n    }\n\n    // Equivalent of glBindTexture, but uses the virtual texture table\n\n    void bind(int virtTexNum) {\n        if ( (unsigned int) virtTexNum >= TEXTURE_STORE_NUM_TEXTURES) {\n            Sys_Error(\"not in the range we're managing\");\n        }\n        mBoundTextureID = virtTexNum;\n        entry* e = &mTextures[virtTexNum];\n\n        if ( e->real_texnum == UNUSED) {\n            glGenTextures( 1, &e->real_texnum);\n        }\n\n        if ( e->pData == 0) {\n            glBindTexture(GL_TEXTURE_2D, e->real_texnum);\n            return;\n        }\n\n        update(e);\n    }\n\n    void update(entry* e)\n    {\n        // Update the \"LRU\" part of the cache\n        unlink(e);\n        e->insertBefore(mFirst);\n        mFirst = e;\n        if (! mLast) {\n            mLast = e;\n        }\n\n        if (e->real_texnum == PAGED_OUT ) {\n            // Create a real texture\n            // Make sure there is enough room for this texture\n            ensure(e->size);\n\n            glGenTextures( 1, &e->real_texnum);\n\t\t\t\n            glBindTexture(GL_TEXTURE_2D, e->real_texnum);\n\t\t\tif (e->is32)\n\t\t\t\tGL_Upload32 ((unsigned*)e->pData, e->width, e->height, e->mipmap,\n                    e->alpha);\n\t\t\telse\n\t\t\t\tGL_Upload8 (e->pData, e->width, e->height, e->mipmap,\n                    e->alpha);\n        }\n        else {\n            glBindTexture(GL_TEXTURE_2D, e->real_texnum);\n        }\n    }\n\n    // Create a texture, and remember the data so we can create\n    // it again later.\n\n    void create(int width, int height, byte* data, bool mipmap,\n            bool alpha, bool is32) {\n        int size = width * height;\n\t\tif (is32) size *= 4;\n        if (size + mLength > mCapacity) {\n            Sys_Error(\"Ran out of virtual texture space. %d\", size);\n        };\n        entry* e = &mTextures[mBoundTextureID];\n\n        // Call evict in case the currently bound texture id is already\n        // in use. (Shouldn't happen in Quake.)\n        // To Do: reclaim the old texture memory from the virtual memory.\n\n        evict(e);\n\n        e->alpha = alpha;\n        e->pData = mBase + mLength;\n        memcpy(e->pData, data, size);\n        e->size = size;\n        e->width = width;\n        e->height = height;\n        e->mipmap = mipmap;\n\t\te->is32 = is32;\n        e->real_texnum = PAGED_OUT;\n        mLength += size;\n\n        update(e);\n    }\n\n    // Re-upload the current textures because we've been reset.\n    void rebindAll() {\n        grabMagicTextureIds();\n        for (entry* e = mFirst; e; e = e->next ) {\n            if (! (e->real_texnum == UNUSED || e->real_texnum == PAGED_OUT)) {\n                glBindTexture(GL_TEXTURE_2D, e->real_texnum);\n                if (e->pData) {\n\t\t\t\t\tif (e->is32)\n\t\t\t\t\t\tGL_Upload32 ((unsigned*)e->pData, e->width, e->height, e->mipmap,\n\t\t\t\t\t\t\te->alpha);\n\t\t\t\t\telse\n\t\t\t\t\t\tGL_Upload8 (e->pData, e->width, e->height, e->mipmap,\n\t\t\t\t\t\t\te->alpha);\n                }\n            }\n        }\n    }\n\nprivate:\n\n    textureStore() {\n        grabMagicTextureIds();\n        mFirst = 0;\n        mLast = 0;\n        mTextureCount = 0;\n\n        mBase = (byte*)malloc(TEXTURE_STORE_SIZE);\n\t\tmBase[TEXTURE_STORE_SIZE-1] = 0;\n\t\t\n        mLength = 0;\n        mCapacity = TEXTURE_STORE_SIZE;\n        mRamUsed = 0;\n        mRamSize = LIVE_TEXTURE_LIMIT;\n    }\n\n    ~textureStore() {\n        free(mBase);\n    }\n\n    void grabMagicTextureIds() {\n        // reserve these two texture ids.\n        glBindTexture(GL_TEXTURE_2D, UNUSED);\n        glBindTexture(GL_TEXTURE_2D, PAGED_OUT);\n    }\n\n    void unlink(entry* e) {\n        if (e == mFirst) {\n            mFirst = e->next;\n        }\n        if (e == mLast) {\n            mLast = e->prev;\n        }\n        e->unlink();\n    }\n\n    void ensure(int size) {\n        while ( mRamSize - mRamUsed < (unsigned int) size) {\n            entry* e = mLast;\n            if(! e) {\n                Sys_Error(\"Ran out of entries\");\n                return;\n            }\n            evict(e);\n        }\n        mRamUsed += size;\n    }\n\n    void evict(entry* e) {\n        unlink(e);\n        if ( e->pData ) {\n            glDeleteTextures(1, &e->real_texnum);\n            e->real_texnum = PAGED_OUT;\n            mRamUsed -= e->size;\n        }\n    }\n\n    static const size_t TEXTURE_STORE_SIZE = 16 * 1024 * 1024;\n    static const size_t LIVE_TEXTURE_LIMIT = 1 * 1024 * 1024;\n    static const size_t TEXTURE_STORE_NUM_TEXTURES = 512;\n\n    byte* mBase;\n    size_t mLength;\n    size_t mCapacity;\n\n    // Keep track of texture RAM.\n    size_t mRamUsed;\n    size_t mRamSize;\n\n    // The virtual textures\n    entry mTextures[MAX_GLTEXTURES];\n    entry* mFirst; // LRU queue\n    entry* mLast;\n    size_t mTextureCount; // How many virtual textures have been allocated\n\n    static textureStore* g_pTextureCache;\n\n    int mBoundTextureID;\n};\n\ntextureStore* textureStore::g_pTextureCache;\n\nvoid GL_Bind (int texnum)\n{\n\tif (currenttexture == texnum)\n\t\treturn;\n\tcurrenttexture = texnum;\n\t\n\tif (tex_cache)\n\t\ttextureStore::get()->bind(texnum);\n\telse\n\t\tglBindTexture(GL_TEXTURE_2D, texnum);\n}\n\n/*\n=============================================================================\n\n  scrap allocation\n\n  Allocate all the little status bar obejcts into a single texture\n  to crutch up stupid hardware / drivers\n\n=============================================================================\n*/\n\n#define\tMAX_SCRAPS\t\t2\n#define\tBLOCK_WIDTH\t\t256\n#define\tBLOCK_HEIGHT\t256\n\nint\t\t\tscrap_allocated[MAX_SCRAPS][BLOCK_WIDTH];\nbyte\t\tscrap_texels[MAX_SCRAPS][BLOCK_WIDTH*BLOCK_HEIGHT*4];\nbool\tscrap_dirty;\nint\t\t\tscrap_texnum;\n\n// returns a texture number and the position inside it\nint Scrap_AllocBlock (int w, int h, int *x, int *y)\n{\n\tint\t\ti, j;\n\tint\t\tbest, best2;\n\tint\t\tbestx;\n\tint\t\ttexnum;\n\n\tfor (texnum=0 ; texnum<MAX_SCRAPS ; texnum++)\n\t{\n\t\tbest = BLOCK_HEIGHT;\n\n\t\tfor (i=0 ; i<BLOCK_WIDTH-w ; i++)\n\t\t{\n\t\t\tbest2 = 0;\n\n\t\t\tfor (j=0 ; j<w ; j++)\n\t\t\t{\n\t\t\t\tif (scrap_allocated[texnum][i+j] >= best)\n\t\t\t\t\tbreak;\n\t\t\t\tif (scrap_allocated[texnum][i+j] > best2)\n\t\t\t\t\tbest2 = scrap_allocated[texnum][i+j];\n\t\t\t}\n\t\t\tif (j == w)\n\t\t\t{\t// this is a valid spot\n\t\t\t\t*x = i;\n\t\t\t\t*y = best = best2;\n\t\t\t}\n\t\t}\n\n\t\tif (best + h > BLOCK_HEIGHT)\n\t\t\tcontinue;\n\n\t\tfor (i=0 ; i<w ; i++)\n\t\t\tscrap_allocated[texnum][*x + i] = best + h;\n\n\t\treturn texnum;\n\t}\n\n\tSys_Error (\"Scrap_AllocBlock: full\");\n\treturn 0;\n}\n\nint\tscrap_uploads;\n\nvoid Scrap_Upload (void)\n{\n\tint\t\ttexnum;\n\n\tscrap_uploads++;\n\n\tfor (texnum=0 ; texnum<MAX_SCRAPS ; texnum++) {\n\t\tGL_Bind(scrap_texnum + texnum);\n\t\tGL_Upload8 (scrap_texels[texnum], BLOCK_WIDTH, BLOCK_HEIGHT, false, true);\n\t}\n\tscrap_dirty = false;\n}\n\n//=============================================================================\n/* Support Routines */\n\ntypedef struct cachepic_s\n{\n\tchar\t\tname[MAX_QPATH];\n\tqpic_t\t\tpic;\n\tbyte\t\tpadding[32];\t// for appended glpic\n} cachepic_t;\n\n#define\tMAX_CACHED_PICS\t\t128\ncachepic_t\tmenu_cachepics[MAX_CACHED_PICS];\nint\t\t\tmenu_numcachepics;\n\nbyte\t\tmenuplyr_pixels[4096];\n\nint\t\tpic_texels;\nint\t\tpic_count;\n\n/*\n================\nGL_LoadPicTexture\n================\n*/\nint GL_LoadPicTexture (qpic_t *pic)\n{\n  return GL_LoadTexture (\"\", pic->width, pic->height, pic->data, false, true);\n}\n\nqpic_t *Draw_PicFromWad (const char *name)\n{\n\tqpic_t\t*p;\n\tglpic_t\t*gl;\n\n\tp = (qpic_t*)W_GetLumpName (name);\n\tgl = (glpic_t *)p->data;\n\t\n\tchar fname[64];\n\tsprintf(fname, \"gfx/%s\", name);\n\tint texnum = LoadExternalPic(fname);\n\tif (texnum != -1) {\n\t\tgl->texnum = texnum;\n\t\tgl->sl = 0;\n\t\tgl->sh = 1;\n\t\tgl->tl = 0;\n\t\tgl->th = 1;\n\t\treturn p;\n\t}\n\t\n\t// load little ones into the scrap\n\tif (p->width < 64 && p->height < 64)\n\t{\n\t\tint\t\tx, y;\n\t\tint\t\ti, j, k;\n\t\tint\t\ttexnum;\n\n\t\ttexnum = Scrap_AllocBlock (p->width, p->height, &x, &y);\n\t\tscrap_dirty = true;\n\t\tk = 0;\n\t\tfor (i=0 ; i<p->height ; i++)\n\t\t\tfor (j=0 ; j<p->width ; j++, k++)\n\t\t\t\tscrap_texels[texnum][(y+i)*BLOCK_WIDTH + x + j] = p->data[k];\n\t\ttexnum += scrap_texnum;\n\t\tgl->texnum = texnum;\n\t\tgl->sl = (x+0.01)/(float)BLOCK_WIDTH;\n\t\tgl->sh = (x+p->width-0.01)/(float)BLOCK_WIDTH;\n\t\tgl->tl = (y+0.01)/(float)BLOCK_WIDTH;\n\t\tgl->th = (y+p->height-0.01)/(float)BLOCK_WIDTH;\n\n\t\tpic_count++;\n\t\tpic_texels += p->width*p->height;\n\t}\n\telse\n\t{\n\t\tgl->texnum = GL_LoadPicTexture (p);\n\t\tgl->sl = 0;\n\t\tgl->sh = 1;\n\t\tgl->tl = 0;\n\t\tgl->th = 1;\n\t}\n\treturn p;\n}\n\n\n/*\n================\nDraw_CachePic\n================\n*/\nqpic_t\t*Draw_CachePic (char *path)\n{\n\tcachepic_t\t*pic;\n\tint\t\t\ti;\n\tqpic_t\t\t*dat;\n\tglpic_t\t\t*gl;\n\n\tfor (pic=menu_cachepics, i=0 ; i<menu_numcachepics ; pic++, i++)\n\t\tif (!strcmp (path, pic->name))\n\t\t\treturn &pic->pic;\n\n\tif (menu_numcachepics == MAX_CACHED_PICS)\n\t\tSys_Error (\"menu_numcachepics == MAX_CACHED_PICS\");\n\tmenu_numcachepics++;\n\tstrcpy (pic->name, path);\n\t\n//\n// load the pic from disk\n//\n\tdat = (qpic_t *)COM_LoadTempFile (path, NULL);\t\n\tif (!dat)\n\t\tSys_Error (\"Draw_CachePic: failed to load %s\", path);\n\tSwapPic (dat);\n\n\t// HACK HACK HACK --- we need to keep the bytes for\n\t// the translatable player picture just for the menu\n\t// configuration dialog\n\tif (!strcmp (path, \"gfx/menuplyr.lmp\"))\n\t\tmemcpy (menuplyr_pixels, dat->data, dat->width*dat->height);\n\n\tpic->pic.width = dat->width;\n\tpic->pic.height = dat->height;\n\t\n\tgl = (glpic_t *)pic->pic.data;\n\tint texnum = LoadExternalPic(path);\n\tif (texnum != -1) gl->texnum = texnum;\n\telse gl->texnum = GL_LoadPicTexture (dat);\n\tgl->sl = 0;\n\tgl->sh = 1;\n\tgl->tl = 0;\n\tgl->th = 1;\n\t\n\treturn &pic->pic;\n}\n\n\nvoid Draw_CharToConback (int num, byte *dest)\n{\n\tint\t\trow, col;\n\tbyte\t*source;\n\tint\t\tdrawline;\n\tint\t\tx;\n\n\trow = num>>4;\n\tcol = num&15;\n\tsource = draw_chars + (row<<10) + (col<<3);\n\n\tdrawline = 8;\n\n\twhile (drawline--)\n\t{\n\t\tfor (x=0 ; x<8 ; x++)\n\t\t\tif (source[x] != 255)\n\t\t\t\tdest[x] = 0x60 + source[x];\n\t\tsource += 128;\n\t\tdest += 320;\n\t}\n\n}\n\ntypedef struct\n{\n\tconst char *name;\n\tint\tminimize, maximize;\n} glmode_t;\n\nglmode_t modes[] = {\n\t{\"GL_NEAREST\", GL_NEAREST, GL_NEAREST},\n\t{\"GL_LINEAR\", GL_LINEAR, GL_LINEAR}\n};\n\n/*\n===============\nDraw_TextureMode_f\n===============\n*/\nvoid Draw_TextureMode_f (void)\n{\n\tint\t\ti;\n\tgltexture_t\t*glt;\n\n\tif (Cmd_Argc() == 1)\n\t{\n\t\tfor (i=0 ; i< 6 ; i++)\n\t\t\tif (gl_filter_min == modes[i].minimize)\n\t\t\t{\n\t\t\t\tCon_Printf (\"%s\\n\", modes[i].name);\n\t\t\t\treturn;\n\t\t\t}\n\t\tCon_Printf (\"current filter is unknown???\\n\");\n\t\treturn;\n\t}\n\n\tfor (i=0 ; i< 6 ; i++)\n\t{\n\t\tif (!strcasecmp ((char*)modes[i].name, Cmd_Argv(1) ) )\n\t\t\tbreak;\n\t}\n\tif (i == 6)\n\t{\n\t\tCon_Printf (\"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, glt=gltextures ; i<numgltextures ; i++, glt++)\n\t{\n\t\tif (glt->mipmap)\n\t\t{\n\t\t\tGL_Bind (glt->texnum);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);\n\t\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\t\t}\n\t}\n}\n\n/*\n===============\nCallback_Bilinear_f\nThis callback is used to set at launch the texture mode.\n===============\n*/\nstatic void Callback_Bilinear_f(cvar_t *var)\n{\n\tif (gl_bilinear.value)\n\t\tCbuf_AddText(\"gl_texturemode GL_LINEAR\\n\");\n\telse\n\t\tCbuf_AddText(\"gl_texturemode GL_NEAREST\\n\");\n}\n\n/*\n===============\nDraw_Init\n===============\n*/\nvoid Draw_Init (void)\n{\n\tint\t\ti;\n\tqpic_t\t*cb;\n\tbyte\t*dest, *src;\n\tint\t\tx, y;\n\tchar\tver[40];\n\tglpic_t\t*gl;\n\tint\t\tstart;\n\tbyte\t*ncdata;\n\tint\t\tf, fstep, maxsize;\n\n\tCvar_RegisterVariable (&gl_nobind);\n\tCvar_RegisterVariable (&gl_max_size);\n\tCvar_RegisterVariable (&gl_picmip);\n\tCvar_RegisterVariable (&gl_bilinear);\n\tCvar_RegisterVariable (&st_separation );\n\tCvar_RegisterVariable (&st_zeropdist );\n\tCvar_RegisterVariable (&st_fustbal );\n\n\tCvar_SetCallback (&gl_bilinear, &Callback_Bilinear_f);\n\n\t// texture_max_size\n\tif ((i = COM_CheckParm(\"-maxsize\")) != 0) {\n\t\tmaxsize = atoi(com_argv[i+1]);\n\t\tmaxsize &= 0xff80;\n\t\tCvar_SetValue(\"gl_max_size\", maxsize);\n\t} \n\n\tCmd_AddCommand (\"gl_texturemode\", &Draw_TextureMode_f);\n\n\t// load the console background and the charset\n\t// by hand, because we need to write the version\n\t// string into the background before turning\n\t// it into a texture\n\tdraw_chars = (byte*)W_GetLumpName (\"conchars\");\n\t\n\tfor (i=0 ; i<256*64 ; i++)\n\t\tif (draw_chars[i] == 0)\n\t\t\tdraw_chars[i] = 255;\t// proper transparent color\n\t\t\n\tunsigned short conchars_crc = CRC_Block(draw_chars, 256*64);\n\tif (conchars_crc == 0x4FA4) {\n\n\t\t// Patching 'Y' glyphs to not make them ugly on original font\n\t\tuint8_t grey  = draw_chars[2 +  42 * 128];\n\t\tuint8_t brown = draw_chars[2 + 123 * 128];\n\t\n\t\tint to_grey[] = {\n\t\t\t74 + 40 * 128, 75 + 41 * 128, 76 + 43 * 128, 76 + 44 * 128,\n\t\t\t76 + 45 * 128, 74 + 57 * 128, 75 + 58 * 128\n\t\t};\n\t\n\t\tint to_trans[] = {\n\t\t\t74 +  42 * 128, 74 +  43 * 128, 74 +  44 * 128, 74 +  45 * 128,\n\t\t\t74 +  59 * 128, 76 +  57 * 128, 74 + 123 * 128, 76 + 121 * 128,\n\t\t\t74 + 106 * 128, 74 + 107 * 128, 74 + 108 * 128, 74 + 109 * 128\n\t\t};\n\t\n\t\tint to_brown[] = {\n\t\t\t74 + 104 * 128, 75 + 105 * 128, 76 + 107 * 128, 76 + 108 * 128,\n\t\t\t76 + 109 * 128, 74 + 121 * 128, 75 + 122 * 128\n\t\t};\n\t\n\t\tfor (i=0 ; i<sizeof(to_grey)/sizeof(int); i++) {\n\t\t\tdraw_chars[to_grey[i]+129] = grey;\n\t\t}\n\t\tfor (i=0 ; i<sizeof(to_brown)/sizeof(int); i++) {\n\t\t\tdraw_chars[to_brown[i]+129] = brown;\n\t\t}\n\t\tfor (i=0 ; i<sizeof(to_trans)/sizeof(int); i++) {\n\t\t\tdraw_chars[to_trans[i]+129] = 0xFF;\n\t\t}\n\t}\n\t\n\t// now turn them into textures\n\tchar_texture = GL_LoadTexture (\"charset\", 128, 128, draw_chars, false, true);\n\t\n\t// custom crosshair support\n\tchar crosshair_file[1024];\n\tsprintf(crosshair_file, \"%s/xhair.bin\", com_gamedir);\n\tSceUID fd = sceIoOpen(crosshair_file, SCE_O_RDONLY, 0777);\n\tif (fd >= 0) {\n\t\tsceIoRead(fd, cs_data, 64);\n\t\tsceIoClose(fd);\n\t}\n\tcs_texture = GL_LoadTexture (\"crosshair\", 8, 8, cs_data, false, true);\n\n\tstart = Hunk_LowMark();\n\t\n\t// External conback texture support\n\tint cwidth, cheight;\n\tbyte *data = Image_LoadImage (\"gfx/conback\", &cwidth, &cheight);\n\tif (data) {\n\t\tconback->width = cwidth;\n\t\tconback->height = cheight;\n\t\tncdata = data;\n\t} else {\n\t\tcb = (qpic_t *)COM_LoadTempFile (\"gfx/conback.lmp\", NULL);\t\n\t\tif (!cb)\n\t\t\tSys_Error (\"Couldn't load gfx/conback.lmp\");\n\t\tSwapPic (cb);\n\n\t\t// hack the version number directly into the pic\n\t\tsprintf (ver, \"(gl %4.2f) %4.2f\", (float)GLQUAKE_VERSION, (float)VERSION);\n\n\t\tdest = cb->data + 320*186 + 320 - 11 - 8*strlen(ver);\n\t\ty = strlen(ver);\n\t\tfor (x=0 ; x<y ; x++)\n\t\t\tDraw_CharToConback (ver[x], dest+(x<<3));\n\n\t\tconback->width = cb->width;\n\t\tconback->height = cb->height;\n\t\tncdata = cb->data;\n\t}\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);  // 13/02/2000 changed: M.Tretene\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\n\tgl = (glpic_t *)conback->data;\n\tif (data) {\n\t\tgl->texnum = GL_LoadTexture32 (\"conback\", conback->width, conback->height, ncdata, false, true, false);\n\t\tfree(data);\n\t} else\n\t\tgl->texnum = GL_LoadTexture (\"conback\", conback->width, conback->height, ncdata, false, true); //  30/01/2000 modified: M.Tretene\n\tgl->sl = 0;\n\tgl->sh = 1;\n\tgl->tl = 0;\n\tgl->th = 1;\n\tconback->width = vid.width;\n\tconback->height = vid.height;\n\n\t// free loaded console\n\tHunk_FreeToLowMark(start);\n\n\t// save a texture slot for translated picture\n\ttranslate_texture = texture_extension_number++;\n\n\t// save slots for scraps\n\tscrap_texnum = texture_extension_number;\n\ttexture_extension_number += MAX_SCRAPS;\n\n\t//\n\t// get the other pics we need\n\t//\n\tdraw_disc = Draw_PicFromWad (\"disc\");\n\tdraw_backtile = Draw_PicFromWad (\"backtile\");\n}\n\nvoid DrawQuad_NoTex(float x, float y, float w, float h, float r, float g, float b, float a)\n{\n\tgVertexBuffer[0] = gVertexBuffer[9] = x;\n\tgVertexBuffer[1] = gVertexBuffer[4] = y;\n\tgVertexBuffer[3] = gVertexBuffer[6] = x+w;\n\tgVertexBuffer[7] = gVertexBuffer[10] = y+h;\n\tgVertexBuffer[2] = gVertexBuffer[5] = gVertexBuffer[8] = gVertexBuffer[11] = 0.5f;\n\t\n\tfloat color[4] = {r,g,b,a};\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\tvglVertexAttribPointerMapped(0, gVertexBuffer);\n\tgVertexBuffer += 12;\n\tglUniform4fv(monocolor, 1, color);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n}\n\nvoid DrawQuad(float x, float y, float w, float h, float u, float v, float uw, float vh)\n{\n\tgTexCoordBuffer[0] = gTexCoordBuffer[6] = u;\n\tgTexCoordBuffer[1] = gTexCoordBuffer[3] = v;\n\tgTexCoordBuffer[2] = gTexCoordBuffer[4] = u+uw;\n\tgTexCoordBuffer[5] = gTexCoordBuffer[7] = v+vh;\n\n\tgVertexBuffer[0] = gVertexBuffer[9] = x;\n\tgVertexBuffer[1] = gVertexBuffer[4] = y;\n\tgVertexBuffer[3] = gVertexBuffer[6] = x+w;\n\tgVertexBuffer[7] = gVertexBuffer[10] = y+h;\n\tgVertexBuffer[2] = gVertexBuffer[5] = gVertexBuffer[8] = gVertexBuffer[11] = 0.5f;\n\t\t\n\tvglVertexAttribPointerMapped(0, gVertexBuffer);\n\tvglVertexAttribPointerMapped(1, gTexCoordBuffer);\n\tgVertexBuffer += 12;\n\tgTexCoordBuffer += 8;\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n}\n\n/*\n================\nDraw_Character\n\nDraws one 8*8 graphics character with 0 being transparent.\nIt can be clipped to the top of the screen to allow the console to be\nsmoothly scrolled off.\n================\n*/\nvoid Draw_Character (int x, int y, int num)\n{\n\tint\t\t\t\trow, col;\n\tfloat\t\t\tfrow, fcol, size;\n\n\tif (num == 0x20)\n\t\treturn;\t\t// space\n\n\tnum &= 255;\n\t\n\tif (y <= -8)\n\t\treturn;\t\t\t// totally off screen\n\n\trow = num>>4;\n\tcol = num&15;\n\n\tfrow = row*0.0625;\n\tfcol = col*0.0625;\n\tsize = 0.0625;\n\t\n\tGL_Bind (char_texture);\n\n\tDrawQuad(x, y, 8, 8, fcol, frow, size, size);\n}\n\n/*\n================\nDraw_String\n================\n*/\nvoid Draw_String (int x, int y, const char *str, int delta)\n{\n\tGL_Bind (char_texture);\n\tfloat *str_vbuffer = gVertexBuffer;\n\tfloat *str_tbuffer = gTexCoordBuffer;\n\tint num_vertices = 0;\n\t\n\twhile (*str)\n\t{\n\t\tint num = (*str) + delta;\n\t\tint\trow, col;\n\t\tfloat frow, fcol, size;\n\n\t\tif (num != 0x20) {\n\t\t\tnum &= 255;\n\t\t\tif (y > -8) {\n\t\t\t\trow = num>>4;\n\t\t\t\tcol = num&15;\n\n\t\t\t\tfrow = row*0.0625;\n\t\t\t\tfcol = col*0.0625;\n\t\t\t\tsize = 0.0625;\n\t\t\t\t\n\t\t\t\tgVertexBuffer[0] = gVertexBuffer[3] = gVertexBuffer[9] = x;\n\t\t\t\tgVertexBuffer[1] = gVertexBuffer[10] = gVertexBuffer[13] = y;\n\t\t\t\tgVertexBuffer[4] = gVertexBuffer[7] = gVertexBuffer[16] = y + 8;\n\t\t\t\tgVertexBuffer[6] = gVertexBuffer[12] = gVertexBuffer[15] = x + 8;\n\t\t\t\tgVertexBuffer[2] = gVertexBuffer[5] = gVertexBuffer[8] = gVertexBuffer[11] = gVertexBuffer[14] = gVertexBuffer[17] = 0.5f;\n\t\t\t\t\n\t\t\t\tgTexCoordBuffer[0] = gTexCoordBuffer[2] = gTexCoordBuffer[6] = fcol;\n\t\t\t\tgTexCoordBuffer[1] = gTexCoordBuffer[7] = gTexCoordBuffer[9] = frow;\n\t\t\t\tgTexCoordBuffer[3] = gTexCoordBuffer[5] = gTexCoordBuffer[11] = frow+size;\n\t\t\t\tgTexCoordBuffer[4] = gTexCoordBuffer[8] = gTexCoordBuffer[10] = fcol+size;\n\t\t\n\t\t\t\tgVertexBuffer += 18;\n\t\t\t\tgTexCoordBuffer += 12;\n\t\t\t\tnum_vertices += 6;\n\t\t\t}\n\t\t}\n\n\t\tstr++;\n\t\tx += 8;\n\t}\n\t\n\tif (num_vertices > 0) {\n\t\tvglVertexAttribPointerMapped(0, str_vbuffer);\n\t\tvglVertexAttribPointerMapped(1, str_tbuffer);\n\t\tGL_DrawPolygon(GL_TRIANGLES, num_vertices);\n\t}\n}\n\n/*\n================\nBatch_Character\n================\n*/\nint batched_vertices = 0;\nfloat *batched_vbuffer = NULL;\nfloat *batched_tbuffer = NULL;\nint is_batching = 0;\nvoid Batch_Character (int x, int y, int num) {\n\tif (!is_batching) {\n\t\tis_batching = 1;\n\t\tbatched_vbuffer = gVertexBuffer;\n\t\tbatched_tbuffer = gTexCoordBuffer;\n\t}\n\n\tint\t\t\t\trow, col;\n\tfloat\t\t\tfrow, fcol, size;\n\n\tif (num == 0x20)\n\t\treturn;\t\t// space\n\n\tnum &= 255;\n\t\n\tif (y <= -8)\n\t\treturn;\t\t\t// totally off screen\n\n\trow = num>>4;\n\tcol = num&15;\n\n\tfrow = row*0.0625;\n\tfcol = col*0.0625;\n\tsize = 0.0625;\n\t\n\tgVertexBuffer[0] = gVertexBuffer[3] = gVertexBuffer[9] = x;\n\tgVertexBuffer[1] = gVertexBuffer[10] = gVertexBuffer[13] = y;\n\tgVertexBuffer[4] = gVertexBuffer[7] = gVertexBuffer[16] = y + 8;\n\tgVertexBuffer[6] = gVertexBuffer[12] = gVertexBuffer[15] = x + 8;\n\tgVertexBuffer[2] = gVertexBuffer[5] = gVertexBuffer[8] = gVertexBuffer[11] = gVertexBuffer[14] = gVertexBuffer[17] = 0.5f;\n\t\t\t\t\n\tgTexCoordBuffer[0] = gTexCoordBuffer[2] = gTexCoordBuffer[6] = fcol;\n\tgTexCoordBuffer[1] = gTexCoordBuffer[7] = gTexCoordBuffer[9] = frow;\n\tgTexCoordBuffer[3] = gTexCoordBuffer[5] = gTexCoordBuffer[11] = frow+size;\n\tgTexCoordBuffer[4] = gTexCoordBuffer[8] = gTexCoordBuffer[10] = fcol+size;\n\t\t\n\tgVertexBuffer += 18;\n\tgTexCoordBuffer += 12;\n\tbatched_vertices += 6;\n}\n\n/*\n================\nBatch_String\n================\n*/\nvoid Batch_String (int x, int y, const char *str, int delta) {\t\n\tif (!is_batching) {\n\t\tis_batching = 1;\n\t\tbatched_vbuffer = gVertexBuffer;\n\t\tbatched_tbuffer = gTexCoordBuffer;\n\t}\n\t\n\twhile (*str)\n\t{\n\t\tint num = (*str) + delta;\n\t\tint\trow, col;\n\t\tfloat frow, fcol, size;\n\n\t\tif (num != 0x20) {\n\t\t\tnum &= 255;\n\t\t\tif (y > -8) {\n\t\t\t\trow = num>>4;\n\t\t\t\tcol = num&15;\n\n\t\t\t\tfrow = row*0.0625;\n\t\t\t\tfcol = col*0.0625;\n\t\t\t\tsize = 0.0625;\n\t\t\t\t\n\t\t\t\tgVertexBuffer[0] = gVertexBuffer[3] = gVertexBuffer[9] = x;\n\t\t\t\tgVertexBuffer[1] = gVertexBuffer[10] = gVertexBuffer[13] = y;\n\t\t\t\tgVertexBuffer[4] = gVertexBuffer[7] = gVertexBuffer[16] = y + 8;\n\t\t\t\tgVertexBuffer[6] = gVertexBuffer[12] = gVertexBuffer[15] = x + 8;\n\t\t\t\tgVertexBuffer[2] = gVertexBuffer[5] = gVertexBuffer[8] = gVertexBuffer[11] = gVertexBuffer[14] = gVertexBuffer[17] = 0.5f;\n\t\t\t\t\n\t\t\t\tgTexCoordBuffer[0] = gTexCoordBuffer[2] = gTexCoordBuffer[6] = fcol;\n\t\t\t\tgTexCoordBuffer[1] = gTexCoordBuffer[7] = gTexCoordBuffer[9] = frow;\n\t\t\t\tgTexCoordBuffer[3] = gTexCoordBuffer[5] = gTexCoordBuffer[11] = frow+size;\n\t\t\t\tgTexCoordBuffer[4] = gTexCoordBuffer[8] = gTexCoordBuffer[10] = fcol+size;\n\t\t\n\t\t\t\tgVertexBuffer += 18;\n\t\t\t\tgTexCoordBuffer += 12;\n\t\t\t\tbatched_vertices += 6;\n\t\t\t}\n\t\t}\n\n\t\tstr++;\n\t\tx += 8;\n\t}\n}\n\n/*\n================\nDraw_Batched\n================\n*/\nvoid Draw_Batched() {\n\tif (batched_vertices > 0) {\n\t\tGL_Bind (char_texture);\n\t\tvglVertexAttribPointerMapped(0, batched_vbuffer);\n\t\tvglVertexAttribPointerMapped(1, batched_tbuffer);\n\t\tGL_DrawPolygon(GL_TRIANGLES, batched_vertices);\n\t\tbatched_vertices = 0;\n\t}\n\t\n\tis_batching = 0;\n}\n\n/*\n================\nDraw_DebugChar\n\nDraws a single character directly to the upper right corner of the screen.\nThis is for debugging lockups by drawing different chars in different parts\nof the code.\n================\n*/\nvoid Draw_DebugChar (signed char num)\n{\n}\n\nvoid Draw_Crosshair(void)\n{\n\tGL_SetCanvas (CANVAS_CROSSHAIR);\n\n\tif (crosshair.value == 2) {\n\t\tGL_EnableState(GL_MODULATE);\n\t\tGL_Bind (cs_texture);\n\t\tGL_Color(crosshaircolor_r.value, crosshaircolor_g.value, crosshaircolor_b.value, 1);\n\t\tDrawQuad(-6, -6, 12, 12, 0, 0, 1, 1);\n\t\tGL_EnableState(GL_REPLACE);\n\t}\n\telse if (crosshair.value)\n\t\tDraw_Character(-4, -4, '+');\n\t\n\t\n}\n\n/*\n=============\nDraw_AlphaPic\n=============\n*/\nvoid Draw_AlphaPic (int x, int y, qpic_t *pic, float alpha)\n{\n\tbyte\t\t\t*dest, *source;\n\tunsigned short\t*pusdest;\n\tint\t\t\t\tv, u;\n\tglpic_t\t\t\t*gl;\n\n\tif (alpha == 0.0f) return;\n\tif (scrap_dirty)\n\t\tScrap_Upload ();\n\tgl = (glpic_t *)pic->data;\n\tGL_DisableState(GL_ALPHA_TEST);\n\tGL_EnableState(GL_MODULATE);\n\tglEnable (GL_BLEND);\n\tGL_Color(1,1,1,alpha);\n\tGL_Bind (gl->texnum);\n\tDrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);\n\tGL_Color(1,1,1,1);\n\tGL_EnableState(GL_ALPHA_TEST);\n\tglDisable (GL_BLEND);\n\tglDepthMask(GL_TRUE);\n}\n\n\n/*\n=============\nDraw_Pic\n=============\n*/\nvoid Draw_Pic (int x, int y, qpic_t *pic)\n{\n\tbyte\t\t\t*dest, *source;\n\tunsigned short\t*pusdest;\n\tint\t\t\t\tv, u;\n\tglpic_t\t\t\t*gl = (glpic_t *)pic->data;\n\n\tif (scrap_dirty)\n\t\tScrap_Upload ();\n\n\tGL_Color(1, 1, 1, 1);\n\tGL_Bind (gl->texnum);\n\n\tDrawQuad(x, y, pic->width, pic->height, gl->sl, gl->tl, gl->sh - gl->sl, gl->th - gl->tl);\n}\n\n\n/*\n=============\nDraw_TransPic\n=============\n*/\nvoid Draw_TransPic (int x, int y, qpic_t *pic)\n{\n\tbyte\t*dest, *source, tbyte;\n\tunsigned short\t*pusdest;\n\tint\t\t\t\tv, u;\n\n\tif (x < 0 || (unsigned)(x + pic->width) > vid.width || y < 0 ||\n\t\t (unsigned)(y + pic->height) > vid.height)\n\t{\n\t\tSys_Error (\"Draw_TransPic: bad coordinates\");\n\t}\n\t\n\tDraw_Pic (x, y, pic);\n}\n\n\n/*\n=============\nDraw_TransPicTranslate\n\nOnly used for the player color selection menu\n=============\n*/\nvoid Draw_TransPicTranslate (int x, int y, qpic_t *pic, byte *translation)\n{\n\tint\t\t\t\tv, u, c;\n\tunsigned\t\ttrans[64*64], *dest;\n\tbyte\t\t\t*src;\n\tint\t\t\t\tp;\n\n\tGL_Bind (translate_texture);\n\n\tc = pic->width * pic->height;\n\n\tdest = trans;\n\tfor (v=0 ; v<64 ; v++, dest += 64)\n\t{\n\t\tsrc = &menuplyr_pixels[ ((v*pic->height)>>6) *pic->width];\n\t\tfor (u=0 ; u<64 ; u++)\n\t\t{\n\t\t\tp = src[(u*pic->width)>>6];\n\t\t\tif (p == 255)\n\t\t\t\tdest[u] = p;\n\t\t\telse\n\t\t\t\tdest[u] =  d_8to24table[translation[p]];\n\t\t}\n\t}\n\t\n\tglTexImage2D (GL_TEXTURE_2D, 0, gl_compress.value ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : gl_alpha_format, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\n\tGL_Color(1,1,1,1);\n\tDrawQuad(x, y, pic->width, pic->height, 0, 0, 1, 1);\n}\n\n\n/*\n================\nDraw_ConsoleBackground\n\n================\n*/\nvoid Draw_ConsoleBackground (void)\n{\n\n\tGL_SetCanvas (CANVAS_CONSOLE);\n\t\n\tif (scr_conalpha.value > 0.0f) {\n\t\tif (scr_conalpha.value < 1.0f)\n\t\t\tDraw_Pic(0, 0, conback);\n\t\telse\n\t\t\tDraw_AlphaPic(0, 0, conback, scr_conalpha.value);\n\t}\n\n}\n\n\n/*\n=============\nDraw_TileClear\n\nThis repeats a 64*64 tile graphic to fill the screen around a sized down\nrefresh window.\n=============\n*/\ntypedef union ByteToInt_t {\n    byte b[4];\n    int i;\n} ByteToInt;\n\nvoid Draw_TileClear (int x, int y, int w, int h)\n{\n\tGL_Color(1,1,1,1);\n\tByteToInt b;\n\tmemcpy(b.b, draw_backtile->data, sizeof(b.b));\n\tGL_Bind (b.i);\n\tDrawQuad(x, y, w, h, x/64.0, y/64.0, w/64.0, h/64.0);\n}\n\n\n/*\n=============\nDraw_Fill\n\nFills a box of pixels with a single color\n=============\n*/\nvoid Draw_Fill (int x, int y, int w, int h, int c)\n{\n\tDrawQuad_NoTex(x, y, w, h, host_basepal[c*3]/255.0, host_basepal[c*3+1]/255.0, host_basepal[c*3+2]/255.0, 1);\n\tGL_Color(1,1,1,1);\n}\n//=============================================================================\n\n/*\n================\nDraw_FadeScreen\n\n================\n*/\nvoid Draw_FadeScreen (void)\n{\n\tGL_SetCanvas (CANVAS_DEFAULT);\n\t\n\tglEnable (GL_BLEND);\n\tDrawQuad_NoTex(0, 0, vid.width, vid.height, 0, 0, 0, 0.8f);\n\tGL_Color(1,1,1,1);\n\tglDisable (GL_BLEND);\n\n\tSbar_Changed();\n}\n\n//=============================================================================\n\n/*\n================\nGL_Set2D\n\nSetup as if the screen was 320*200\n================\n*/\nvoid GL_Set2D (void)\n{\n\tcurrentcanvas = -1;\n\tGL_SetCanvas (CANVAS_DEFAULT);\n\n\tglDisable (GL_DEPTH_TEST);\n\tglDisable (GL_CULL_FACE);\n\tglDisable (GL_BLEND);\n\tGL_EnableState(GL_ALPHA_TEST);\n\n\tGL_Color(1,1,1,1);\n}\n\n//====================================================================\n\n/*\n================\nGL_ResampleTexture\n================\n*/\nvoid GL_ResampleTexture (unsigned *in, int inwidth, int inheight, unsigned *out,  int outwidth, int outheight)\n{\n\tint\t\ti, j;\n\tunsigned\t*inrow;\n\tunsigned\tfrac, fracstep;\n\n\tfracstep = inwidth*0x10000/outwidth;\n\tfor (i=0 ; i<outheight ; i++, out += outwidth)\n\t{\n\t\tinrow = in + inwidth*(i*inheight/outheight);\n\t\tfrac = fracstep >> 1;\n\t\tfor (j=0 ; j<outwidth ; j+=4)\n\t\t{\n\t\t\tout[j] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+1] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+2] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+3] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t}\n\t}\n}\n\n/*\n================\nGL_Resample8BitTexture -- JACK\n================\n*/\nvoid GL_Resample8BitTexture (unsigned char *in, int inwidth, int inheight, unsigned char *out,  int outwidth, int outheight)\n{\n\tint\t\ti, j;\n\tunsigned\tchar *inrow;\n\tunsigned\tfrac, fracstep;\n\n\tfracstep = inwidth*0x10000/outwidth;\n\tfor (i=0 ; i<outheight ; i++, out += outwidth)\n\t{\n\t\tinrow = in + inwidth*(i*inheight/outheight);\n\t\tfrac = fracstep >> 1;\n\t\tfor (j=0 ; j<outwidth ; j+=4)\n\t\t{\n\t\t\tout[j] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+1] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+2] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+3] = inrow[frac>>16];\n\t\t\tfrac += fracstep;\n\t\t}\n\t}\n}\n\n\n/*\n================\nGL_MipMap\n\nOperates in place, quartering the size of the texture\n================\n*/\nvoid GL_MipMap (byte *in, int width, int height)\n{\n\tint\t\ti, j;\n\tbyte\t*out;\n\n\twidth <<=2;\n\theight >>= 1;\n\tout = in;\n\tfor (i=0 ; i<height ; i++, in+=width)\n\t{\n\t\tfor (j=0 ; j<width ; j+=8, out+=4, in+=8)\n\t\t{\n\t\t\tout[0] = (in[0] + in[4] + in[width+0] + in[width+4])>>2;\n\t\t\tout[1] = (in[1] + in[5] + in[width+1] + in[width+5])>>2;\n\t\t\tout[2] = (in[2] + in[6] + in[width+2] + in[width+6])>>2;\n\t\t\tout[3] = (in[3] + in[7] + in[width+3] + in[width+7])>>2;\n\t\t}\n\t}\n}\n\n/*\n================\nGL_MipMap8Bit\n\nMipping for 8 bit textures\n================\n*/\nvoid GL_MipMap8Bit (byte *in, int width, int height)\n{\n\tint\t\ti, j;\n\tunsigned short     r,g,b;\n\tbyte\t*out, *at1, *at2, *at3, *at4;\n\n//\twidth <<=2;\n\theight >>= 1;\n\tout = in;\n\tfor (i=0 ; i<height ; i++, in+=width)\n\t{\n\t\tfor (j=0 ; j<width ; j+=2, out+=1, in+=2)\n\t\t{\n\t\t\tat1 = (byte *) (d_8to24table + in[0]);\n\t\t\tat2 = (byte *) (d_8to24table + in[1]);\n\t\t\tat3 = (byte *) (d_8to24table + in[width+0]);\n\t\t\tat4 = (byte *) (d_8to24table + in[width+1]);\n\n \t\t\tr = (at1[0]+at2[0]+at3[0]+at4[0]); r>>=5;\n \t\t\tg = (at1[1]+at2[1]+at3[1]+at4[1]); g>>=5;\n \t\t\tb = (at1[2]+at2[2]+at3[2]+at4[2]); b>>=5;\n\n\t\t\tout[0] = d_15to8table[(r<<0) + (g<<5) + (b<<10)];\n\t\t}\n\t}\n}\n\n/*\n===============\nGL_Upload32\n===============\n*/\nvoid GL_Upload32 (unsigned *data, int width, int height,  bool mipmap, bool alpha)\n{\n\tif (!gl_mipmap.value) mipmap = false;\n\tint\t\t\tsamples;\n\tstatic unsigned int scaled[2048*2048];\t// [512*256];\n\tint\t\t\tscaled_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\t\n\tscaled_width >>= (int)gl_picmip.value;\n\tscaled_height >>= (int)gl_picmip.value;\n\n\tif (scaled_width > gl_max_size.value)\n\t\tscaled_width = gl_max_size.value;\n\tif (scaled_height > gl_max_size.value)\n\t\tscaled_height = gl_max_size.value;\n\n\tif (scaled_width * scaled_height > sizeof(scaled)/4)\n\t\tSys_Error (\"GL_LoadTexture: too big\");\n\n\tif (gl_compress.value) {\n\t\tsamples = alpha ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;\n\t\tmipmap = false; // Compressed textures do not support mipmaps yet in vitaGL\n\t} else samples = alpha ? gl_alpha_format : gl_solid_format;\n\n\ttexels += scaled_width * scaled_height;\n\n\tif (scaled_width == width && scaled_height == height)\n\t{\n\t\tif (!mipmap)\n\t\t{\n\t\t\tglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n\t\t\tgoto done;\n\t\t}\n\t\tmemcpy (scaled, data, width*height*4);\n\t}\n\telse\n\t\tGL_ResampleTexture (data, width, height, scaled, scaled_width, scaled_height);\n\t\n\tglTexImage2D (GL_TEXTURE_2D, 0, samples, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, scaled);\n\tif (mipmap) glGenerateMipmap(GL_TEXTURE_2D);\n\t\ndone: ;\n\t\n\tif (mipmap)\n\t{\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_min);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\t}\n\telse\n\t{\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gl_filter_max);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gl_filter_max);\n\t}\n\t\n}\n\n/*\n===============\nGL_Upload8\n===============\n*/\nvoid GL_Upload8 (byte *data, int width, int height,  bool mipmap, bool alpha)\n{\nstatic\tunsigned\ttrans[640*480];\t\t// FIXME, temporary\n\tint\t\t\ti, s;\n\tbool\tnoalpha;\n\tint\t\t\tp;\n\n\ts = width*height;\n\t// if there are no transparent pixels, make it a 3 component\n\t// texture even if it was specified as otherwise\n\tif (alpha)\n\t{\n\t\tnoalpha = true;\n\t\tfor (i=0 ; i<s ; i++)\n\t\t{\n\t\t\tp = data[i];\n\t\t\tif (p == 255)\n\t\t\t\tnoalpha = false;\n\t\t\ttrans[i] = d_8to24table[p];\n\t\t}\n\n\t\tif (alpha && noalpha)\n\t\t\talpha = false;\n\t}\n\telse\n\t{\n\t\tif (s&3)\n\t\t\tSys_Error (\"GL_Upload8: s&3\");\n\t\tfor (i=0 ; i<s ; i+=4)\n\t\t{\n\t\t\ttrans[i] = d_8to24table[data[i]];\n\t\t\ttrans[i+1] = d_8to24table[data[i+1]];\n\t\t\ttrans[i+2] = d_8to24table[data[i+2]];\n\t\t\ttrans[i+3] = d_8to24table[data[i+3]];\n\t\t}\n\t}\n\n\tGL_Upload32 (trans, width, height, mipmap, alpha);\n}\n\n/*\n================\nGL_LoadTexture\n================\n*/\nint GL_LoadTexture (const char *identifier, int width, int height, byte *data, bool mipmap, bool alpha)\n{\n\tbool\tnoalpha;\n\tint\t\t\ti, p, s;\n\tgltexture_t\t*glt;\n\n\t// see if the texture is already present\n\tif (identifier[0])\n\t{\n\t\tfor (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)\n\t\t{\n\t\t\tif (!strcmp (identifier, glt->identifier))\n\t\t\t{\n\t\t\t\t// FIXME: Caching is broken with external textures\n\t\t\t\t//if (width != glt->width || height != glt->height)\n\t\t\t\t//\tSys_Error (\"GL_LoadTexture32: cache mismatch for %s, expected: %ld, got %d\", identifier, width, glt->width);\n\t\t\t\treturn gltextures[i].texnum;\n\t\t\t}\n\t\t}\n\t}\n\t//else {                                    // 13/02/2000 removed: M.Tretene\n\t\tglt = &gltextures[numgltextures];\n\t\tnumgltextures++;\n\t//}\n\n\tstrcpy (glt->identifier, identifier);\n\tglt->texnum = texture_extension_number;\n\tglt->width = width;\n\tglt->height = height;\n\tglt->mipmap = mipmap;\n\n\tGL_Bind(texture_extension_number );\n\t\n\tif (tex_cache)\n\t\ttextureStore::get()->create(width, height, data, mipmap, alpha, false);\n\telse\n\t\tGL_Upload8 (data, width, height, mipmap, alpha);\n\n\ttexture_extension_number++;\n\n\treturn texture_extension_number-1;\n}\n\n/*\n================\nGL_LoadTexture32\n================\n*/\nint GL_LoadTexture32 (const char *identifier, int width, int height, byte *data, bool mipmap, bool alpha, bool fullbright)\n{\n\tbool\tnoalpha;\n\tint\t\t\ti, p, s;\n\tgltexture_t\t*glt;\n\n\t// see if the texture is already present\n\tif (identifier[0])\n\t{\n\t\tfor (i=0, glt=gltextures ; i<numgltextures ; i++, glt++)\n\t\t{\n\t\t\tif (!strcmp (identifier, glt->identifier))\n\t\t\t{\n\t\t\t\tif (width != glt->width || height != glt->height)\n\t\t\t\t\tSys_Error (\"GL_LoadTexture32: cache mismatch for %s, expected: %ld, got %d\", identifier, width, glt->width);\n\t\t\t\treturn gltextures[i].texnum;\n\t\t\t}\n\t\t}\n\t}\n\t//else {                                    // 13/02/2000 removed: M.Tretene\n\t\tglt = &gltextures[numgltextures];\n\t\tnumgltextures++;\n\t//}\n\t\n\t// Make black pixels transparent for *_luma textures\n\tif (fullbright) {\n\t\tint cnt = width * height * 4;\n\t\tfor (i=0; i<cnt; i+=4) {\n\t\t\tif (data[i] < 1 && data[i+1] < 1 && data[i+2] < 1)\n\t\t\t\tdata[i+3] = 0;\n\t\t}\n\t}\n\t\n\tstrcpy (glt->identifier, identifier);\n\tglt->texnum = texture_extension_number;\n\tglt->width = width;\n\tglt->height = height;\n\tglt->mipmap = mipmap;\n\t\n\tGL_Bind(texture_extension_number );\n\t\n\tif (tex_cache)\n\t\ttextureStore::get()->create(width, height, data, mipmap, alpha, true);\n\telse\n\t\tGL_Upload32 ((unsigned*)data, width, height, mipmap, alpha);\n\t\n\ttexture_extension_number++;\n\n\treturn texture_extension_number-1;\n}\n\n/****************************************/\n\nstatic GLenum oldtarget = 0; // KH\n\n// Benchmark\nint max_fps = 0;\nint average_fps = 0; // TODO: Add this\nint min_fps = 999;\nextern \"C\"{\nextern bool bBenchmarkStarted;\n};\nbool bBlinkBenchmark;\n\nvoid GL_DrawBenchmark(void)\n{\n\tstatic double lastframetime;\n\tdouble t;\n\textern int fps_count;\n\tstatic int lastfps;\n\tint x, y;\n\tchar st[80],st2[80],st3[80],st4[80];\n\n\tt = Sys_FloatTime ();\n\n\tif ((t - lastframetime) >= 1.0) {\n\t\tlastfps = fps_count;\n\t\tfps_count = 0;\n\t\tlastframetime = t;\n\t\tbBlinkBenchmark = !bBlinkBenchmark;\n\t}\n\n\tsprintf(st,  \"Current: %3d\", lastfps);\n\n\tif (bBenchmarkStarted)\n\t{\n\t\tif (lastfps > max_fps) max_fps = lastfps;\n\t\tif (lastfps < min_fps) min_fps = lastfps;\n\t\tsprintf(st2, \"    Max: %3d\", max_fps);\n\t\tsprintf(st3, \"    Min: %3d\", min_fps);\t// <-- Dat Result really feels cheated\n\t}\n\n\tx = 320 - strlen(st) * 8 - 16;\n\tGL_SetCanvas (CANVAS_TOPRIGHT);\n\tBatch_String(x, 2, st, 0);\n\tBatch_String(x, 10, st2, 0);\n\tBatch_String(x, 18, st3, 0);\n\tDraw_Batched();\n\t\n\tif (bBlinkBenchmark) {\t// Neato messaji\n\t\tGL_SetCanvas (CANVAS_MENU);\n\t\tDraw_String(160 - 37 * 4, 200*0.25, \"Benchmark in progress, please wait...\", 0);\n\t}\n}\n\nvoid GL_DrawFPS(void){\n\textern cvar_t show_fps;\n\tstatic double lastframetime;\n\tdouble t;\n\textern int fps_count;\n\tstatic int lastfps;\n\tint x;\n\tchar st[80];\n\t\n\tif (!show_fps.value)\n\t\treturn;\n\n\tt = Sys_FloatTime ();\n\n\tif ((t - lastframetime) >= 1.0) {\n\t\tlastfps = fps_count;\n\t\tfps_count = 0;\n\t\tlastframetime = t;\n\n\t}\n\tsprintf(st, \"%3d FPS\", lastfps);\n\n\tx = 329 - strlen(st) * 8 - 16;\n\tGL_SetCanvas (CANVAS_TOPRIGHT);\n\tDraw_String(x, 2, st, 0);\n}\n\nvoid GL_SetCanvas (int newcanvas)\n{\n\textern vrect_t scr_vrect;\n\tfloat s;\n\tint lines;\n\t\n\tif (newcanvas == currentcanvas) return;\n\t\tcurrentcanvas = newcanvas;\n\t\n\tglMatrixMode(GL_PROJECTION);\n\tglLoadIdentity ();\n\t\n\tswitch(newcanvas)\n\t{\n\tcase CANVAS_DEFAULT:\n\t\tglOrtho (0, glwidth, glheight, 0, -99999, 99999);\n\t\tglViewport (glx, gly, glwidth, glheight);\n\t\tbreak;\n\tcase CANVAS_CONSOLE:\n\t\tlines = vid.conheight - (scr_con_current * vid.conheight / glheight);\n\t\tglOrtho (0, vid.conwidth, vid.conheight + lines, lines, -99999, 99999);\n\t\tglViewport (glx, gly, glwidth, glheight);\n\t\tbreak;\n\tcase CANVAS_MENU:\n\t\ts = fmin((float)glwidth / 320.0, (float)glheight / 200.0);\n\t\ts = Q_CLAMP (1.0, scr_menuscale.value, s);\n\t\t// ericw -- doubled width to 640 to accommodate long keybindings\n\t\tglOrtho (0, 640, 200, 0, -99999, 99999);\n\t\tglViewport (glx + (glwidth - 320*s) / 2, gly + (glheight - 200*s) / 2, 640*s, 200*s);\n\t\tbreak;\n\tcase CANVAS_SBAR:\n\t\ts = Q_CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);\n\t\tif (cl.gametype == GAME_DEATHMATCH)\n\t\t{\n\t\t\tglOrtho (0, glwidth / s, 48, 0, -99999, 99999);\n\t\t\tglViewport (glx, gly, glwidth, 48*s);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tglOrtho (0, 320, 48, 0, -99999, 99999);\n\t\t\tglViewport (glx + (glwidth - 320*s) / 2, gly, 320*s, 48*s);\n\t\t}\n\t\tbreak;\n\tcase CANVAS_CROSSHAIR: //0,0 is center of viewport\n\t\ts = Q_CLAMP (1.0, scr_crosshairscale.value, 10.0);\n\t\tglOrtho (scr_vrect.width/-2/s, scr_vrect.width/2/s, scr_vrect.height/2/s, scr_vrect.height/-2/s, -99999, 99999);\n\t\tglViewport (scr_vrect.x, glheight - scr_vrect.y - scr_vrect.height, scr_vrect.width & ~1, scr_vrect.height & ~1);\n\t\tbreak;\n\tcase CANVAS_TOPRIGHT: //used by fps\n\t\ts = 1;\n\t\tglOrtho (0, 320, 200, 0, -99999, 99999);\n\t\tglViewport (glx+glwidth-320*s, gly+glheight-200*s, 320*s, 200*s);\n\t\tbreak;\n\tdefault:\n\t\tSys_Error (\"GL_SetCanvas: bad canvas type\");\n\t}\n\n\tglMatrixMode(GL_MODELVIEW);\n\tglLoadIdentity ();\n}\n"
  },
  {
    "path": "source/gl_fullbright.c",
    "content": "//gl_fullbright.c\n#include \"quakedef.h\"\n\nextern void DrawGLPoly (glpoly_t *p);\n\nint FindFullbrightTexture (byte *pixels, int num_pix)\n{\n\tint i;\n\tfor (i = 0; i < num_pix; i++)\n\tif (pixels[i] > 223)\n\t\treturn 1;\n\treturn 0;\n}\n\nvoid ConvertPixels (byte *pixels, int num_pixels)\n{\n\tint i;\n\tfor (i = 0; i < num_pixels; i++)\n\t\tif (pixels[i] < 224)\n\t\t\tpixels[i] = 255;\n}\n\nvoid DrawFullBrightTextures (msurface_t *first_surf, int num_surfs)\n{\n\tint i;\n\tmsurface_t *fa;\n\ttexture_t *t;\n\tif (r_fullbright.value)\n\t\treturn;\n\t\n\tglEnable (GL_BLEND);\n\t\n\tfor (fa = first_surf, i = 0; i < num_surfs; fa++, i++)\n\t{\n\t\t// find the correct texture\n\t\tt = R_TextureAnimation (fa->texinfo->texture);\n\t\tif (t->fullbright != -1 && fa->draw_this_frame)\n\t\t{\n\t\t\tif (t->luma) glBlendFunc (GL_ONE, GL_ONE);\n\t\t\telse glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\t\tGL_Bind (t->fullbright);\n\t\t\tDrawGLPoly (fa->polys);\n\t\t}\n\t\tfa->draw_this_frame = 0;\n\t}\n\t\n\tglDisable (GL_BLEND);\n\tglBlendFunc (GL_ZERO, GL_SRC_COLOR);\n}\n"
  },
  {
    "path": "source/gl_fullbright.h",
    "content": "//gl_fullbright.h\n#include \"gl_model.h\"\nint FindFullbrightTexture (byte *pixels, int num_pix);\nvoid DrawFullBrightTextures (msurface_t *first_surf, int num_surfs);\nvoid ConvertPixels (byte *pixels, int num_pixels);"
  },
  {
    "path": "source/gl_mesh.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// gl_mesh.c: triangle model functions\n\n#include \"quakedef.h\"\n\n/*\n=================================================================\n\nALIAS MODEL DISPLAY LIST GENERATION\n\n=================================================================\n*/\n\nmodel_t\t\t*aliasmodel;\naliashdr_t\t*paliashdr;\n\nint \tused[8192];\n\n// the command list holds counts and s/t values that are valid for\n// every frame\nint\t\tcommands[8192];\nint\t\tnumcommands;\n\n// all frames will have their vertexes rearranged and expanded\n// so they are in the order expected by the command list\nint\t\tvertexorder[8192];\nint\t\tnumorder;\n\nint\t\tallverts, alltris;\n\nint\t\tstripverts[128];\nint\t\tstriptris[128];\nint\t\tstripcount;\n\n/*\n================\nStripLength\n================\n*/\nstatic int\tStripLength (int starttri, int startv)\n{\n\tint\t\t\tm1, m2;\n\tint\t\t\tj;\n\tmtriangle_t\t*last, *check;\n\tint\t\t\tk;\n\n\tused[starttri] = 2;\n\n\tlast = &triangles[starttri];\n\n\tstripverts[0] = last->vertindex[(startv)%3];\n\tstripverts[1] = last->vertindex[(startv+1)%3];\n\tstripverts[2] = last->vertindex[(startv+2)%3];\n\n\tstriptris[0] = starttri;\n\tstripcount = 1;\n\n\tm1 = last->vertindex[(startv+2)%3];\n\tm2 = last->vertindex[(startv+1)%3];\n\n\t// look for a matching triangle\nnexttri:\n\tfor (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)\n\t{\n\t\tif (check->facesfront != last->facesfront)\n\t\t\tcontinue;\n\t\tfor (k=0 ; k<3 ; k++)\n\t\t{\n\t\t\tif (check->vertindex[k] != m1)\n\t\t\t\tcontinue;\n\t\t\tif (check->vertindex[ (k+1)%3 ] != m2)\n\t\t\t\tcontinue;\n\n\t\t\t// this is the next part of the fan\n\n\t\t\t// if we can't use this triangle, this tristrip is done\n\t\t\tif (used[j])\n\t\t\t\tgoto done;\n\n\t\t\t// the new edge\n\t\t\tif (stripcount & 1)\n\t\t\t\tm2 = check->vertindex[ (k+2)%3 ];\n\t\t\telse\n\t\t\t\tm1 = check->vertindex[ (k+2)%3 ];\n\n\t\t\tstripverts[stripcount+2] = check->vertindex[ (k+2)%3 ];\n\t\t\tstriptris[stripcount] = j;\n\t\t\tstripcount++;\n\n\t\t\tused[j] = 2;\n\t\t\tgoto nexttri;\n\t\t}\n\t}\ndone:\n\n\t// clear the temp used flags\n\tfor (j=starttri+1 ; j<pheader->numtris ; j++)\n\t\tif (used[j] == 2)\n\t\t\tused[j] = 0;\n\n\treturn stripcount;\n}\n\n/*\n===========\nFanLength\n===========\n*/\nstatic int\tFanLength (int starttri, int startv)\n{\n\tint\t\tm1, m2;\n\tint\t\tj;\n\tmtriangle_t\t*last, *check;\n\tint\t\tk;\n\n\tused[starttri] = 2;\n\n\tlast = &triangles[starttri];\n\n\tstripverts[0] = last->vertindex[(startv)%3];\n\tstripverts[1] = last->vertindex[(startv+1)%3];\n\tstripverts[2] = last->vertindex[(startv+2)%3];\n\n\tstriptris[0] = starttri;\n\tstripcount = 1;\n\n\tm1 = last->vertindex[(startv+0)%3];\n\tm2 = last->vertindex[(startv+2)%3];\n\n\n\t// look for a matching triangle\nnexttri:\n\tfor (j=starttri+1, check=&triangles[starttri+1] ; j<pheader->numtris ; j++, check++)\n\t{\n\t\tif (check->facesfront != last->facesfront)\n\t\t\tcontinue;\n\t\tfor (k=0 ; k<3 ; k++)\n\t\t{\n\t\t\tif (check->vertindex[k] != m1)\n\t\t\t\tcontinue;\n\t\t\tif (check->vertindex[ (k+1)%3 ] != m2)\n\t\t\t\tcontinue;\n\n\t\t\t// this is the next part of the fan\n\n\t\t\t// if we can't use this triangle, this tristrip is done\n\t\t\tif (used[j])\n\t\t\t\tgoto done;\n\n\t\t\t// the new edge\n\t\t\tm2 = check->vertindex[ (k+2)%3 ];\n\n\t\t\tstripverts[stripcount+2] = m2;\n\t\t\tstriptris[stripcount] = j;\n\t\t\tstripcount++;\n\n\t\t\tused[j] = 2;\n\t\t\tgoto nexttri;\n\t\t}\n\t}\ndone:\n\n\t// clear the temp used flags\n\tfor (j=starttri+1 ; j<pheader->numtris ; j++)\n\t\tif (used[j] == 2)\n\t\t\tused[j] = 0;\n\n\treturn stripcount;\n}\n\n\n/*\n================\nBuildTris\n\nGenerate a list of trifans or strips\nfor the model, which holds for all frames\n================\n*/\nstatic void BuildTris (void)\n{\n\tint\t\ti, j, k;\n\tint\t\tstartv;\n\tfloat  s, t;\n\tint\t\tlen, bestlen, besttype;\n\tint\t\tbestverts[1024];\n\tint\t\tbesttris[1024];\n\tint\t\ttype;\n\t\n\t//\n\t// build tristrips\n\t//\n\tbesttype = 0;\n\tnumorder = 0;\n\tnumcommands = 0;\n\tmemset (used, 0, sizeof(used));\n\tfor (i=0 ; i<pheader->numtris ; i++)\n\t{\n\t\t// pick an unused triangle and start the trifan\n\t\tif (used[i])\n\t\t\tcontinue;\n\n\t\tbestlen = 0;\n\t\tfor (type = 0 ; type < 2 ; type++)\n//\ttype = 1;\n\t\t{\n\t\t\tfor (startv =0 ; startv < 3 ; startv++)\n\t\t\t{\n\t\t\t\tif (type == 1)\n\t\t\t\t\tlen = StripLength (i, startv);\n\t\t\t\telse\n\t\t\t\t\tlen = FanLength (i, startv);\n\t\t\t\tif (len > bestlen)\n\t\t\t\t{\n\t\t\t\t\tbesttype = type;\n\t\t\t\t\tbestlen = len;\n\t\t\t\t\tfor (j=0 ; j<bestlen+2 ; j++)\n\t\t\t\t\t\tbestverts[j] = stripverts[j];\n\t\t\t\t\tfor (j=0 ; j<bestlen ; j++)\n\t\t\t\t\t\tbesttris[j] = striptris[j];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// mark the tris on the best strip as used\n\t\tfor (j=0 ; j<bestlen ; j++)\n\t\t\tused[besttris[j]] = 1;\n\n\t\tif (besttype == 1)\n\t\t\tcommands[numcommands++] = (bestlen+2);\n\t\telse\n\t\t\tcommands[numcommands++] = -(bestlen+2);\n\n\t\tfor (j=0 ; j<bestlen+2 ; j++)\n\t\t{\n\t\t\t// emit a vertex into the reorder buffer\n\t\t\tk = bestverts[j];\n\t\t\tvertexorder[numorder++] = k;\n\n\t\t\t// emit s/t coords into the commands stream\n\t\t\ts = stverts[k].s;\n\t\t\tt = stverts[k].t;\n\t\t\tif (!triangles[besttris[0]].facesfront && stverts[k].onseam)\n\t\t\t\ts += pheader->skinwidth / 2;\t// on back side\n\t\t\ts = (s + 0.5) / pheader->skinwidth;\n\t\t\tt = (t + 0.5) / pheader->skinheight;\n\n\t\t\t*(float *)&commands[numcommands++] = s;\n\t\t\t*(float *)&commands[numcommands++] = t;\n\t\t}\n\t}\n\n\tcommands[numcommands++] = 0;\t\t// end of list marker\n\n\tCon_DPrintf (\"%3i tri %3i vert %3i cmd\\n\", pheader->numtris, numorder, numcommands);\n\n\tallverts += numorder;\n\talltris += pheader->numtris;\n}\n\n\n/*\n================\nGL_MakeAliasModelDisplayLists\n================\n*/\nvoid GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr)\n{\n\tint i,j;\n\taliasmodel = m;\n\tpaliashdr = hdr;\t// (aliashdr_t *)Mod_Extradata (m);\n\n\tBuildTris ();\t\t// trifans or lists\n\t\n\t// save the data out\n\n\tpaliashdr->poseverts = numorder;\n\n\tint* cmds = (int*)Hunk_Alloc (numcommands * 4);\n\tpaliashdr->commands = (byte *)cmds - (byte *)paliashdr;\n\tmemcpy (cmds, commands, numcommands * 4);\n\n\ttrivertx_t* verts = (trivertx_t*)Hunk_Alloc (paliashdr->numposes * paliashdr->poseverts \n\t\t* sizeof(trivertx_t) );\n\tpaliashdr->posedata = (byte *)verts - (byte *)paliashdr;\n\tfor (i=0 ; i<paliashdr->numposes ; i++)\n\t\tfor (j=0 ; j<numorder ; j++)\n\t\t\t*verts++ = poseverts[i][vertexorder[j]];\n}\n\n"
  },
  {
    "path": "source/gl_model.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// models.c -- model loading and caching\n\n// models are the only shared resource between a client and server running\n// on the same machine.\n\n#include \"quakedef.h\"\n#include \"gl_fullbright.h\"\n\nextern void WAD3_LoadTextureWadFile (char *filename);\nextern byte *WAD3_LoadTexture(miptex_t *mt);\n\nmodel_t\t*loadmodel;\nchar\tloadname[32];\t// for hunk tags\nchar fbr_mask_name[64]; // for fullbrights\n\n\nvoid Mod_LoadSpriteModel (model_t *mod, void *buffer);\nvoid Mod_LoadBrushModel (model_t *mod, void *buffer);\nvoid Mod_LoadAliasModel (model_t *mod, void *buffer);\nmodel_t *Mod_LoadModel (model_t *mod, bool crash);\n\nbyte\tmod_novis[MAX_MAP_LEAFS/8];\n\n#define\tMAX_MOD_KNOWN\t512\nmodel_t\tmod_known[MAX_MOD_KNOWN];\nint\t\tmod_numknown;\n\nCVAR (gl_subdivide_size, 128, CVAR_ARCHIVE)\n\n/*\n===============\nMod_Init\n===============\n*/\nvoid Mod_Init (void)\n{\n\tCvar_RegisterVariable (&gl_subdivide_size);\n\tmemset (mod_novis, 0xff, sizeof(mod_novis));\n}\n\n/*\n===============\nMod_Init\n\nCaches the data if needed\n===============\n*/\nvoid *Mod_Extradata (model_t *mod)\n{\n\tvoid\t*r;\n\t\n\tr = Cache_Check (&mod->cache);\n\tif (r)\n\t\treturn r;\n\n\tMod_LoadModel (mod, true);\n\t\n\tif (!mod->cache.data)\n\t\tSys_Error (\"Mod_Extradata: caching failed\");\n\treturn mod->cache.data;\n}\n\n/*\n===============\nMod_PointInLeaf\n===============\n*/\nmleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)\n{\n\tmnode_t\t\t*node;\n\tfloat\t\td;\n\tmplane_t\t*plane;\n\t\n\tif (!model || !model->nodes)\n\t\tSys_Error (\"Mod_PointInLeaf: bad model\");\n\n\tnode = model->nodes;\n\twhile (1)\n\t{\n\t\tif (node->contents < 0)\n\t\t\treturn (mleaf_t *)node;\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\telse\n\t\t\tnode = node->children[1];\n\t}\n\t\n\treturn NULL;\t// never reached\n}\n\n\n/*\n===================\nMod_DecompressVis\n===================\n*/\nbyte *Mod_DecompressVis (byte *in, model_t *model)\n{\n\tstatic byte\tdecompressed[MAX_MAP_LEAFS/8];\n\tint\t\tc;\n\tbyte\t*out;\n\tint\t\trow;\n\n\trow = (model->numleafs+7)>>3;\t\n\tout = decompressed;\n\n\tif (!in)\n\t{\t// no vis info, so make all visible\n\t\twhile (row)\n\t\t{\n\t\t\t*out++ = 0xff;\n\t\t\trow--;\n\t\t}\n\t\treturn decompressed;\t\t\n\t}\n\n\tdo\n\t{\n\t\tif (*in)\n\t\t{\n\t\t\t*out++ = *in++;\n\t\t\tcontinue;\n\t\t}\n\t\n\t\tc = in[1];\n\t\tin += 2;\n\t\twhile (c)\n\t\t{\n\t\t\t*out++ = 0;\n\t\t\tc--;\n\t\t}\n\t} while (out - decompressed < row);\n\t\n\treturn decompressed;\n}\n\nbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)\n{\n\tif (leaf == model->leafs)\n\t\treturn mod_novis;\n\treturn Mod_DecompressVis (leaf->compressed_vis, model);\n}\n\n/*\n===================\nMod_ClearAll\n===================\n*/\nstatic byte *ent_file = NULL;\nvoid Mod_ClearAll (void)\n{\n\tint\t\ti;\n\tmodel_t\t*mod;\n\t\n\tfor (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)\n\t\tif (mod->type != mod_alias)\n\t\t\tmod->needload = true;\n\t\t\n\tent_file = NULL;\n}\n\nvoid Mod_ResetAll (void)\n{\n\tint\t\ti;\n\tmodel_t\t*mod;\n\t\n\tfor (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)\n\t{\n\t\tmemset(mod, 0, sizeof(model_t));\n\t}\n\tmod_numknown = 0;\n}\n\n/*\n==================\nMod_FindName\n\n==================\n*/\nmodel_t *Mod_FindName (char *name)\n{\n\tint\t\ti;\n\tmodel_t\t*mod;\n\t\n\tif (!name[0])\n\t\tSys_Error (\"Mod_ForName: NULL name\");\n\t\t\n//\n// search the currently loaded models\n//\n\tfor (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)\n\t\tif (!strcmp (mod->name, name) )\n\t\t\tbreak;\n\t\t\t\n\tif (i == mod_numknown)\n\t{\n\t\tif (mod_numknown == MAX_MOD_KNOWN)\n\t\t\tSys_Error (\"mod_numknown == MAX_MOD_KNOWN\");\n\t\tstrcpy (mod->name, name);\n\t\tmod->needload = true;\n\t\tmod_numknown++;\n\t}\n\n\treturn mod;\n}\n\n/*\n==================\nMod_TouchModel\n\n==================\n*/\nvoid Mod_TouchModel (char *name)\n{\n\tmodel_t\t*mod;\n\t\n\tmod = Mod_FindName (name);\n\t\n\tif (!mod->needload)\n\t{\n\t\tif (mod->type == mod_alias)\n\t\t\tCache_Check (&mod->cache);\n\t}\n}\n\n/*\n==================\nMod_LoadModel\n\nLoads a model into the cache\n==================\n*/\nmodel_t *Mod_LoadModel (model_t *mod, bool crash)\n{\n\tvoid\t*d;\n\tunsigned *buf;\n\tbyte\tstackbuf[1024];\t\t// avoid dirtying the cache heap\n\n\tif (!mod->needload)\n\t{\n\t\tif (mod->type == mod_alias)\n\t\t{\n\t\t\td = Cache_Check (&mod->cache);\n\t\t\tif (d)\n\t\t\t\treturn mod;\n\t\t}\n\t\telse\n\t\t\treturn mod;\t\t// not cached at all\n\t}\n\n//\n// because the world is so huge, load it one piece at a time\n//\n\tif (!crash)\n\t{\n\t\n\t}\n\t\n//\n// load the file\n//\n\tbuf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf), &mod->path_id);\n\tif (!buf)\n\t{\n\t\tif (crash)\n\t\t\tSys_Error (\"Mod_NumForName: %s not found\", mod->name);\n\t\treturn NULL;\n\t}\n\t\n//\n// allocate a new model\n//\n\tCOM_FileBase (mod->name, loadname);\n\t\n\tloadmodel = mod;\n\n//\n// fill it in\n//\n\n// call the apropriate loader\n\tmod->needload = false;\n\t\n\tswitch (LittleLong(*(unsigned *)buf))\n\t{\n\tcase IDPOLYHEADER:\n\t\tMod_LoadAliasModel (mod, buf);\n\t\tbreak;\n\t\t\n\tcase IDSPRITEHEADER:\n\t\tMod_LoadSpriteModel (mod, buf);\n\t\tbreak;\n\t\n\tdefault:\n\t\tMod_LoadBrushModel (mod, buf);\n\t\tbreak;\n\t}\n\n\treturn mod;\n}\n\n/*\n==================\nMod_ForName\n\nLoads in a model for the given name\n==================\n*/\nmodel_t *Mod_ForName (char *name, bool crash)\n{\n\tmodel_t\t*mod;\n\t\n\tmod = Mod_FindName (name);\n\t\n\treturn Mod_LoadModel (mod, crash);\n}\n\n\n/*\n===============================================================================\n\n\t\t\t\t\tBRUSHMODEL LOADING\n\n===============================================================================\n*/\n\nbyte\t*mod_base;\n\n\n/*\n=================\nMod_LoadTextures\n=================\n*/\nvoid Mod_LoadTextures (lump_t *l)\n{\n\tint\t\ti, j, pixels, num, max, altmax, fwidth, fheight;\n\tmiptex_t\t*mt;\n\ttexture_t\t*tx, *tx2;\n\ttexture_t\t*anims[10];\n\ttexture_t\t*altanims[10];\n\tdmiptexlump_t *m;\n\tchar filename[MAX_OSPATH], filename2[MAX_OSPATH], mapname[MAX_OSPATH];\n\n\tif (!l->filelen)\n\t{\n\t\tloadmodel->textures = NULL;\n\t\treturn;\n\t}\n\tm = (dmiptexlump_t *)(mod_base + l->fileofs);\n\t\n\tm->nummiptex = LittleLong (m->nummiptex);\n\t\n\tloadmodel->numtextures = m->nummiptex;\n\tloadmodel->textures = (texture_t**)Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);\n\n\tfor (i=0 ; i<m->nummiptex ; i++)\n\t{\n\t\tm->dataofs[i] = LittleLong(m->dataofs[i]);\n\t\tif (m->dataofs[i] == -1)\n\t\t\tcontinue;\n\t\tmt = (miptex_t *)((byte *)m + m->dataofs[i]);\n\t\tmt->width = LittleLong (mt->width);\n\t\tmt->height = LittleLong (mt->height);\n\t\tfor (j=0 ; j<MIPLEVELS ; j++)\n\t\t\tmt->offsets[j] = LittleLong (mt->offsets[j]);\n\t\t\n\t\tif ( (mt->width & 15) || (mt->height & 15) )\n\t\t\tSys_Error (\"Texture %s is not 16 aligned\", mt->name);\n\t\tpixels = mt->width*mt->height/64*85;\n\t\ttx = (texture_t*)Hunk_AllocName (sizeof(texture_t), loadname );\n\t\tloadmodel->textures[i] = tx;\n\n\t\tmemcpy (tx->name, mt->name, sizeof(tx->name));\n\t\ttx->width = mt->width;\n\t\ttx->height = mt->height;\n\t\tfor (j=0 ; j<MIPLEVELS ; j++)\n\t\t\ttx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);\n\n\t\t// ericw -- check for pixels extending past the end of the lump.\n\t\t// appears in the wild; e.g. jam2_tronyn.bsp (func_mapjam2),\n\t\t// kellbase1.bsp (quoth), and can lead to a segfault if we read past\n\t\t// the end of the .bsp file buffer\n\t\tif (((byte*)(mt+1) + pixels) > (mod_base + l->fileofs + l->filelen))\n\t\t{\n\t\t\tCon_DPrintf(\"Texture %s extends past end of lump\\n\", mt->name);\n\t\t\tpixels = max(0, (mod_base + l->fileofs + l->filelen) - (byte*)(mt+1));\n\t\t}\n\n\t\tif (loadmodel->bspversion != HL_BSPVERSION && (!strncmp(mt->name,\"sky\",3))) {\n\t\t\tR_InitSky (mt);\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (loadmodel->bspversion == HL_BSPVERSION) {\n\t\t\tbyte      *data;\n\t\t\tif ((data = WAD3_LoadTexture(mt))) {\n\t\t\t\t//com_netpath[0] = 0;      \n\t\t\t\t//alpha_flag = ISALPHATEX(tx->name) ? TEX_ALPHA : 0;\n\t\t\t\ttexture_mode = GL_LINEAR;\n\t\t\t\ttx->gl_texturenum = GL_LoadTexture32 (mt->name, tx->width, tx->height, data, true, false, false);\n\t\t\t\ttx->fullbright = -1;\n\t\t\t\tfree(data);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\t// External textures support for regular textures\n\t\ttx->fullbright = -1;\n\t\ttx->gl_texturenum = -1;\n\t\ttx->luma = false;\n\t\tCOM_StripExtension (loadmodel->name + 5, mapname);\n\t\tsnprintf(filename, sizeof(filename), \"textures/%s/%s%s\", mapname, tx->name[0] == '*' ? \"#\" : \"\", tx->name);\n\t\tbyte *data = Image_LoadImage (filename, &fwidth, &fheight);\n\t\tif (!data) {\n\t\t\tsnprintf(filename, sizeof(filename), \"textures/%s%s\", tx->name[0] == '*' ? \"#\" : \"\", tx->name);\n\t\t\tdata = Image_LoadImage (filename, &fwidth, &fheight);\n\t\t\tif (!data) {\n\t\t\t\tsnprintf(filename, sizeof(filename), \"textures/bmodels/%s%s\", tx->name[0] == '*' ? \"#\" : \"\", tx->name);\n\t\t\t\tdata = Image_LoadImage (filename, &fwidth, &fheight);\n\t\t\t}\n\t\t}\n\t\tif (data) {\n\t\t\ttx->gl_texturenum = GL_LoadTexture32 (mt->name, fwidth, fheight, data, true, tx->name[0] == '{', false);\n\t\t\tfree(data);\n\t\t\t\t\n\t\t\t// Fullbright\n\t\t\tsnprintf (filename2, sizeof(filename2), \"%s_luma\", filename);\n\t\t\tdata = Image_LoadImage (filename2, &fwidth, &fheight);\n\t\t\tif (!data) {\n\t\t\t\tsnprintf (filename2, sizeof(filename2), \"%s_glow\", filename);\n\t\t\t\tdata = Image_LoadImage (filename2, &fwidth, &fheight);\n\t\t\t}\n\t\t\tif (data) {\n\t\t\t\t// get a new name for the fullbright mask to avoid cache mismatches\n\t\t\t\tsprintf (fbr_mask_name, \"fullbright_mask_%s\", mt->name);\n\t\t\t\t// load the fullbright pixels version of the texture\n\t\t\t\ttx->fullbright = GL_LoadTexture32 (fbr_mask_name, fwidth, fheight, data, true, tx->name[0] == '{', true);\n\t\t\t\ttx->luma = true;\n\t\t\t\tfree(data);\n\t\t\t}\n\t\t}\n\t\t\n\t\t// Fallback to original textures\n\t\tif (tx->gl_texturenum == -1) {\n\t\t\ttx->gl_texturenum = GL_LoadTexture (mt->name, tx->width, tx->height, (byte *)(mt+1), true, false);\n\t\t\n\t\t\tif (FindFullbrightTexture ((byte *)(mt+1), pixels)) {\n\t\t\t\t// convert any non fullbright pixel to fully transparent\n\t\t\t\tConvertPixels ((byte *)(mt+1), pixels);\n\t\t\t\t// get a new name for the fullbright mask to avoid cache mismatches\n\t\t\t\tsprintf (fbr_mask_name, \"fullbright_mask_%s\", mt->name);\n\t\t\t\t// load the fullbright pixels version of the texture\n\t\t\t\ttx->fullbright = GL_LoadTexture (fbr_mask_name, tx->width, tx->height, (byte *)(mt + 1), true, true);\n\t\t\t}\n\t\t}\n\t}\n\n//\n// sequence the animations\n//\n\tfor (i=0 ; i<m->nummiptex ; i++)\n\t{\n\t\ttx = loadmodel->textures[i];\n\t\tif (!tx || tx->name[0] != '+')\n\t\t\tcontinue;\n\t\tif (tx->anim_next)\n\t\t\tcontinue;\t// allready sequenced\n\n\t// find the number of frames in the animation\n\t\tmemset (anims, 0, sizeof(anims));\n\t\tmemset (altanims, 0, sizeof(altanims));\n\n\t\tmax = tx->name[1];\n\t\taltmax = 0;\n\t\tif (max >= 'a' && max <= 'z')\n\t\t\tmax -= 'a' - 'A';\n\t\tif (max >= '0' && max <= '9')\n\t\t{\n\t\t\tmax -= '0';\n\t\t\taltmax = 0;\n\t\t\tanims[max] = tx;\n\t\t\tmax++;\n\t\t}\n\t\telse if (max >= 'A' && max <= 'J')\n\t\t{\n\t\t\taltmax = max - 'A';\n\t\t\tmax = 0;\n\t\t\taltanims[altmax] = tx;\n\t\t\taltmax++;\n\t\t}\n\t\telse\n\t\t\tSys_Error (\"Bad animating texture %s\", tx->name);\n\n\t\tfor (j=i+1 ; j<m->nummiptex ; j++)\n\t\t{\n\t\t\ttx2 = loadmodel->textures[j];\n\t\t\tif (!tx2 || tx2->name[0] != '+')\n\t\t\t\tcontinue;\n\t\t\tif (strcmp (tx2->name+2, tx->name+2))\n\t\t\t\tcontinue;\n\n\t\t\tnum = tx2->name[1];\n\t\t\tif (num >= 'a' && num <= 'z')\n\t\t\t\tnum -= 'a' - 'A';\n\t\t\tif (num >= '0' && num <= '9')\n\t\t\t{\n\t\t\t\tnum -= '0';\n\t\t\t\tanims[num] = tx2;\n\t\t\t\tif (num+1 > max)\n\t\t\t\t\tmax = num + 1;\n\t\t\t}\n\t\t\telse if (num >= 'A' && num <= 'J')\n\t\t\t{\n\t\t\t\tnum = num - 'A';\n\t\t\t\taltanims[num] = tx2;\n\t\t\t\tif (num+1 > altmax)\n\t\t\t\t\taltmax = num+1;\n\t\t\t}\n\t\t\telse\n\t\t\t\tSys_Error (\"Bad animating texture %s\", tx->name);\n\t\t}\n\t\t\n#define\tANIM_CYCLE\t2\n\t// link them all together\n\t\tfor (j=0 ; j<max ; j++)\n\t\t{\n\t\t\ttx2 = anims[j];\n\t\t\tif (!tx2)\n\t\t\t\tSys_Error (\"Missing frame %i of %s\",j, tx->name);\n\t\t\ttx2->anim_total = max * ANIM_CYCLE;\n\t\t\ttx2->anim_min = j * ANIM_CYCLE;\n\t\t\ttx2->anim_max = (j+1) * ANIM_CYCLE;\n\t\t\ttx2->anim_next = anims[ (j+1)%max ];\n\t\t\tif (altmax)\n\t\t\t\ttx2->alternate_anims = altanims[0];\n\t\t}\n\t\tfor (j=0 ; j<altmax ; j++)\n\t\t{\n\t\t\ttx2 = altanims[j];\n\t\t\tif (!tx2)\n\t\t\t\tSys_Error (\"Missing frame %i of %s\",j, tx->name);\n\t\t\ttx2->anim_total = altmax * ANIM_CYCLE;\n\t\t\ttx2->anim_min = j * ANIM_CYCLE;\n\t\t\ttx2->anim_max = (j+1) * ANIM_CYCLE;\n\t\t\ttx2->anim_next = altanims[ (j+1)%altmax ];\n\t\t\tif (max)\n\t\t\t\ttx2->alternate_anims = anims[0];\n\t\t}\n\t}\n}\n\nvoid Mod_LoadLighting (lump_t *l)\n{\n\tunsigned int path_id;\n\t\n\tloadmodel->lightdata = NULL;\n\n\t// Half-Life models support\n\tif (loadmodel->bspversion == HL_BSPVERSION) {\n\t\tif (!l->filelen) return;\n\t\tloadmodel->lightdata = Hunk_AllocName(l->filelen, loadname);\n\t\tmemcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);\n\t\treturn;\n\t}\n\t\n\t// LordHavoc: .lit support begin\n\tint i;\n\tbyte *in, *out, *data;\n\tbyte d;\n\tchar litfilename[1024];\n\t\n\t// LordHavoc: check for a .lit file\n\tstrcpy(litfilename, loadmodel->name);\n\tCOM_StripExtension(litfilename, litfilename);\n\tstrcat(litfilename, \".lit\");\n\tdata = (byte*) COM_LoadHunkFile (litfilename, &path_id);\n\tif (data && (path_id >= loadmodel->path_id))\n\t{\n\t\tif (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')\n\t\t{\n\t\t\ti = LittleLong(((int *)data)[1]);\n\t\t\tif (i == 1)\n\t\t\t{\n\t\t\t\tCon_DPrintf(\"%s loaded\", litfilename);\n\t\t\t\tloadmodel->lightdata = data + 8;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\telse\n\t\t\t\tCon_Printf(\"Unknown .lit file version (%d)\\n\", i);\n\t\t}\n\t\telse\n\t\t\tCon_Printf(\"Corrupt .lit file (old version?), ignoring\\n\");\n\t}\n\n\tif (!l->filelen)\n\t\treturn;\n\t\n\t// LordHavoc: no .lit found, expand the white lighting data to color\n\tloadmodel->lightdata = Hunk_AllocName ( l->filelen*3, litfilename);\n\tin = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write\n\tout = loadmodel->lightdata;\n\tmemcpy (in, mod_base + l->fileofs, l->filelen);\n\tfor (i = 0;i < l->filelen;i++)\n\t{\n\t\td = *in++;\n\t\t*out++ = d;\n\t\t*out++ = d;\n\t\t*out++ = d;\n\t}\n\t// LordHavoc: .lit support end\n\n}\n\n/*\n=================\nMod_LoadVisibility\n=================\n*/\nvoid Mod_LoadVisibility (lump_t *l)\n{\n\tif (!l->filelen)\n\t{\n\t\tloadmodel->visdata = NULL;\n\t\treturn;\n\t}\n\tloadmodel->visdata = (byte*)Hunk_AllocName ( l->filelen, loadname);\t\n\tmemcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);\n}\n\n/*\n=================\nMod_ParseWadsFromEntityLump\nFor Half-life maps\n=================\n*/\nstatic void Mod_ParseWadsFromEntityLump(char *data)\n{\n\tchar *s, key[1024], value[1024];\n\tint i, j, k;\n\n\tif (!data || !(data = COM_Parse(data)))\n\t\treturn;\n\n\tif (com_token[0] != '{')\n\t\treturn; // error\n\n\twhile (1)\n\t{\n\t\tif (!(data = COM_Parse(data)))\n\t\t\treturn; // error\n\n\t\tif (com_token[0] == '}')\n\t\t\tbreak; // end of worldspawn\n\n\t\tstrncpyz(key, (com_token[0] == '_') ? com_token + 1 : com_token, sizeof(key));\n\n\t\tfor (s = key + strlen(key) - 1; s >= key && *s == ' '; s--)\t\t// remove trailing spaces\n\t\t\t*s = 0;\n\n\t\tif (!(data = COM_Parse(data)))\n\t\t\treturn; // error\n\n\t\tstrncpyz(value, com_token, sizeof(value));\n\n\t\tif (!strcmp(\"MaxRange\", key))\n            Cvar_Set(\"r_maxrange\", value);\n\n\t\tif (!strcmp(\"wad\", key))\n\t\t{\n\t\t\tj = 0;\n\t\t\tfor (i = 0; i < strlen(value); i++)\n\t\t\t{\n\t\t\t\tif (value[i] != ';' && value[i] != '\\\\' && value[i] != '/' && value[i] != ':')\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (!value[i])\n\t\t\t\tcontinue;\n\t\t\tfor ( ; i < sizeof(value); i++)\n\t\t\t{\n\t\t\t\t// ignore path - the \\\\ check is for HalfLife... stupid windoze 'programmers'...\n\t\t\t\tif (value[i] == '\\\\' || value[i] == '/' || value[i] == ':')\n\t\t\t\t{\n\t\t\t\t\tj = i + 1;\n\t\t\t\t}\n                else if (value[i] == ';' || value[i] == 0)\n\t\t\t\t{\n\t\t\t\t\tk = value[i];\n\t\t\t\t\tvalue[i] = 0;\n\t\t\t\t\tif (value[j])\n\t\t\t\t\t\tWAD3_LoadTextureWadFile (value + j);\n\t\t\t\t\tj = i + 1;\n\t\t\t\t\tif (!k)\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n    }\n}\n\n\n/*\n=================\nMod_LoadEntities\n=================\n*/\nvoid Mod_LoadEntities (lump_t *l)\n{\n\tchar entfilename[128];\n\tunsigned int path_id;\n\t\n\tloadmodel->entities = NULL;\n\t\n\tstrcpy(entfilename, loadmodel->name);\n\tCOM_StripExtension(entfilename, entfilename);\n\tstrcat(entfilename, \".ent\");\n\tent_file = (byte*) COM_LoadHunkFile (entfilename, &path_id);\n\t\n\tif (ent_file && (path_id >= loadmodel->path_id))\n\t{\n\t\tif (ent_file[0] == '{')\n\t\t{\n\t\t\tCon_DPrintf(\"%s loaded\", entfilename);\n\t\t\tloadmodel->entities = (char*)ent_file;\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t\tCon_Printf(\"Corrupt .ent file, ignoring\\n\");\n\t}\n\t\n\tif (!l->filelen)\n\t{\n\t\tloadmodel->entities = NULL;\n\t\treturn;\n\t}\n\tloadmodel->entities = (signed char*)Hunk_AllocName ( l->filelen, loadname);\t\n\tmemcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);\n\t\n\tif (loadmodel->bspversion == HL_BSPVERSION)\n\t\tMod_ParseWadsFromEntityLump(loadmodel->entities);\n}\n\n\n/*\n=================\nMod_LoadVertexes\n=================\n*/\nvoid Mod_LoadVertexes (lump_t *l)\n{\n\tdvertex_t\t*in;\n\tmvertex_t\t*out;\n\tint\t\t\ti, count;\n\n\tin = (dvertex_t*)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (mvertex_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->vertexes = out;\n\tloadmodel->numvertexes = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tout->position[0] = LittleFloat (in->point[0]);\n\t\tout->position[1] = LittleFloat (in->point[1]);\n\t\tout->position[2] = LittleFloat (in->point[2]);\n\t}\n}\n\n/*\n=================\nMod_LoadSubmodels\n=================\n*/\nvoid Mod_LoadSubmodels (lump_t *l)\n{\n\tdmodel_t\t*in;\n\tdmodel_t\t*out;\n\tint\t\t\ti, j, count;\n\n\tin = (dmodel_t*)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (dmodel_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->submodels = out;\n\tloadmodel->numsubmodels = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\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\tout->origin[j] = LittleFloat (in->origin[j]);\n\t\t}\n\t\tfor (j=0 ; j<MAX_MAP_HULLS ; j++)\n\t\t\tout->headnode[j] = LittleLong (in->headnode[j]);\n\t\tout->visleafs = LittleLong (in->visleafs);\n\t\tout->firstface = LittleLong (in->firstface);\n\t\tout->numfaces = LittleLong (in->numfaces);\n\t}\n}\n\n/*\n=================\nMod_LoadEdges\n=================\n*/\nvoid Mod_LoadEdges (lump_t *l, int bsp2)\n{\n\tmedge_t *out;\n\tint \ti, count;\n\t\n\tif (bsp2) {\n\t\tdledge_t *in = (dledge_t *)(mod_base + l->fileofs);\n\t\tif (l->filelen % sizeof(*in))\n\t\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\t\tcount = l->filelen / sizeof(*in);\n\t\tout = (medge_t*) Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);\n\t\tloadmodel->edges = out;\n\t\tloadmodel->numedges = count;\n\n\t\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t\t{\n\t\t\tout->v[0] = LittleLong(in->v[0]);\n\t\t\tout->v[1] = LittleLong(in->v[1]);\n\t\t}\n\t} else {\n\t\tdsedge_t *in = (dsedge_t *)(mod_base + l->fileofs);\n\t\tif (l->filelen % sizeof(*in))\n\t\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\n\t\tcount = l->filelen / sizeof(*in);\n\t\tout = (medge_t *) Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);\n\n\t\tloadmodel->edges = out;\n\t\tloadmodel->numedges = count;\n\n\t\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t\t{\n\t\t\tout->v[0] = (unsigned short)LittleShort(in->v[0]);\n\t\t\tout->v[1] = (unsigned short)LittleShort(in->v[1]);\n\t\t}\n\t}\n}\n\n/*\n=================\nMod_LoadTexinfo\n=================\n*/\nvoid Mod_LoadTexinfo (lump_t *l)\n{\n\ttexinfo_t *in;\n\tmtexinfo_t *out;\n\tint \ti, j, count;\n\tint\t\tmiptex;\n\tfloat\tlen1, len2;\n\n\tin = (texinfo_t *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (mtexinfo_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->texinfo = out;\n\tloadmodel->numtexinfo = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<4 ; j++)\n\t\t{\n\t\t\tout->vecs[0][j] = LittleFloat (in->vecs[0][j]);\n\t\t\tout->vecs[1][j] = LittleFloat (in->vecs[1][j]);\n\t\t}\n\t\tlen1 = Length (out->vecs[0]);\n\t\tlen2 = Length (out->vecs[1]);\n\t\tlen1 = (len1 + len2)/2;\n\t\tif (len1 < 0.32)\n\t\t\tout->mipadjust = 4;\n\t\telse if (len1 < 0.49)\n\t\t\tout->mipadjust = 3;\n\t\telse if (len1 < 0.99)\n\t\t\tout->mipadjust = 2;\n\t\telse\n\t\t\tout->mipadjust = 1;\n\n\t\tmiptex = LittleLong (in->miptex);\n\t\tout->flags = LittleLong (in->flags);\n\t\n\t\tif (!loadmodel->textures)\n\t\t{\n\t\t\tout->texture = r_notexture_mip;\t// checkerboard texture\n\t\t\tout->flags = 0;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (miptex >= loadmodel->numtextures)\n\t\t\t\tSys_Error (\"miptex >= loadmodel->numtextures\");\n\t\t\tout->texture = loadmodel->textures[miptex];\n\t\t\tif (!out->texture)\n\t\t\t{\n\t\t\t\tout->texture = r_notexture_mip; // texture not found\n\t\t\t\tout->flags = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n================\nCalcSurfaceExtents\n\nFills in s->texturemins[] and s->extents[]\n================\n*/\nvoid CalcSurfaceExtents (msurface_t *s)\n{\n\tfloat\tmins[2], maxs[2], val;\n\tint\t\ti,j, e;\n\tmvertex_t\t*v;\n\tmtexinfo_t\t*tex;\n\tint\t\tbmins[2], bmaxs[2];\n\n\tmins[0] = mins[1] = 999999;\n\tmaxs[0] = maxs[1] = -99999;\n\n\ttex = s->texinfo;\n\t\n\tfor (i=0 ; i<s->numedges ; i++)\n\t{\n\t\te = loadmodel->surfedges[s->firstedge+i];\n\t\tif (e >= 0)\n\t\t\tv = &loadmodel->vertexes[loadmodel->edges[e].v[0]];\n\t\telse\n\t\t\tv = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];\n\t\t\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\tval = v->position[0] * tex->vecs[j][0] + \n\t\t\t\tv->position[1] * tex->vecs[j][1] +\n\t\t\t\tv->position[2] * tex->vecs[j][2] +\n\t\t\t\ttex->vecs[j][3];\n\t\t\tif (val < mins[j])\n\t\t\t\tmins[j] = val;\n\t\t\tif (val > maxs[j])\n\t\t\t\tmaxs[j] = val;\n\t\t}\n\t}\n\n\tfor (i=0 ; i<2 ; i++)\n\t{\t\n\t\tbmins[i] = (int)floorf(mins[i]/16);\n\t\tbmaxs[i] = (int)ceilf(maxs[i]/16);\n\n\t\ts->texturemins[i] = bmins[i] * 16;\n\t\ts->extents[i] = (bmaxs[i] - bmins[i]) * 16;\n\t\tif ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512 /* 256 */ )\n\t\t\tSys_Error (\"Bad surface extents\");\n\t}\n}\n\n\n/*\n=================\nMod_LoadFaces\n=================\n*/\nvoid Mod_LoadFaces (lump_t *l, int bsp2)\n{\n\tdsface_t\t*ins;\n\tdlface_t\t*inl;\n\tmsurface_t \t*out;\n\tint\t\t\ti, count, surfnum, lofs;\n\tint\t\t\tplanenum, side, texinfon;\n\t\n\tif (bsp2)\n\t{\n\t\tins = NULL;\n\t\tinl = (dlface_t *)(mod_base + l->fileofs);\n\t\tif (l->filelen % sizeof(*inl))\n\t\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\t\tcount = l->filelen / sizeof(*inl);\n\t}\n\telse\n\t{\n\t\tins = (dsface_t *)(mod_base + l->fileofs);\n\t\tinl = NULL;\n\t\tif (l->filelen % sizeof(*ins))\n\t\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\t\tcount = l->filelen / sizeof(*ins);\n\t}\n\tout = (msurface_t *)Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\tloadmodel->surfaces = out;\n\tloadmodel->numsurfaces = count;\n\n\tfor ( surfnum=0 ; surfnum<count ; surfnum++, out++)\n\t{\n\t\tif (bsp2)\n\t\t{\n\t\t\tout->firstedge = LittleLong(inl->firstedge);\n\t\t\tout->numedges = LittleLong(inl->numedges);\n\t\t\tplanenum = LittleLong(inl->planenum);\n\t\t\tside = LittleLong(inl->side);\n\t\t\ttexinfon = LittleLong (inl->texinfo);\n\t\t\tfor (i=0 ; i<MAXLIGHTMAPS ; i++)\n\t\t\t\tout->styles[i] = inl->styles[i];\n\t\t\tlofs = LittleLong(inl->lightofs);\n\t\t\tinl++;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tout->firstedge = LittleLong(ins->firstedge);\n\t\t\tout->numedges = LittleShort(ins->numedges);\n\t\t\tplanenum = LittleShort(ins->planenum);\n\t\t\tside = LittleShort(ins->side);\n\t\t\ttexinfon = LittleShort (ins->texinfo);\n\t\t\tfor (i=0 ; i<MAXLIGHTMAPS ; i++)\n\t\t\t\tout->styles[i] = ins->styles[i];\n\t\t\tlofs = LittleLong(ins->lightofs);\n\t\t\tins++;\n\t\t}\n\t\tout->flags = 0;\n\n\t\tif (side)\n\t\t\tout->flags |= SURF_PLANEBACK;\t\t\t\n\n\t\tout->plane = loadmodel->planes + planenum;\n\n\t\tout->texinfo = loadmodel->texinfo + texinfon;\n\n\t\tCalcSurfaceExtents (out);\n\t\t\t\t\n\t// lighting info\n\t\tif (lofs == -1)\n\t\t\tout->samples = NULL;\n\t\telse\n\t\t\tout->samples = loadmodel->lightdata + (loadmodel->bspversion == HL_BSPVERSION ? lofs : lofs * 3); // LordHavoc\n\t\t\n\t// set the drawing flags flag\n\t\t\n\t\tif (!strncmp(out->texinfo->texture->name,\"sky\",3))\t// sky\n\t\t{\n\t\t\tout->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);\n#ifndef QUAKE2\n\t\t\tGL_SubdivideSurface (out);\t// cut up polygon for warps\n#endif\n\t\t\tcontinue;\n\t\t}\n\t\t\n\t\tif (!strncmp(out->texinfo->texture->name,\"*\",1))\t\t// turbulent\n\t\t{\n\t\t\tout->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);\n\t\t\tfor (i=0 ; i<2 ; i++)\n\t\t\t{\n\t\t\t\tout->extents[i] = 16384;\n\t\t\t\tout->texturemins[i] = -8192;\n\t\t\t}\n\t\t\tGL_SubdivideSurface (out);\t// cut up polygon for warps\n\t\t\tcontinue;\n\t\t}\n\n\t}\n}\n\n\n/*\n=================\nMod_SetParent\n=================\n*/\nvoid Mod_SetParent (mnode_t *node, mnode_t *parent)\n{\n\tnode->parent = parent;\n\tif (node->contents < 0)\n\t\treturn;\n\tMod_SetParent (node->children[0], node);\n\tMod_SetParent (node->children[1], node);\n}\n\n/*\n=================\nMod_LoadNodes\n=================\n*/\nvoid Mod_LoadNodes_S (lump_t *l)\n{\n\tint\t\t\ti, j, count, p;\n\tdsnode_t\t\t*in;\n\tmnode_t \t*out;\n\n\tin = (dsnode_t *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (mnode_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->nodes = out;\n\tloadmodel->numnodes = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleShort (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleShort (in->maxs[j]);\n\t\t}\n\t\n\t\tp = LittleLong(in->planenum);\n\t\tout->plane = loadmodel->planes + p;\n\n\t\tout->firstsurface = LittleShort (in->firstface);\n\t\tout->numsurfaces = LittleShort (in->numfaces);\n\t\t\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\t//johnfitz -- hack to handle nodes > 32k, adapted from darkplaces\n\t\t\tp = (unsigned short)LittleShort(in->children[j]);\n\t\t\tif (p < count)\n\t\t\t\tout->children[j] = loadmodel->nodes + p;\n\t\t\telse\n\t\t\t{\n\t\t\t\tp = 65535 - p; //note this uses 65535 intentionally, -1 is leaf 0\n\t\t\t\tif (p < loadmodel->numleafs)\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs + p);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCon_Printf(\"Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\\n\", p, loadmodel->numleafs);\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf\n\t\t\t\t}\n\t\t\t}\n\t\t\t//johnfitz\n\t\t}\n\t}\n}\n\nvoid Mod_LoadNodes_L1 (lump_t *l)\n{\n\tint\t\t\ti, j, count, p;\n\tdl1node_t\t*in;\n\tmnode_t \t*out;\n\n\tin = (dl1node_t *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"Mod_LoadNodes: funny lump size in %s\",loadmodel->name);\n\n\tcount = l->filelen / sizeof(*in);\n\tout = (mnode_t *)Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\tloadmodel->nodes = out;\n\tloadmodel->numnodes = count;\n\n\tfor ( i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleShort (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleShort (in->maxs[j]);\n\t\t}\n\n\t\tp = LittleLong(in->planenum);\n\t\tout->plane = loadmodel->planes + p;\n\n\t\tout->firstsurface = LittleLong (in->firstface);\n\t\tout->numsurfaces = LittleLong (in->numfaces);\n\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\t//johnfitz -- hack to handle nodes > 32k, adapted from darkplaces\n\t\t\tp = LittleLong(in->children[j]);\n\t\t\tif (p >= 0 && p < count)\n\t\t\t\tout->children[j] = loadmodel->nodes + p;\n\t\t\telse\n\t\t\t{\n\t\t\t\tp = 0xffffffff - p; //note this uses 65535 intentionally, -1 is leaf 0\n\t\t\t\tif (p >= 0 && p < loadmodel->numleafs)\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs + p);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCon_Printf(\"Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\\n\", p, loadmodel->numleafs);\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf\n\t\t\t\t}\n\t\t\t}\n\t\t\t//johnfitz\n\t\t}\n\t}\n}\n\nvoid Mod_LoadNodes_L2 (lump_t *l)\n{\n\tint\t\t\ti, j, count, p;\n\tdl2node_t\t*in;\n\tmnode_t\t\t*out;\n\n\tin = (dl2node_t *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"Mod_LoadNodes: funny lump size in %s\",loadmodel->name);\n\n\tcount = l->filelen / sizeof(*in);\n\tout = (mnode_t *)Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\tloadmodel->nodes = out;\n\tloadmodel->numnodes = count;\n\n\tfor (i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleFloat (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleFloat (in->maxs[j]);\n\t\t}\n\n\t\tp = LittleLong(in->planenum);\n\t\tout->plane = loadmodel->planes + p;\n\n\t\tout->firstsurface = LittleLong (in->firstface); //johnfitz -- explicit cast as unsigned short\n\t\tout->numsurfaces = LittleLong (in->numfaces); //johnfitz -- explicit cast as unsigned short\n\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\t//johnfitz -- hack to handle nodes > 32k, adapted from darkplaces\n\t\t\tp = LittleLong(in->children[j]);\n\t\t\tif (p > 0 && p < count)\n\t\t\t\tout->children[j] = loadmodel->nodes + p;\n\t\t\telse\n\t\t\t{\n\t\t\t\tp = 0xffffffff - p; //note this uses 65535 intentionally, -1 is leaf 0\n\t\t\t\tif (p >= 0 && p < loadmodel->numleafs)\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs + p);\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCon_Printf(\"Mod_LoadNodes: invalid leaf index %i (file has only %i leafs)\\n\", p, loadmodel->numleafs);\n\t\t\t\t\tout->children[j] = (mnode_t *)(loadmodel->leafs); //map it to the solid leaf\n\t\t\t\t}\n\t\t\t}\n\t\t\t//johnfitz\n\t\t}\n\t}\n}\n\nvoid Mod_LoadNodes (lump_t *l, int bsp2)\n{\n\tif (bsp2 == 2)\n\t\tMod_LoadNodes_L2(l);\n\telse if (bsp2)\n\t\tMod_LoadNodes_L1(l);\n\telse\n\t\tMod_LoadNodes_S(l);\n\n\tMod_SetParent (loadmodel->nodes, NULL);\t// sets nodes and leafs\n}\n\n/*\n=================\nMod_ProcessLeafs\n=================\n*/\nvoid Mod_ProcessLeafs_S (dsleaf_t *in, int filelen)\n{\n\tmleaf_t\t\t*out;\n\tint\t\t\ti, j, count, p;\n\n\tif (filelen % sizeof(*in))\n\t\tSys_Error (\"Mod_ProcessLeafs: funny lump size in %s\", loadmodel->name);\n\tcount = filelen / sizeof(*in);\n\tout = (mleaf_t *) Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\t//johnfitz\n\tif (count > 32767)\n\t\tHost_Error (\"Mod_LoadLeafs: %i leafs exceeds limit of 32767.\\n\", count);\n\t//johnfitz\n\n\tloadmodel->leafs = out;\n\tloadmodel->numleafs = count;\n\n\tfor (i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleShort (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleShort (in->maxs[j]);\n\t\t}\n\n\t\tp = LittleLong(in->contents);\n\t\tout->contents = p;\n\n\t\tout->firstmarksurface = loadmodel->marksurfaces + (unsigned short)LittleShort(in->firstmarksurface); //johnfitz -- unsigned short\n\t\tout->nummarksurfaces = (unsigned short)LittleShort(in->nummarksurfaces); //johnfitz -- unsigned short\n\n\t\tp = LittleLong(in->visofs);\n\t\tif (p == -1)\n\t\t\tout->compressed_vis = NULL;\n\t\telse\n\t\t\tout->compressed_vis = loadmodel->visdata + p;\n\t\tout->efrags = NULL;\n\n\t\tfor (j=0 ; j<4 ; j++)\n\t\t\tout->ambient_sound_level[j] = in->ambient_level[j];\n\n\t\tif (out->contents != CONTENTS_EMPTY)\n\t\t{\n\t\t\tfor (j=0 ; j<out->nummarksurfaces ; j++)\n\t\t\t\tout->firstmarksurface[j]->flags |= SURF_UNDERWATER;\n\t\t}\n\t}\n}\n\nvoid Mod_ProcessLeafs_L1 (dl1leaf_t *in, int filelen)\n{\n\tmleaf_t\t\t*out;\n\tint\t\t\ti, j, count, p;\n\n\tif (filelen % sizeof(*in))\n\t\tSys_Error (\"Mod_ProcessLeafs: funny lump size in %s\", loadmodel->name);\n\n\tcount = filelen / sizeof(*in);\n\n\tout = (mleaf_t *) Hunk_AllocName (count * sizeof(*out), loadname);\n\n\tloadmodel->leafs = out;\n\tloadmodel->numleafs = count;\n\n\tfor (i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleShort (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleShort (in->maxs[j]);\n\t\t}\n\n\t\tp = LittleLong(in->contents);\n\t\tout->contents = p;\n\n\t\tout->firstmarksurface = loadmodel->marksurfaces + LittleLong(in->firstmarksurface); //johnfitz -- unsigned short\n\t\tout->nummarksurfaces = LittleLong(in->nummarksurfaces); //johnfitz -- unsigned short\n\n\t\tp = LittleLong(in->visofs);\n\t\tif (p == -1)\n\t\t\tout->compressed_vis = NULL;\n\t\telse\n\t\t\tout->compressed_vis = loadmodel->visdata + p;\n\t\tout->efrags = NULL;\n\n\t\tfor (j=0 ; j<4 ; j++)\n\t\t\tout->ambient_sound_level[j] = in->ambient_level[j];\n\n\t\tif (out->contents != CONTENTS_EMPTY)\n\t\t{\n\t\t\tfor (j=0 ; j<out->nummarksurfaces ; j++)\n\t\t\t\tout->firstmarksurface[j]->flags |= SURF_UNDERWATER;\n\t\t}\n\t}\n}\n\nvoid Mod_ProcessLeafs_L2 (dl2leaf_t *in, int filelen)\n{\n\tmleaf_t\t\t*out;\n\tint\t\t\ti, j, count, p;\n\n\tif (filelen % sizeof(*in))\n\t\tSys_Error (\"Mod_ProcessLeafs: funny lump size in %s\", loadmodel->name);\n\n\tcount = filelen / sizeof(*in);\n\n\tout = (mleaf_t *) Hunk_AllocName (count * sizeof(*out), loadname);\n\n\tloadmodel->leafs = out;\n\tloadmodel->numleafs = count;\n\n\tfor (i=0 ; i<count ; i++, in++, out++)\n\t{\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tout->minmaxs[j] = LittleFloat (in->mins[j]);\n\t\t\tout->minmaxs[3+j] = LittleFloat (in->maxs[j]);\n\t\t}\n\n\t\tp = LittleLong(in->contents);\n\t\tout->contents = p;\n\n\t\tout->firstmarksurface = loadmodel->marksurfaces + LittleLong(in->firstmarksurface); //johnfitz -- unsigned short\n\t\tout->nummarksurfaces = LittleLong(in->nummarksurfaces); //johnfitz -- unsigned short\n\n\t\tp = LittleLong(in->visofs);\n\t\tif (p == -1)\n\t\t\tout->compressed_vis = NULL;\n\t\telse\n\t\t\tout->compressed_vis = loadmodel->visdata + p;\n\t\tout->efrags = NULL;\n\n\t\tfor (j=0 ; j<4 ; j++)\n\t\t\tout->ambient_sound_level[j] = in->ambient_level[j];\n\n\t\tif (out->contents != CONTENTS_EMPTY)\n\t\t{\n\t\t\tfor (j=0 ; j<out->nummarksurfaces ; j++)\n\t\t\t\tout->firstmarksurface[j]->flags |= SURF_UNDERWATER;\n\t\t}\n\t}\n}\n\n/*\n=================\nMod_LoadLeafs\n=================\n*/\nvoid Mod_LoadLeafs (lump_t *l, int bsp2)\n{\n\tvoid *in = (void *)(mod_base + l->fileofs);\n\n\tif (bsp2 == 2)\n\t\tMod_ProcessLeafs_L2 ((dl2leaf_t *)in, l->filelen);\n\telse if (bsp2)\n\t\tMod_ProcessLeafs_L1 ((dl1leaf_t *)in, l->filelen);\n\telse\n\t\tMod_ProcessLeafs_S  ((dsleaf_t *) in, l->filelen);\n}\n\n/*\n=================\nMod_LoadClipnodes\n=================\n*/\nvoid Mod_LoadClipnodes (lump_t *l, int bsp2)\n{\n\tdsclipnode_t *ins;\n\tdlclipnode_t *inl;\n\tmclipnode_t *out;\n\tint\t\t\ti, count;\n\thull_t\t\t*hull;\n\n\tif (bsp2)\n\t{\n\t\tins = NULL;\n\t\tinl = (dlclipnode_t *)(mod_base + l->fileofs);\n\t\tif (l->filelen % sizeof(*inl))\n\t\t\tSys_Error (\"Mod_LoadClipnodes: funny lump size in %s\",loadmodel->name);\n\n\t\tcount = l->filelen / sizeof(*inl);\n\t}\n\telse\n\t{\n\t\tins = (dsclipnode_t *)(mod_base + l->fileofs);\n\t\tinl = NULL;\n\t\tif (l->filelen % sizeof(*ins))\n\t\t\tSys_Error (\"Mod_LoadClipnodes: funny lump size in %s\",loadmodel->name);\n\n\t\tcount = l->filelen / sizeof(*ins);\n\t}\n\tout = (mclipnode_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->clipnodes = out;\n\tloadmodel->numclipnodes = count;\n\t\n\tif (loadmodel->bspversion == HL_BSPVERSION)\n\t{\n\t\thull = &loadmodel->hulls[1];\n\t\thull->clipnodes = out;\n\t\thull->firstclipnode = 0;\n\t\thull->lastclipnode = count-1;\n\t\thull->planes = loadmodel->planes;\n\t\thull->clip_mins[0] = -16;\n\t\thull->clip_mins[1] = -16;\n\t\thull->clip_mins[2] = -36;\n\t\thull->clip_maxs[0] = 16;\n\t\thull->clip_maxs[1] = 16;\n\t\thull->clip_maxs[2] = 36;\n\n\t\thull = &loadmodel->hulls[2];\n\t\thull->clipnodes = out;\n\t\thull->firstclipnode = 0;\n\t\thull->lastclipnode = count-1;\n\t\thull->planes = loadmodel->planes;\n\t\thull->clip_mins[0] = -32;\n\t\thull->clip_mins[1] = -32;\n\t\thull->clip_mins[2] = -32;\n\t\thull->clip_maxs[0] = 32;\n\t\thull->clip_maxs[1] = 32;\n\t\thull->clip_maxs[2] = 32;\n\n\t    hull = &loadmodel->hulls[3];\n\t\thull->clipnodes = out;\n\t\thull->firstclipnode = 0;\n\t\thull->lastclipnode = count-1;\n\t\thull->planes = loadmodel->planes;\n\t\thull->clip_mins[0] = -16;\n\t\thull->clip_mins[1] = -16;\n\t\thull->clip_mins[2] = -18;\n\t\thull->clip_maxs[0] = 16;\n\t\thull->clip_maxs[1] = 16;\n\t\thull->clip_maxs[2] = 18;\n\t}\n\telse\n\t{\n\t\thull = &loadmodel->hulls[1];\n\t\thull->clipnodes = out;\n\t\thull->firstclipnode = 0;\n\t\thull->lastclipnode = count-1;\n\t\thull->planes = loadmodel->planes;\n\t\thull->clip_mins[0] = -16;\n\t\thull->clip_mins[1] = -16;\n\t\thull->clip_mins[2] = -24;\n\t\thull->clip_maxs[0] = 16;\n\t\thull->clip_maxs[1] = 16;\n\t\thull->clip_maxs[2] = 32;\n\n\t\thull = &loadmodel->hulls[2];\n\t\thull->clipnodes = out;\n\t\thull->firstclipnode = 0;\n\t\thull->lastclipnode = count-1;\n\t\thull->planes = loadmodel->planes;\n\t\thull->clip_mins[0] = -32;\n\t\thull->clip_mins[1] = -32;\n\t\thull->clip_mins[2] = -24;\n\t\thull->clip_maxs[0] = 32;\n\t\thull->clip_maxs[1] = 32;\n\t\thull->clip_maxs[2] = 64;\n\t}\n\t\n\tif (bsp2)\n\t{\n\t\tfor (i=0 ; i<count ; i++, out++, inl++)\n\t\t{\n\t\t\tout->planenum = LittleLong(inl->planenum);\n\n\t\t\t//johnfitz -- bounds check\n\t\t\tif (out->planenum < 0 || out->planenum >= loadmodel->numplanes)\n\t\t\t\tHost_Error (\"Mod_LoadClipnodes: planenum out of bounds\");\n\t\t\t//johnfitz\n\n\t\t\tout->children[0] = LittleLong(inl->children[0]);\n\t\t\tout->children[1] = LittleLong(inl->children[1]);\n\t\t}\n\t}\n\telse\n\t{\n\t\tfor (i=0 ; i<count ; i++, out++, ins++)\n\t\t{\n\t\t\tout->planenum = LittleLong(ins->planenum);\n\n\t\t\t//johnfitz -- bounds check\n\t\t\tif (out->planenum < 0 || out->planenum >= loadmodel->numplanes)\n\t\t\t\tHost_Error (\"Mod_LoadClipnodes: planenum out of bounds\");\n\t\t\t//johnfitz\n\n\t\t\t//johnfitz -- support clipnodes > 32k\n\t\t\tout->children[0] = (unsigned short)LittleShort(ins->children[0]);\n\t\t\tout->children[1] = (unsigned short)LittleShort(ins->children[1]);\n\n\t\t\tif (out->children[0] >= count)\n\t\t\t\tout->children[0] -= 65536;\n\t\t\tif (out->children[1] >= count)\n\t\t\t\tout->children[1] -= 65536;\n\t\t\t//johnfitz\n\t\t}\n\t}\n}\n\n/*\n=================\nMod_MakeHull0\n\nDeplicate the drawing hull structure as a clipping hull\n=================\n*/\nvoid Mod_MakeHull0 (void)\n{\n\tmnode_t\t\t*in, *child;\n\tmclipnode_t *out;\n\tint\t\t\ti, j, count;\n\thull_t\t\t*hull;\n\t\n\thull = &loadmodel->hulls[0];\t\n\t\n\tin = loadmodel->nodes;\n\tcount = loadmodel->numnodes;\n\tout = (mclipnode_t*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\thull->clipnodes = out;\n\thull->firstclipnode = 0;\n\thull->lastclipnode = count-1;\n\thull->planes = loadmodel->planes;\n\n\tfor (i=0 ; i<count ; i++, out++, in++)\n\t{\n\t\tout->planenum = in->plane - loadmodel->planes;\n\t\tfor (j=0 ; j<2 ; j++)\n\t\t{\n\t\t\tchild = in->children[j];\n\t\t\tif (child->contents < 0)\n\t\t\t\tout->children[j] = child->contents;\n\t\t\telse\n\t\t\t\tout->children[j] = child - loadmodel->nodes;\n\t\t}\n\t}\n}\n\n/*\n=================\nMod_LoadMarksurfaces\n=================\n*/\nvoid Mod_LoadMarksurfaces (lump_t *l, int bsp2)\n{\n\tint\t\ti, j, count;\n\tmsurface_t **out;\n\tif (bsp2)\n\t{\n\t\tunsigned int *in = (unsigned int *)(mod_base + l->fileofs);\n\n\t\tif (l->filelen % sizeof(*in))\n\t\t\tHost_Error (\"Mod_LoadMarksurfaces: funny lump size in %s\",loadmodel->name);\n\n\t\tcount = l->filelen / sizeof(*in);\n\t\tout = (msurface_t **)Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\t\tloadmodel->marksurfaces = out;\n\t\tloadmodel->nummarksurfaces = count;\n\n\t\tfor (i=0 ; i<count ; i++)\n\t\t{\n\t\t\tj = LittleLong(in[i]);\n\t\t\tif (j >= loadmodel->numsurfaces)\n\t\t\t\tHost_Error (\"Mod_LoadMarksurfaces: bad surface number\");\n\t\t\tout[i] = loadmodel->surfaces + j;\n\t\t}\n\t}\n\telse\n\t{\n\t\tshort *in = (short *)(mod_base + l->fileofs);\n\n\t\tif (l->filelen % sizeof(*in))\n\t\t\tHost_Error (\"Mod_LoadMarksurfaces: funny lump size in %s\",loadmodel->name);\n\n\t\tcount = l->filelen / sizeof(*in);\n\t\tout = (msurface_t **)Hunk_AllocName ( count*sizeof(*out), loadname);\n\n\t\tloadmodel->marksurfaces = out;\n\t\tloadmodel->nummarksurfaces = count;\n\n\t\tfor (i=0 ; i<count ; i++)\n\t\t{\n\t\t\tj = (unsigned short)LittleShort(in[i]); //johnfitz -- explicit cast as unsigned short\n\t\t\tif (j >= loadmodel->numsurfaces)\n\t\t\t\tSys_Error (\"Mod_LoadMarksurfaces: bad surface number\");\n\t\t\tout[i] = loadmodel->surfaces + j;\n\t\t}\n\t}\n}\n\n/*\n=================\nMod_LoadSurfedges\n=================\n*/\nvoid Mod_LoadSurfedges (lump_t *l)\n{\t\n\tint\t\ti, count;\n\tint\t\t*in, *out;\n\t\n\tin = (int *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (int*)Hunk_AllocName ( count*sizeof(*out), loadname);\t\n\n\tloadmodel->surfedges = out;\n\tloadmodel->numsurfedges = count;\n\n\tfor ( i=0 ; i<count ; i++)\n\t\tout[i] = LittleLong (in[i]);\n}\n\n\n/*\n=================\nMod_LoadPlanes\n=================\n*/\nvoid Mod_LoadPlanes (lump_t *l)\n{\n\tint\t\t\ti, j;\n\tmplane_t\t*out;\n\tdplane_t \t*in;\n\tint\t\t\tcount;\n\tint\t\t\tbits;\n\t\n\tin = (dplane_t *)(mod_base + l->fileofs);\n\tif (l->filelen % sizeof(*in))\n\t\tSys_Error (\"MOD_LoadBmodel: funny lump size in %s\",loadmodel->name);\n\tcount = l->filelen / sizeof(*in);\n\tout = (mplane_t*)Hunk_AllocName ( count*2*sizeof(*out), loadname);\t\n\t\n\tloadmodel->planes = out;\n\tloadmodel->numplanes = count;\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 = LittleLong (in->type);\n\t\tout->signbits = bits;\n\t}\n}\n\n/*\n=================\nRadiusFromBounds\n=================\n*/\nfloat RadiusFromBounds (vec3_t mins, vec3_t maxs)\n{\n\tint\t\ti;\n\tvec3_t\tcorner;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tcorner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);\n\t}\n\n\treturn Length (corner);\n}\n\n/*\n=================\nMod_LoadBrushModel\n=================\n*/\nvoid Mod_LoadBrushModel (model_t *mod, void *buffer)\n{\n\tint\t\t\ti, j;\n\tint\t\t\tbsp2;\n\tdheader_t\t*header;\n\tdmodel_t \t*bm;\n\t\n\tloadmodel->type = mod_brush;\n\t\n\theader = (dheader_t *)buffer;\n\t\n\tmod->bspversion = LittleLong (header->version);\n\t\n\tswitch (mod->bspversion) {\n\tcase Q1_BSPVERSION:\n\tcase HL_BSPVERSION:\n\t\tbsp2 = 0;\n\t\tbreak;\n\tcase BSP2VERSION_2PSB:\n\t\tbsp2 = 1;\n\t\tbreak;\n\tcase BSP2VERSION_BSP2:\n\t\tbsp2 = 2;\n\t\tbreak;\n\tdefault:\n\t\tHost_Error (\"Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or %i (Half-Life))\", mod->name, mod->bspversion, Q1_BSPVERSION, HL_BSPVERSION);\n\t\tbreak;\n\t}\n\n// swap all the lumps\n\tmod_base = (byte *)header;\n\n\tfor (i=0 ; i<(int)(sizeof(dheader_t)/4) ; i++)\n\t\t((int *)header)[i] = LittleLong ( ((int *)header)[i]);\n\n// load into heap\n\t\n\tMod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);\n\tMod_LoadEdges (&header->lumps[LUMP_EDGES], bsp2);\n\tMod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);\n\tMod_LoadTextures (&header->lumps[LUMP_TEXTURES]);\n\tMod_LoadLighting (&header->lumps[LUMP_LIGHTING]);\n\tMod_LoadPlanes (&header->lumps[LUMP_PLANES]);\n\tMod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);\n\tMod_LoadFaces (&header->lumps[LUMP_FACES], bsp2);\n\tMod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES], bsp2);\n\tMod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);\n\tMod_LoadLeafs (&header->lumps[LUMP_LEAFS], bsp2);\n\tMod_LoadNodes (&header->lumps[LUMP_NODES], bsp2);\n\tMod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES], bsp2);\n\tMod_LoadEntities (&header->lumps[LUMP_ENTITIES]);\n\tMod_LoadSubmodels (&header->lumps[LUMP_MODELS]);\n\n\tMod_MakeHull0 ();\n\t\n\tmod->numframes = 2;\t\t// regular and alternate animation\n\t\n//\n// set up the submodels (FIXME: this is confusing)\n//\n\tfor (i=0 ; i<mod->numsubmodels ; i++)\n\t{\n\t\tbm = &mod->submodels[i];\n\n\t\tmod->hulls[0].firstclipnode = bm->headnode[0];\n\t\tfor (j=1 ; j<MAX_MAP_HULLS ; j++)\n\t\t{\n\t\t\tmod->hulls[j].firstclipnode = bm->headnode[j];\n\t\t\tmod->hulls[j].lastclipnode = mod->numclipnodes-1;\n\t\t}\n\t\t\n\t\tmod->firstmodelsurface = bm->firstface;\n\t\tmod->nummodelsurfaces = bm->numfaces;\n\t\t\n\t\tVectorCopy (bm->maxs, mod->maxs);\n\t\tVectorCopy (bm->mins, mod->mins);\n\n\t\tmod->radius = RadiusFromBounds (mod->mins, mod->maxs);\n\n\t\tmod->numleafs = bm->visleafs;\n\n\t\tif (i < mod->numsubmodels-1)\n\t\t{\t// duplicate the basic information\n\t\t\tchar\tname[10];\n\n\t\t\tsprintf (name, \"*%i\", i+1);\n\t\t\tloadmodel = Mod_FindName (name);\n\t\t\t*loadmodel = *mod;\n\t\t\tstrcpy (loadmodel->name, name);\n\t\t\tmod = loadmodel;\n\t\t}\n\t}\n}\n\n/*\n==============================================================================\n\nALIAS MODELS\n\n==============================================================================\n*/\n\naliashdr_t\t*pheader;\n\nstvert_t\tstverts[MAXALIASVERTS];\nmtriangle_t\ttriangles[MAXALIASTRIS];\n\n// a pose is a single set of vertexes.  a frame may be\n// an animating sequence of poses\ntrivertx_t\t*poseverts[MAXALIASFRAMES];\nint\t\t\tposenum;\n\nbyte\t\t**player_8bit_texels_tbl;\nbyte\t\t*player_8bit_texels;\n\n/*\n=================\nMod_LoadAliasFrame\n=================\n*/\nvoid * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame)\n{\n\ttrivertx_t\t\t*pframe, *pinframe;\n\tint\t\t\t\ti, j;\n\tdaliasframe_t\t*pdaliasframe;\n\t\n\tpdaliasframe = (daliasframe_t *)pin;\n\n\tstrcpy (frame->name, pdaliasframe->name);\n\tframe->firstpose = posenum;\n\tframe->numposes = 1;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t// these are byte values, so we don't have to worry about\n\t// endianness\n\t\tframe->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];\n\t\tframe->bboxmin.v[i] = pdaliasframe->bboxmax.v[i];\n\t}\n\n\tpinframe = (trivertx_t *)(pdaliasframe + 1);\n\n\tposeverts[posenum] = pinframe;\n\tposenum++;\n\n\tpinframe += pheader->numverts;\n\n\treturn (void *)pinframe;\n}\n\n\n/*\n=================\nMod_LoadAliasGroup\n=================\n*/\nvoid *Mod_LoadAliasGroup (void * pin,  maliasframedesc_t *frame)\n{\n\tdaliasgroup_t\t\t*pingroup;\n\tint\t\t\t\t\ti, numframes;\n\tdaliasinterval_t\t*pin_intervals;\n\tvoid\t\t\t\t*ptemp;\n\t\n\tpingroup = (daliasgroup_t *)pin;\n\n\tnumframes = LittleLong (pingroup->numframes);\n\n\tframe->firstpose = posenum;\n\tframe->numposes = numframes;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t// these are byte values, so we don't have to worry about endianness\n\t\tframe->bboxmin.v[i] = pingroup->bboxmin.v[i];\n\t\tframe->bboxmin.v[i] = pingroup->bboxmax.v[i];\n\t}\n\n\tpin_intervals = (daliasinterval_t *)(pingroup + 1);\n\n\tframe->interval = LittleFloat (pin_intervals->interval);\n\n\tpin_intervals += numframes;\n\n\tptemp = (void *)pin_intervals;\n\n\tfor (i=0 ; i<numframes ; i++)\n\t{\n\t\tposeverts[posenum] = (trivertx_t *)((daliasframe_t *)ptemp + 1);\n\t\tposenum++;\n\n\t\tptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts;\n\t}\n\n\treturn ptemp;\n}\n\n//=========================================================\n\n/*\n=================\nMod_FloodFillSkin\n\nFill background pixels so mipmapping doesn't have haloes - Ed\n=================\n*/\n\ntypedef struct\n{\n\tshort\t\tx, y;\n} floodfill_t;\n\nextern unsigned d_8to24table[];\n\n// must be a power of 2\n#define FLOODFILL_FIFO_SIZE 0x1000\n#define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)\n\n#define FLOODFILL_STEP( off, dx, dy ) \\\n{ \\\n\tif (pos[off] == fillcolor) \\\n\t{ \\\n\t\tpos[off] = 255; \\\n\t\tfifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \\\n\t\tinpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \\\n\t} \\\n\telse if (pos[off] != 255) fdc = pos[off]; \\\n}\n\nvoid Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight )\n{\n\tbyte\t\t\t\tfillcolor = *skin; // assume this is the pixel to fill\n\tfloodfill_t\t\t\tfifo[FLOODFILL_FIFO_SIZE];\n\tint\t\t\t\t\tinpt = 0, outpt = 0;\n\tint\t\t\t\t\tfilledcolor = -1;\n\tint\t\t\t\t\ti;\n\n\tif (filledcolor == -1)\n\t{\n\t\tfilledcolor = 0;\n\t\t// attempt to find opaque black\n\t\tfor (i = 0; i < 256; ++i)\n\t\t\tif (d_8to24table[i] == (255 << 0)) // alpha 1.0\n\t\t\t{\n\t\t\t\tfilledcolor = i;\n\t\t\t\tbreak;\n\t\t\t}\n\t}\n\n\t// can't fill to filled color or to transparent color (used as visited marker)\n\tif ((fillcolor == filledcolor) || (fillcolor == 255))\n\t{\n\t\t//printf( \"not filling skin from %d to %d\\n\", fillcolor, filledcolor );\n\t\treturn;\n\t}\n\n\tfifo[inpt].x = 0, fifo[inpt].y = 0;\n\tinpt = (inpt + 1) & FLOODFILL_FIFO_MASK;\n\n\twhile (outpt != inpt)\n\t{\n\t\tint\t\t\tx = fifo[outpt].x, y = fifo[outpt].y;\n\t\tint\t\t\tfdc = filledcolor;\n\t\tbyte\t\t*pos = &skin[x + skinwidth * y];\n\n\t\toutpt = (outpt + 1) & FLOODFILL_FIFO_MASK;\n\n\t\tif (x > 0)\t\t\t\tFLOODFILL_STEP( -1, -1, 0 );\n\t\tif (x < skinwidth - 1)\tFLOODFILL_STEP( 1, 1, 0 );\n\t\tif (y > 0)\t\t\t\tFLOODFILL_STEP( -skinwidth, 0, -1 );\n\t\tif (y < skinheight - 1)\tFLOODFILL_STEP( skinwidth, 0, 1 );\n\t\tskin[x + skinwidth * y] = fdc;\n\t}\n}\n\nstatic int Mod_LoadExternalSkin(char *identifier)\n{\n\tint w, h;\n\tbyte *data = Image_LoadImage (identifier, &w, &h);\n\tif (data) {\n\t\tint r = GL_LoadTexture32 (identifier, w, h, data, false, false, false);\n\t\tfree(data);\n\t\treturn r;\n\t}\n\treturn -1;\n}\n\n/*\n===============\nMod_LoadAllSkins\n===============\n*/\nvoid *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype)\n{\n\tint\t\ti, j, k;\n\tchar\tname[32];\n\tint\t\ts, texnum;\n\tbyte\t*copy;\n\tbyte\t*skin;\n\tbyte\t*texels;\n\tdaliasskingroup_t\t\t*pinskingroup;\n\tint\t\tgroupskins;\n\tdaliasskininterval_t\t*pinskinintervals;\n\t\n\tskin = (byte *)(pskintype + 1);\n\n\tif (numskins < 1 || numskins > MAX_SKINS)\n\t\tSys_Error (\"Mod_LoadAliasModel: Invalid # of skins: %d\\n\", numskins);\n\n\ts = pheader->skinwidth * pheader->skinheight;\n\n\tfor (i=0 ; i<numskins ; i++)\n\t{\n\t\tif (pskintype->type == ALIAS_SKIN_SINGLE) {\n\t\t\tMod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );\n\n\t\t\t// save 8 bit texels for the player model to remap\n\t\t\tif (!strcmp(loadmodel->name,\"progs/player.mdl\")) {\n\t\t\t\ttexels = Hunk_AllocName(s, loadname);\n\t\t\t\tpheader->texels[i] = texels - (byte *)pheader;\n\t\t\t\tmemcpy (texels, (byte *)(pskintype + 1), s);\n\t\t\t}\n\t\t\tsprintf (name, \"%s_%i\", loadmodel->name, i);\n\t\t\t\n\t\t\ttexnum = Mod_LoadExternalSkin(name);\n\t\t\tpheader->gl_texturenum[i][0] =\n\t\t\tpheader->gl_texturenum[i][1] =\n\t\t\tpheader->gl_texturenum[i][2] =\n\t\t\tpheader->gl_texturenum[i][3] = texnum != -1 ? texnum : GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype + 1), true, false);\n\t\t\tpskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s);\n\t\t} else {\n\t\t\t// animating skin group.  yuck.\n\t\t\tpskintype++;\n\t\t\tpinskingroup = (daliasskingroup_t *)pskintype;\n\t\t\tgroupskins = LittleLong (pinskingroup->numskins);\n\t\t\tpinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);\n\n\t\t\tpskintype = (void *)(pinskinintervals + groupskins);\n\n\t\t\tfor (j=0 ; j<groupskins ; j++)\n\t\t\t{\n\t\t\t\t\tMod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );\n\t\t\t\t\tif (j == 0) {\n\t\t\t\t\t\ttexels = Hunk_AllocName(s, loadname);\n\t\t\t\t\t\tpheader->texels[i] = texels - (byte *)pheader;\n\t\t\t\t\t\tmemcpy (texels, (byte *)(pskintype), s);\n\t\t\t\t\t}\n\t\t\t\t\tsprintf (name, \"%s_%i_%i\", loadmodel->name, i,j);\n\t\t\t\t\ttexnum = Mod_LoadExternalSkin(name);\n\t\t\t\t\tpheader->gl_texturenum[i][j&3] = texnum != -1 ? texnum : GL_LoadTexture (name, pheader->skinwidth, pheader->skinheight, (byte *)(pskintype), true, false);\n\t\t\t\t\tpskintype = (daliasskintype_t *)((byte *)(pskintype) + s);\n\t\t\t}\n\t\t\tk = j;\n\t\t\tfor (/* */; j < 4; j++)\n\t\t\t\tpheader->gl_texturenum[i][j&3] = \n\t\t\t\tpheader->gl_texturenum[i][j - k]; \n\t\t}\n\t}\n\n\treturn (void *)pskintype;\n}\n\n//=========================================================================\n\n/*\n=================\nMod_LoadAliasModel\n=================\n*/\nvoid Mod_LoadAliasModel (model_t *mod, void *buffer)\n{\n\tint\t\t\t\t\ti, j;\n\tmdl_t\t\t\t\t*pinmodel;\n\tstvert_t\t\t\t*pinstverts;\n\tdtriangle_t\t\t\t*pintriangles;\n\tint\t\t\t\t\tversion, numframes, numskins;\n\tint\t\t\t\t\tsize;\n\tdaliasframetype_t\t*pframetype;\n\tdaliasskintype_t\t*pskintype;\n\tint\t\t\t\t\tstart, end, total;\n\t\n\tstart = Hunk_LowMark ();\n\n\tpinmodel = (mdl_t *)buffer;\n\n\tversion = LittleLong (pinmodel->version);\n\tif (version != ALIAS_VERSION)\n\t\tSys_Error (\"%s has wrong version number (%i should be %i)\",\n\t\t\t\t mod->name, version, ALIAS_VERSION);\n\n//\n// allocate space for a working header, plus all the data except the frames,\n// skin and group info\n//\n\tsize = \tsizeof (aliashdr_t) \n\t\t\t+ (LittleLong (pinmodel->numframes) - 1) *\n\t\t\tsizeof (pheader->frames[0]);\n\tpheader = Hunk_AllocName (size, loadname);\n\t\n\ti = LittleLong (pinmodel->flags);\n\tmod->flags = ((i & 255) << 24) | (i & 0x00FFFF00);\n\t\n//\n// endian-adjust and copy the data, starting with the alias model header\n//\n\tpheader->boundingradius = LittleFloat (pinmodel->boundingradius);\n\tpheader->numskins = LittleLong (pinmodel->numskins);\n\tpheader->skinwidth = LittleLong (pinmodel->skinwidth);\n\tpheader->skinheight = LittleLong (pinmodel->skinheight);\n\n\tif (pheader->skinheight > MAX_LBM_HEIGHT)\n\t\tSys_Error (\"model %s has a skin taller than %d\", mod->name,\n\t\t\t\t   MAX_LBM_HEIGHT);\n\n\tpheader->numverts = LittleLong (pinmodel->numverts);\n\n\tif (pheader->numverts <= 0)\n\t\tSys_Error (\"model %s has no vertices\", mod->name);\n\n\tif (pheader->numverts > MAXALIASVERTS)\n\t\tSys_Error (\"model %s has too many vertices (%d; max = %d)\", mod->name, pheader->numverts, MAXALIASVERTS);\n\n\tpheader->numtris = LittleLong (pinmodel->numtris);\n\n\tif (pheader->numtris <= 0)\n\t\tSys_Error (\"model %s has no triangles\", mod->name);\n\t\n\tif (pheader->numtris > MAXALIASTRIS)\n\t\tSys_Error (\"model %s has too many triangles (%d; max = %d)\", mod->name, pheader->numtris, MAXALIASTRIS);\n\n\tpheader->numframes = LittleLong (pinmodel->numframes);\n\tnumframes = pheader->numframes;\n\tif (numframes < 1)\n\t\tSys_Error (\"Mod_LoadAliasModel: Invalid # of frames: %d\\n\", numframes);\n\n\tpheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;\n\tmod->synctype = LittleLong (pinmodel->synctype);\n\tmod->numframes = pheader->numframes;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tpheader->scale[i] = LittleFloat (pinmodel->scale[i]);\n\t\tpheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);\n\t\tpheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);\n\t}\n\n\n//\n// load the skins\n//\n\tpskintype = (daliasskintype_t *)&pinmodel[1];\n\tpskintype = Mod_LoadAllSkins (pheader->numskins, pskintype);\n\n//\n// load base s and t vertices\n//\n\tpinstverts = (stvert_t *)pskintype;\n\n\tfor (i=0 ; i<pheader->numverts ; i++)\n\t{\n\t\tstverts[i].onseam = LittleLong (pinstverts[i].onseam);\n\t\tstverts[i].s = LittleLong (pinstverts[i].s);\n\t\tstverts[i].t = LittleLong (pinstverts[i].t);\n\t}\n\n//\n// load triangle lists\n//\n\tpintriangles = (dtriangle_t *)&pinstverts[pheader->numverts];\n\n\tfor (i=0 ; i<pheader->numtris ; i++)\n\t{\n\t\ttriangles[i].facesfront = LittleLong (pintriangles[i].facesfront);\n\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\ttriangles[i].vertindex[j] =\n\t\t\t\t\tLittleLong (pintriangles[i].vertindex[j]);\n\t\t}\n\t}\n\n//\n// load the frames\n//\n\tposenum = 0;\n\tpframetype = (daliasframetype_t *)&pintriangles[pheader->numtris];\n\n\tfor (i=0 ; i<numframes ; i++)\n\t{\n\t\taliasframetype_t\tframetype;\n\n\t\tframetype = LittleLong (pframetype->type);\n\n\t\tif (frametype == ALIAS_SINGLE)\n\t\t{\n\t\t\tpframetype = (daliasframetype_t *)\n\t\t\t\t\tMod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpframetype = (daliasframetype_t *)\n\t\t\t\t\tMod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]);\n\t\t}\n\t}\n\n\tpheader->numposes = posenum;\n\n\tmod->type = mod_alias;\n\n// FIXME: do this right\n\tmod->mins[0] = mod->mins[1] = mod->mins[2] = -16;\n\tmod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;\n\n\t//\n\t// build the draw lists\n\t//\n\tGL_MakeAliasModelDisplayLists (mod, pheader);\n\n//\n// move the complete, relocatable alias model to the cache\n//\t\n\tend = Hunk_LowMark ();\n\ttotal = end - start;\n\t\n\tCache_Alloc (&mod->cache, total, loadname);\n\tif (!mod->cache.data)\n\t\treturn;\n\tmemcpy (mod->cache.data, pheader, total);\n\n\tHunk_FreeToLowMark (start);\n}\n\n//=============================================================================\n\n/*\n=================\nMod_LoadSpriteFrame\n=================\n*/\nvoid * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum)\n{\n\tdspriteframe_t\t\t*pinframe;\n\tmspriteframe_t\t\t*pspriteframe;\n\tint\t\t\t\t\ti, width, height, size, origin[2];\n\tunsigned short\t\t*ppixout;\n\tbyte\t\t\t\t*ppixin;\n\tchar\t\t\t\tname[64];\n\n\tpinframe = (dspriteframe_t *)pin;\n\n\twidth = LittleLong (pinframe->width);\n\theight = LittleLong (pinframe->height);\n\tsize = width * height;\n\n\tpspriteframe = Hunk_AllocName (sizeof (mspriteframe_t),loadname);\n\n\tmemset (pspriteframe, 0, sizeof (mspriteframe_t));\n\n\t*ppframe = pspriteframe;\n\n\tpspriteframe->width = width;\n\tpspriteframe->height = height;\n\torigin[0] = LittleLong (pinframe->origin[0]);\n\torigin[1] = LittleLong (pinframe->origin[1]);\n\n\tpspriteframe->up = origin[1];\n\tpspriteframe->down = origin[1] - height;\n\tpspriteframe->left = origin[0];\n\tpspriteframe->right = width + origin[0];\n\n\tsprintf (name, \"%s_%i\", loadmodel->name, framenum);\n\tpspriteframe->gl_texturenum = GL_LoadTexture (name, width, height, (byte *)(pinframe + 1), true, true);\n\n\treturn (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);\n}\n\n\n/*\n=================\nMod_LoadSpriteGroup\n=================\n*/\nvoid * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum)\n{\n\tdspritegroup_t\t\t*pingroup;\n\tmspritegroup_t\t\t*pspritegroup;\n\tint\t\t\t\t\ti, numframes;\n\tdspriteinterval_t\t*pin_intervals;\n\tfloat\t\t\t\t*poutintervals;\n\tvoid\t\t\t\t*ptemp;\n\n\tpingroup = (dspritegroup_t *)pin;\n\n\tnumframes = LittleLong (pingroup->numframes);\n\n\tpspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +\n\t\t\t\t(numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);\n\n\tpspritegroup->numframes = numframes;\n\n\t*ppframe = (mspriteframe_t *)pspritegroup;\n\n\tpin_intervals = (dspriteinterval_t *)(pingroup + 1);\n\n\tpoutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);\n\n\tpspritegroup->intervals = poutintervals;\n\n\tfor (i=0 ; i<numframes ; i++)\n\t{\n\t\t*poutintervals = LittleFloat (pin_intervals->interval);\n\t\tif (*poutintervals <= 0.0)\n\t\t\tSys_Error (\"Mod_LoadSpriteGroup: interval<=0\");\n\n\t\tpoutintervals++;\n\t\tpin_intervals++;\n\t}\n\n\tptemp = (void *)pin_intervals;\n\n\tfor (i=0 ; i<numframes ; i++)\n\t{\n\t\tptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], framenum * 100 + i);\n\t}\n\n\treturn ptemp;\n}\n\n\n/*\n=================\nMod_LoadSpriteModel\n=================\n*/\nvoid Mod_LoadSpriteModel (model_t *mod, void *buffer)\n{\n\tint\t\t\t\t\ti;\n\tint\t\t\t\t\tversion;\n\tdsprite_t\t\t\t*pin;\n\tmsprite_t\t\t\t*psprite;\n\tint\t\t\t\t\tnumframes;\n\tint\t\t\t\t\tsize;\n\tdspriteframetype_t\t*pframetype;\n\t\n\tpin = (dsprite_t *)buffer;\n\n\tversion = LittleLong (pin->version);\n\tif (version != SPRITE_VERSION)\n\t\tSys_Error (\"%s has wrong version number \"\n\t\t\t\t \"(%i should be %i)\", mod->name, version, SPRITE_VERSION);\n\n\tnumframes = LittleLong (pin->numframes);\n\n\tsize = sizeof (msprite_t) +\t(numframes - 1) * sizeof (psprite->frames);\n\n\tpsprite = Hunk_AllocName (size, loadname);\n\n\tmod->cache.data = psprite;\n\n\tpsprite->type = LittleLong (pin->type);\n\tpsprite->maxwidth = LittleLong (pin->width);\n\tpsprite->maxheight = LittleLong (pin->height);\n\tpsprite->beamlength = LittleFloat (pin->beamlength);\n\tmod->synctype = LittleLong (pin->synctype);\n\tpsprite->numframes = numframes;\n\n\tmod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;\n\tmod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;\n\tmod->mins[2] = -psprite->maxheight/2;\n\tmod->maxs[2] = psprite->maxheight/2;\n\t\n//\n// load the frames\n//\n\tif (numframes < 1)\n\t\tSys_Error (\"Mod_LoadSpriteModel: Invalid # of frames: %d\\n\", numframes);\n\n\tmod->numframes = numframes;\n\n\tpframetype = (dspriteframetype_t *)(pin + 1);\n\n\tfor (i=0 ; i<numframes ; i++)\n\t{\n\t\tspriteframetype_t\tframetype;\n\n\t\tframetype = LittleLong (pframetype->type);\n\t\tpsprite->frames[i].type = frametype;\n\n\t\tif (frametype == SPR_SINGLE)\n\t\t{\n\t\t\tpframetype = (dspriteframetype_t *)\n\t\t\t\t\tMod_LoadSpriteFrame (pframetype + 1,\n\t\t\t\t\t\t\t\t\t\t &psprite->frames[i].frameptr, i);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tpframetype = (dspriteframetype_t *)\n\t\t\t\t\tMod_LoadSpriteGroup (pframetype + 1,\n\t\t\t\t\t\t\t\t\t\t &psprite->frames[i].frameptr, i);\n\t\t}\n\t}\n\n\tmod->type = mod_sprite;\n}\n\n//=============================================================================\n\n/*\n================\nMod_Print\n================\n*/\nvoid Mod_Print (void)\n{\n\tint\t\ti;\n\tmodel_t\t*mod;\n\n\tCon_Printf (\"Cached models:\\n\");\n\tfor (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)\n\t{\n\t\tCon_Printf (\"%8p : %s\\n\",mod->cache.data, mod->name);\n\t}\n}\n\n\n"
  },
  {
    "path": "source/gl_model.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#ifndef __MODEL__\n#define __MODEL__\n\n#include \"modelgen.h\"\n#include \"spritegn.h\"\n\n/*\n\nd*_t structures are on-disk representations\nm*_t structures are in-memory\n\n*/\n\n// entity effects\n\n#define\tEF_BRIGHTFIELD\t\t\t1\n#define\tEF_MUZZLEFLASH \t\t\t2\n#define\tEF_BRIGHTLIGHT \t\t\t4\n#define\tEF_DIMLIGHT \t\t\t8\n#define EF_BLUE\t\t\t\t\t64\n#define EF_RED\t\t\t\t\t128\n\n/*\n==============================================================================\n\nBRUSH MODELS\n\n==============================================================================\n*/\n\n\n//\n// in memory representation\n//\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct\n{\n\tvec3_t\t\tposition;\n} mvertex_t;\n\n#define\tSIDE_FRONT\t0\n#define\tSIDE_BACK\t1\n#define\tSIDE_ON\t\t2\n\n\n// plane_t structure\n// !!! if this is changed, it must be changed in asm_i386.h too !!!\ntypedef struct mplane_s\n{\n\tvec3_t\tnormal;\n\tfloat\tdist;\n\tbyte\ttype;\t\t\t// for texture axis selection and fast side tests\n\tbyte\tsignbits;\t\t// signx + signy<<1 + signz<<1\n\tbyte\tpad[2];\n} mplane_t;\n\ntypedef struct texture_s\n{\n\tchar\t\tname[16];\n\tunsigned\twidth, height;\n\tint\t\t\tgl_texturenum;\n\tstruct msurface_s\t*texturechain;\t// for gl_texsort drawing\n\tint\t\t\tanim_total;\t\t\t\t// total tenths in sequence ( 0 = no)\n\tint\t\t\tanim_min, anim_max;\t\t// time for this frame min <=time< max\n\tstruct texture_s *anim_next;\t\t// in the animation sequence\n\tstruct texture_s *alternate_anims;\t// bmodels in frmae 1 use these\n\tunsigned\toffsets[MIPLEVELS];\t\t// four mip maps stored\n\tint\t\t\tfullbright;\n\tbool\t\tluma;\n} texture_t;\n\n\n#define\tSURF_PLANEBACK\t\t2\n#define\tSURF_DRAWSKY\t\t4\n#define SURF_DRAWSPRITE\t\t8\n#define SURF_DRAWTURB\t\t0x10\n#define SURF_DRAWTILED\t\t0x20\n#define SURF_DRAWBACKGROUND\t0x40\n#define SURF_UNDERWATER\t\t0x80\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct\n{\n\tunsigned int\tv[2];\n\tunsigned int\tcachededgeoffset;\n} medge_t;\n\ntypedef struct\n{\n\tfloat\t\tvecs[2][4];\n\tfloat\t\tmipadjust;\n\ttexture_t\t*texture;\n\tint\t\t\tflags;\n} mtexinfo_t;\n\n#define\tVERTEXSIZE\t7\n\ntypedef struct glpoly_s\n{\n\tstruct\tglpoly_s\t*next;\n\tstruct\tglpoly_s\t*chain;\n\tint\t\tnumverts;\n\tint\t\tflags;\t\t\t// for SURF_UNDERWATER\n\tfloat\tverts[4][VERTEXSIZE];\t// variable sized (xyz s1t1 s2t2)\n} glpoly_t;\n\ntypedef struct msurface_s\n{\n\tint\t\t\tvisframe;\t\t// should be drawn when node is crossed\n\n\tmplane_t\t*plane;\n\tint\t\t\tflags;\n\n\tint\t\t\tfirstedge;\t// look up in model->surfedges[], negative numbers\n\tint\t\t\tnumedges;\t// are backwards edges\n\t\n\tshort\t\ttexturemins[2];\n\tshort\t\textents[2];\n\n\tint\t\t\tlight_s, light_t;\t// gl lightmap coordinates\n\n\tglpoly_t\t*polys;\t\t\t\t// multiple if warped\n\tstruct\tmsurface_s\t*texturechain;\n\n\tmtexinfo_t\t*texinfo;\n\t\n// lighting info\n\tint\t\t\tdlightframe;\n\tint\t\t\tdlightbits;\n\n\tint\t\t\tlightmaptexturenum;\n\tbyte\t\tstyles[MAXLIGHTMAPS];\n\tint\t\t\tcached_light[MAXLIGHTMAPS];\t// values currently used in lightmap\n\tbool\tcached_dlight;\t\t\t\t// true if dynamic light in cache\n\tbyte\t\t*samples;\t\t// [numstyles*surfsize]\n\tint\t\t\tdraw_this_frame;\n\tint\t\toverbright;\n} msurface_t;\n\ntypedef struct mnode_s\n{\n// common with leaf\n\tint\t\t\tcontents;\t\t// 0, to differentiate from leafs\n\tint\t\t\tvisframe;\t\t// node needs to be traversed if current\n\t\n\tfloat\t\tminmaxs[6];\t\t// for bounding box culling\n\n\tstruct mnode_s\t*parent;\n\n// node specific\n\tmplane_t\t*plane;\n\tstruct mnode_s\t*children[2];\t\n\n\tunsigned int\t\tfirstsurface;\n\tunsigned int\t\tnumsurfaces;\n} mnode_t;\n\n\n\ntypedef struct mleaf_s\n{\n// common with node\n\tint\t\t\tcontents;\t\t// wil be a negative contents number\n\tint\t\t\tvisframe;\t\t// node needs to be traversed if current\n\n\tfloat\t\tminmaxs[6];\t\t// for bounding box culling\n\n\tstruct mnode_s\t*parent;\n\n// leaf specific\n\tbyte\t\t*compressed_vis;\n\tefrag_t\t\t*efrags;\n\n\tmsurface_t\t**firstmarksurface;\n\tint\t\t\tnummarksurfaces;\n\tint\t\t\tkey;\t\t\t// BSP sequence number for leaf's contents\n\tbyte\t\tambient_sound_level[NUM_AMBIENTS];\n} mleaf_t;\n\n//johnfitz -- for clipnodes>32k\ntypedef struct mclipnode_s\n{\n\tint\t\t\tplanenum;\n\tint\t\t\tchildren[2]; // negative numbers are contents\n} mclipnode_t;\n//johnfitz\n\n// !!! if this is changed, it must be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tmclipnode_t\t*clipnodes;\n\tmplane_t\t*planes;\n\tint\t\t\tfirstclipnode;\n\tint\t\t\tlastclipnode;\n\tvec3_t\t\tclip_mins;\n\tvec3_t\t\tclip_maxs;\n} hull_t;\n\n/*\n==============================================================================\n\nSPRITE MODELS\n\n==============================================================================\n*/\n\n\n// FIXME: shorten these?\ntypedef struct mspriteframe_s\n{\n\tint\t\twidth;\n\tint\t\theight;\n\tfloat\tup, down, left, right;\n\tint\t\tgl_texturenum;\n} mspriteframe_t;\n\ntypedef struct\n{\n\tint\t\t\t\tnumframes;\n\tfloat\t\t\t*intervals;\n\tmspriteframe_t\t*frames[1];\n} mspritegroup_t;\n\ntypedef struct\n{\n\tspriteframetype_t\ttype;\n\tmspriteframe_t\t\t*frameptr;\n} mspriteframedesc_t;\n\ntypedef struct\n{\n\tint\t\t\t\t\ttype;\n\tint\t\t\t\t\tmaxwidth;\n\tint\t\t\t\t\tmaxheight;\n\tint\t\t\t\t\tnumframes;\n\tfloat\t\t\t\tbeamlength;\t\t// remove?\n\tvoid\t\t\t\t*cachespot;\t\t// remove?\n\tmspriteframedesc_t\tframes[1];\n} msprite_t;\n\n\n/*\n==============================================================================\n\nALIAS MODELS\n\nAlias models are position independent, so the cache manager can move them.\n==============================================================================\n*/\n\ntypedef struct\n{\n\tint\t\t\t\t\tfirstpose;\n\tint\t\t\t\t\tnumposes;\n\tfloat\t\t\t\tinterval;\n\ttrivertx_t\t\t\tbboxmin;\n\ttrivertx_t\t\t\tbboxmax;\n\tint\t\t\t\t\tframe;\n\tchar\t\t\t\tname[16];\n} maliasframedesc_t;\n\ntypedef struct\n{\n\ttrivertx_t\t\t\tbboxmin;\n\ttrivertx_t\t\t\tbboxmax;\n\tint\t\t\t\t\tframe;\n} maliasgroupframedesc_t;\n\ntypedef struct\n{\n\tint\t\t\t\t\t\tnumframes;\n\tint\t\t\t\t\t\tintervals;\n\tmaliasgroupframedesc_t\tframes[1];\n} maliasgroup_t;\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct mtriangle_s {\n\tint\t\t\t\t\tfacesfront;\n\tint\t\t\t\t\tvertindex[3];\n} mtriangle_t;\n\n\n#define\tMAX_SKINS\t32\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\tvec3_t\t\tscale;\n\tvec3_t\t\tscale_origin;\n\tfloat\t\tboundingradius;\n\tvec3_t\t\teyeposition;\n\tint\t\t\tnumskins;\n\tint\t\t\tskinwidth;\n\tint\t\t\tskinheight;\n\tint\t\t\tnumverts;\n\tint\t\t\tnumtris;\n\tint\t\t\tnumframes;\n\tsynctype_t\tsynctype;\n\tint\t\t\tflags;\n\tfloat\t\tsize;\n\n\tint\t\t\t\t\tnumposes;\n\tint\t\t\t\t\tposeverts;\n\tint\t\t\t\t\tposedata;\t// numposes*poseverts trivert_t\n\tint\t\t\t\t\tcommands;\t// gl command list with embedded s/t\n\tint\t\t\t\t\tgl_texturenum[MAX_SKINS][4];\n\tint\t\t\t\t\ttexels[MAX_SKINS];\t// only for player skins\n\tmaliasframedesc_t\tframes[1];\t// variable sized\n} aliashdr_t;\n\n#define\tMAXALIASVERTS\t5120\n#define\tMAXALIASFRAMES\t256\n#define\tMAXALIASTRIS\t4096\nextern\taliashdr_t\t*pheader;\nextern\tstvert_t\tstverts[MAXALIASVERTS];\nextern\tmtriangle_t\ttriangles[MAXALIASTRIS];\nextern\ttrivertx_t\t*poseverts[MAXALIASFRAMES];\n\n//===================================================================\n\n//\n// Whole model\n//\n\ntypedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;\n\n#define\tMF_ROCKET\t1\t\t\t// leave a trail\n#define\tMF_GRENADE\t2\t\t\t// leave a trail\n#define\tMF_GIB\t\t4\t\t\t// leave a trail\n#define\tMF_ROTATE\t8\t\t\t// rotate (bonus items)\n#define\tMF_TRACER\t16\t\t\t// green split trail\n#define\tMF_ZOMGIB\t32\t\t\t// small blood trail\n#define\tMF_TRACER2\t64\t\t\t// orange split trail + rotate\n#define\tMF_TRACER3\t128\t\t\t// purple trail\n\ntypedef struct model_s\n{\n\tchar\t\tname[MAX_QPATH];\n\tunsigned int\tpath_id;\n\tbool\tneedload;\t\t// bmodels and sprites don't cache normally\n\n\tmodtype_t\ttype;\n\tint\t\t\tnumframes;\n\tsynctype_t\tsynctype;\n\t\n\tint\t\t\tflags;\n\n//\n// volume occupied by the model graphics\n//\t\t\n\tvec3_t\t\tmins, maxs;\n\tfloat\t\tradius;\n\n//\n// solid volume for clipping \n//\n\tbool\tclipbox;\n\tvec3_t\t\tclipmins, clipmaxs;\n\n//\n// brush model\n//\n\tint\t\t\tfirstmodelsurface, nummodelsurfaces;\n\n\tint\t\t\tnumsubmodels;\n\tdmodel_t\t*submodels;\n\n\tint\t\t\tnumplanes;\n\tmplane_t\t*planes;\n\n\tint\t\t\tnumleafs;\t\t// number of visible leafs, not counting 0\n\tmleaf_t\t\t*leafs;\n\n\tint\t\t\tnumvertexes;\n\tmvertex_t\t*vertexes;\n\n\tint\t\t\tnumedges;\n\tmedge_t\t\t*edges;\n\n\tint\t\t\tnumnodes;\n\tmnode_t\t\t*nodes;\n\n\tint\t\t\tnumtexinfo;\n\tmtexinfo_t\t*texinfo;\n\n\tint\t\t\tnumsurfaces;\n\tmsurface_t\t*surfaces;\n\n\tint\t\t\tnumsurfedges;\n\tint\t\t\t*surfedges;\n\n\tint\t\t\tnumclipnodes;\n\tmclipnode_t\t*clipnodes;\n\n\tint\t\t\tnummarksurfaces;\n\tmsurface_t\t**marksurfaces;\n\n\thull_t\t\thulls[MAX_MAP_HULLS];\n\n\tint\t\t\tnumtextures;\n\ttexture_t\t**textures;\n\n\tbyte\t\t*visdata;\n\tbyte\t\t*lightdata;\n\tsigned char\t*entities;\n\t\n\tint bspversion;\n\n//\n// additional model data\n//\n\tcache_user_t\tcache;\t\t// only access through Mod_Extradata\n\n} model_t;\n\n//============================================================================\n\nvoid\tMod_Init (void);\nvoid\tMod_ClearAll (void);\nvoid\tMod_ResetAll (void); // for gamedir changes (Host_Game_f)\nmodel_t *Mod_ForName (char *name, bool crash);\nvoid\t*Mod_Extradata (model_t *mod);\t// handles caching\nvoid\tMod_TouchModel (char *name);\n\nmleaf_t *Mod_PointInLeaf (float *p, model_t *model);\nbyte\t*Mod_LeafPVS (mleaf_t *leaf, model_t *model);\n\n#endif\t// __MODEL__\n"
  },
  {
    "path": "source/gl_refrag.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_efrag.c\n\n#include \"quakedef.h\"\n\nmnode_t\t*r_pefragtopnode;\n\n// mh - extended efrags - begin\n#define EXTRA_EFRAGS   32\n\nvoid R_GetMoreEfrags (void)\n{\n\tint i;\n\n\tcl.free_efrags = (efrag_t *) Hunk_Alloc (EXTRA_EFRAGS * sizeof (efrag_t));\n\n\tfor (i = 0; i < EXTRA_EFRAGS - 1; i++)\n\t\tcl.free_efrags[i].entnext = &cl.free_efrags[i + 1];\n\n\tcl.free_efrags[i].entnext = NULL;\n}\n// mh - extended efrags - end\n\n\n//===========================================================================\n\n/*\n===============================================================================\n\n\t\t\t\t\tENTITY FRAGMENT FUNCTIONS\n\n===============================================================================\n*/\n\nefrag_t\t\t**lastlink;\n\nvec3_t\t\tr_emins, r_emaxs;\n\nentity_t\t*r_addent;\n\n\n/*\n================\nR_RemoveEfrags\n\nCall when removing an object from the world or moving it to another position\n================\n*/\nvoid R_RemoveEfrags (entity_t *ent)\n{\n\tefrag_t\t\t*ef, *old, *walk, **prev;\n\t\n\tef = ent->efrag;\n\t\n\twhile (ef)\n\t{\n\t\tprev = &ef->leaf->efrags;\n\t\twhile (1)\n\t\t{\n\t\t\twalk = *prev;\n\t\t\tif (!walk)\n\t\t\t\tbreak;\n\t\t\tif (walk == ef)\n\t\t\t{\t// remove this fragment\n\t\t\t\t*prev = ef->leafnext;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\telse\n\t\t\t\tprev = &walk->leafnext;\n\t\t}\n\t\t\t\t\n\t\told = ef;\n\t\tef = ef->entnext;\n\t\t\n\t// put it on the free list\n\t\told->entnext = cl.free_efrags;\n\t\tcl.free_efrags = old;\n\t}\n\t\n\tent->efrag = NULL; \n}\n\n/*\n===================\nR_SplitEntityOnNode\n===================\n*/\nvoid R_SplitEntityOnNode (mnode_t *node)\n{\n\tefrag_t\t\t*ef;\n\tmplane_t\t*splitplane;\n\tmleaf_t\t\t*leaf;\n\tint\t\t\tsides;\n\t\n\tif (node->contents == CONTENTS_SOLID)\n\t{\n\t\treturn;\n\t}\n\t\n// add an efrag if the node is a leaf\n\n\tif ( node->contents < 0)\n\t{\n\t\tif (!r_pefragtopnode)\n\t\t\tr_pefragtopnode = node;\n\n\t\tleaf = (mleaf_t *)node;\n\n// grab an efrag off the free list\n\t\tef = cl.free_efrags;\n\t\tif (!ef)\n\t\t{\n\t\t\t// mh - extended efrags - begin\n\t\t\tR_GetMoreEfrags ();\n\t\t\tef = cl.free_efrags;\n\t\t\t// mh - extended efrags - end\n\t\t}\n\t\tcl.free_efrags = cl.free_efrags->entnext;\n\n\t\tef->entity = r_addent;\n\t\t\n// add the entity link\t\n\t\t*lastlink = ef;\n\t\tlastlink = &ef->entnext;\n\t\tef->entnext = NULL;\n\t\t\n// set the leaf links\n\t\tef->leaf = leaf;\n\t\tef->leafnext = leaf->efrags;\n\t\tleaf->efrags = ef;\n\t\t\t\n\t\treturn;\n\t}\n\t\n// NODE_MIXED\n\n\tsplitplane = node->plane;\n\tsides = BOX_ON_PLANE_SIDE(r_emins, r_emaxs, splitplane);\n\t\n\tif (sides == 3)\n\t{\n\t// split on this plane\n\t// if this is the first splitter of this bmodel, remember it\n\t\tif (!r_pefragtopnode)\n\t\t\tr_pefragtopnode = node;\n\t}\n\t\n// recurse down the contacted sides\n\tif (sides & 1)\n\t\tR_SplitEntityOnNode (node->children[0]);\n\t\t\n\tif (sides & 2)\n\t\tR_SplitEntityOnNode (node->children[1]);\n}\n\n\n\n/*\n===========\nR_AddEfrags\n===========\n*/\nvoid R_AddEfrags (entity_t *ent)\n{\n\tmodel_t\t\t*entmodel;\n\tint\t\t\ti;\n\t\t\n\tif (!ent->model)\n\t\treturn;\n\n\tr_addent = ent;\n\t\t\t\n\tlastlink = &ent->efrag;\n\tr_pefragtopnode = NULL;\n\t\n\tentmodel = ent->model;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tr_emins[i] = ent->origin[i] + entmodel->mins[i];\n\t\tr_emaxs[i] = ent->origin[i] + entmodel->maxs[i];\n\t}\n\n\tR_SplitEntityOnNode (cl.worldmodel->nodes);\n\n\tent->topnode = r_pefragtopnode;\n}\n\n\n/*\n================\nR_StoreEfrags\n\n// FIXME: a lot of this goes away with edge-based\n================\n*/\nvoid R_StoreEfrags (efrag_t **ppefrag)\n{\n\tentity_t\t*pent;\n\tmodel_t\t\t*clmodel;\n\tefrag_t\t\t*pefrag;\n\n\n\twhile ((pefrag = *ppefrag) != NULL)\n\t{\n\t\tpent = pefrag->entity;\n\t\tclmodel = pent->model;\n\n\t\tswitch (clmodel->type)\n\t\t{\n\t\tcase mod_alias:\n\t\tcase mod_brush:\n\t\tcase mod_sprite:\n\t\t\tpent = pefrag->entity;\n\n\t\t\tif ((pent->visframe != r_framecount) &&\n\t\t\t\t(cl_numvisedicts < MAX_VISEDICTS))\n\t\t\t{\n\t\t\t\tcl_visedicts[cl_numvisedicts++] = pent;\n\n\t\t\t// mark that we've recorded this entity for this frame\n\t\t\t\tpent->visframe = r_framecount;\n\t\t\t}\n\n\t\t\tppefrag = &pefrag->leafnext;\n\t\t\tbreak;\n\n\t\tdefault:\t\n\t\t\tSys_Error (\"R_StoreEfrags: Bad entity type %d\\n\", clmodel->type);\n\t\t}\n\t}\n}\n\n\n"
  },
  {
    "path": "source/gl_rlight.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_light.c\n\n#include \"quakedef.h\"\n\nint\tr_dlightframecount;\n\n\n/*\n==================\nR_AnimateLight\n==================\n*/\nvoid R_AnimateLight (void)\n{\n\tint\t\t\ti,j,k;\n\t\n//\n// light animations\n// 'm' is normal light, 'a' is no light, 'z' is double bright\n\ti = (int)(cl.time*10);\n\tfor (j=0 ; j<MAX_LIGHTSTYLES ; j++)\n\t{\n\t\tif (!cl_lightstyle[j].length)\n\t\t{\n\t\t\td_lightstylevalue[j] = 256;\n\t\t\tcontinue;\n\t\t}\n\t\tk = i % cl_lightstyle[j].length;\n\t\tk = cl_lightstyle[j].map[k] - 'a';\n\t\tk = k*22;\n\t\td_lightstylevalue[j] = k;\n\t}\t\n}\n\n/*\n=============================================================================\n\nDYNAMIC LIGHTS BLEND RENDERING\n\n=============================================================================\n*/\n\nvoid AddLightBlend (float r, float g, float b, float a2)\n{\n\tfloat\ta;\n\n\tv_blend[3] = a = v_blend[3] + a2*(1-v_blend[3]);\n\n\ta2 = a2/a;\n\n\tv_blend[0] = v_blend[1]*(1-a2) + r*a2;\n\tv_blend[1] = v_blend[1]*(1-a2) + g*a2;\n\tv_blend[2] = v_blend[2]*(1-a2) + b*a2;\n}\n\nvoid R_RenderDlight (dlight_t *light)\n{\n\tint\t\ti, j;\n\tvec3_t\tv;\n\tfloat\trad;\n\t\n\trad = light->radius * 0.35;\n\n\tVectorSubtract (light->origin, r_origin, v);\n\tif (Length (v) < rad)\n\t{\t// view is inside the dlight\n\t\tAddLightBlend (1, 0.5, 0, light->radius * 0.0003);\n\t\treturn;\n\t}\n\t\n\tGL_EnableState(GL_COLOR_ARRAY);\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\tfloat* pPos = gVertexBuffer;\n\tfloat* pColor = gColorBuffer;\n\t*gColorBuffer++ = light->color[0];\n\t*gColorBuffer++ = light->color[1];\n\t*gColorBuffer++ = light->color[2];\n\t*gColorBuffer++ = light->alpha;\n\tfor (i=0 ; i<3 ; i++)\n\t\t*gVertexBuffer++ = light->origin[i] - vpn[i]*rad;\n\tfor (i=16 ; i>=0 ; i--)\n\t{\n\t\t*gColorBuffer++ = 0.8f;\n\t\t*gColorBuffer++ = 0.4f;\n\t\t*gColorBuffer++ = 0.0f;\n\t\t*gColorBuffer++ = 0.0f;\n\t\tfloat cos_rad = costablef[i]*rad;\n\t\tfloat sin_rad = sintablef[i]*rad;\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t*gVertexBuffer++ = light->origin[j] + vright[j]*cos_rad\n\t\t\t\t+ vup[j]*sin_rad;\n\t}\n\tvglVertexAttribPointerMapped(0, pPos);\n\tvglVertexAttribPointerMapped(1, pColor);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 18);\n\tGL_DisableState(GL_COLOR_ARRAY);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\tGL_Color(0,0,0,1); // Ensure the color ends up being zero just like the non-OpenGLES code\n}\n\n/*\n=============\nR_RenderDlights\n=============\n*/\nvoid R_RenderDlights (void)\n{\n\tint\t\ti;\n\tdlight_t\t*l;\n\n\tif (!gl_flashblend.value)\n\t\treturn;\n\n\tr_dlightframecount = r_framecount + 1;\t// because the count hasn't\n\t\t\t\t\t\t\t\t\t\t\t//  advanced yet for this frame\n\tglDepthMask (0);\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t//->glShadeModel (GL_SMOOTH);\n\tglEnable (GL_BLEND);\n\t// glBlendFunc (GL_ONE, GL_ONE);    // 30/01/2000 removed: M.Tretene\n\n\tl = cl_dlights;\n\tfor (i=0 ; i<MAX_DLIGHTS ; i++, l++)\n\t{\n\t\tif (l->die < cl.time || !l->radius)\n\t\t\tcontinue;\n\t\tR_RenderDlight (l);\n\t}\n\n\tGL_Color(1,1,1,1);\n\tglDisable (GL_BLEND);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\t// glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);     // 30/01/2000 removed: M.Tretene\n\tglDepthMask (1);\n}\n\n\n/*\n=============================================================================\n\nDYNAMIC LIGHTS\n\n=============================================================================\n*/\n\n/*\n=============\nR_MarkLights\n=============\n*/\nvoid R_MarkLights (dlight_t *light, int bit, mnode_t *node)\n{\n\tmplane_t\t*splitplane;\n\tfloat\t\tdist;\n\tmsurface_t\t*surf;\n\tint\t\t\ti;\n\t// LordHavoc: .lit support begin (actually this is just a major lighting speedup, no relation to color :)\n\tfloat\t\tl, maxdist;\n\tint\t\t\tj, s, t;\n\tvec3_t\t\timpact;\nloc0:\n\t// LordHavoc: .lit support end\n\n\tif (node->contents < 0)\n\t\treturn;\n\n\tsplitplane = node->plane; // LordHavoc: original code\n\t// LordHavoc: .lit support (actually this is just a major lighting speedup, no relation to color :)\n\tif (splitplane->type < 3)\n\t\tdist = light->origin[splitplane->type] - splitplane->dist;\n\telse\n\t\tdist = DotProduct (light->origin, splitplane->normal) - splitplane->dist; // LordHavoc: original code\n\t// LordHavoc: .lit support end\n\n\tif (dist > light->radius)\n\t{\n\t\t// LordHavoc: .lit support begin (actually this is just a major lighting speedup, no relation to color :)\n\t\tnode = node->children[0];\n\t\tgoto loc0;\n\t\t// LordHavoc: .lit support end\n\t}\n\tif (dist < -light->radius)\n\t{\n\t\t// LordHavoc: .lit support begin (actually this is just a major lighting speedup, no relation to color :)\n\t\tnode = node->children[1];\n\t\tgoto loc0;\n\t\t// LordHavoc: .lit support end\n\t}\n\n\tmaxdist = light->radius*light->radius; // LordHavoc: .lit support (actually this is just a major lighting speedup, no relation to color :)\n// mark the polygons\n\tsurf = cl.worldmodel->surfaces + node->firstsurface;\n\tfor (i=0 ; i<node->numsurfaces ; i++, surf++)\n\t{\n\n\t\t// LordHavoc: .lit support begin (actually this is just a major lighting speedup, no relation to color :)\n\t\t// LordHavoc: MAJOR dynamic light speedup here, eliminates marking of surfaces that are too far away from light, thus preventing unnecessary renders and uploads\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t\timpact[j] = light->origin[j] - surf->plane->normal[j]*dist;\n\t\t// clamp center of light to corner and check brightness\n\t\tl = DotProduct (impact, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3] - surf->texturemins[0];\n\t\ts = l+0.5;if (s < 0) s = 0;else if (s > surf->extents[0]) s = surf->extents[0];\n\t\ts = l - s;\n\t\tl = DotProduct (impact, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3] - surf->texturemins[1];\n\t\tt = l+0.5;if (t < 0) t = 0;else if (t > surf->extents[1]) t = surf->extents[1];\n\t\tt = l - t;\n\t\t// compare to minimum light\n\t\tif ((s*s+t*t+dist*dist) < maxdist)\n\t\t{\n\t\t\tif (surf->dlightframe != r_dlightframecount) // not dynamic until now\n\t\t\t{\n\t\t\t\tsurf->dlightbits = bit;\n\t\t\t\tsurf->dlightframe = r_dlightframecount;\n\t\t\t}\n\t\t\telse // already dynamic\n\t\t\t\tsurf->dlightbits |= bit;\n\t\t}\n\t\t// LordHavoc: .lit support end\n\t}\n\n\t// LordHavoc: .lit support begin (actually this is just a major lighting speedup, no relation to color :)\n\tif (node->children[0]->contents >= 0)\n\t\tR_MarkLights (light, bit, node->children[0]); // LordHavoc: original code\n\tif (node->children[1]->contents >= 0)\n\t\tR_MarkLights (light, bit, node->children[1]); // LordHavoc: original code\n\t// LordHavoc: .lit support end\n}\n\n/*\n=============\nR_PushDlights\n=============\n*/\nvoid R_PushDlights (void)\n{\n\tint\t\ti;\n\tdlight_t\t*l;\n\n\tif (gl_flashblend.value)\n\t\treturn;\n\n\tr_dlightframecount = r_framecount + 1;\t// because the count hasn't\n\t\t\t\t\t\t\t\t\t\t\t//  advanced yet for this frame\n\tl = cl_dlights;\n\n\tfor (i=0 ; i<MAX_DLIGHTS ; i++, l++)\n\t{\n\t\tif (l->die < cl.time || !l->radius)\n\t\t\tcontinue;\n\t\tR_MarkLights ( l, 1<<i, cl.worldmodel->nodes );\n\t}\n}\n\n\n/*\n=============================================================================\nLIGHT SAMPLING\n=============================================================================\n*/\n\nmplane_t\t\t*lightplane;\nvec3_t\t\t\tlightspot;\nvec3_t\t\t\tlightcolor; //johnfitz -- lit support via lordhavoc\n\n// LordHavoc: .lit support begin\n// LordHavoc: original code replaced entirely\nint RecursiveLightPoint (vec3_t color, mnode_t *node, vec3_t start, vec3_t end)\n{\n\tfloat\t\tfront, back, frac;\n\tvec3_t\t\tmid;\n\nloc0:\n\tif (node->contents < 0)\n\t\treturn false;\t\t// didn't hit anything\n\t\n// calculate mid point\n\tif (node->plane->type < 3)\n\t{\n\t\tfront = start[node->plane->type] - node->plane->dist;\n\t\tback = end[node->plane->type] - node->plane->dist;\n\t}\n\telse\n\t{\n\t\tfront = DotProduct(start, node->plane->normal) - node->plane->dist;\n\t\tback = DotProduct(end, node->plane->normal) - node->plane->dist;\n\t}\n\n\t// LordHavoc: optimized recursion\n\tif ((back < 0) == (front < 0))\n//\t\treturn RecursiveLightPoint (color, node->children[front < 0], start, end);\n\t{\n\t\tnode = node->children[front < 0];\n\t\tgoto loc0;\n\t}\n\t\n\tfrac = front / (front-back);\n\tmid[0] = start[0] + (end[0] - start[0])*frac;\n\tmid[1] = start[1] + (end[1] - start[1])*frac;\n\tmid[2] = start[2] + (end[2] - start[2])*frac;\n\t\n// go down front side\n\tif (RecursiveLightPoint (color, node->children[front < 0], start, mid))\n\t\treturn true;\t// hit something\n\telse\n\t{\n\t\tint i, ds, dt;\n\t\tmsurface_t *surf;\n\t// check for impact on this node\n\t\tVectorCopy (mid, lightspot);\n\t\tlightplane = node->plane;\n\n\t\tsurf = cl.worldmodel->surfaces + node->firstsurface;\n\t\tfor (i = 0;i < node->numsurfaces;i++, surf++)\n\t\t{\n\t\t\tif (surf->flags & SURF_DRAWTILED)\n\t\t\t\tcontinue;\t// no lightmaps\n\n\t\t\tds = (int) ((float) DotProduct (mid, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);\n\t\t\tdt = (int) ((float) DotProduct (mid, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);\n\n\t\t\tif (ds < surf->texturemins[0] || dt < surf->texturemins[1])\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tds -= surf->texturemins[0];\n\t\t\tdt -= surf->texturemins[1];\n\t\t\t\n\t\t\tif (ds > surf->extents[0] || dt > surf->extents[1])\n\t\t\t\tcontinue;\n\n\t\t\tif (surf->samples)\n\t\t\t{\n\t\t\t\t// LordHavoc: enhanced to interpolate lighting\n\t\t\t\tbyte *lightmap;\n\t\t\t\tint maps, line3, dsfrac = ds & 15, dtfrac = dt & 15, r00 = 0, g00 = 0, b00 = 0, r01 = 0, g01 = 0, b01 = 0, r10 = 0, g10 = 0, b10 = 0, r11 = 0, g11 = 0, b11 = 0;\n\t\t\t\tfloat scale;\n\t\t\t\tline3 = ((surf->extents[0]>>4)+1)*3;\n\n\t\t\t\tlightmap = surf->samples + ((dt>>4) * ((surf->extents[0]>>4)+1) + (ds>>4))*3; // LordHavoc: *3 for color\n\n\t\t\t\tfor (maps = 0;maps < MAXLIGHTMAPS && surf->styles[maps] != 255;maps++)\n\t\t\t\t{\n\t\t\t\t\tscale = (float) d_lightstylevalue[surf->styles[maps]] * 1.0 / 256.0;\n\t\t\t\t\tr00 += (float) lightmap[      0] * scale;g00 += (float) lightmap[      1] * scale;b00 += (float) lightmap[2] * scale;\n\t\t\t\t\tr01 += (float) lightmap[      3] * scale;g01 += (float) lightmap[      4] * scale;b01 += (float) lightmap[5] * scale;\n\t\t\t\t\tr10 += (float) lightmap[line3+0] * scale;g10 += (float) lightmap[line3+1] * scale;b10 += (float) lightmap[line3+2] * scale;\n\t\t\t\t\tr11 += (float) lightmap[line3+3] * scale;g11 += (float) lightmap[line3+4] * scale;b11 += (float) lightmap[line3+5] * scale;\n\t\t\t\t\tlightmap += ((surf->extents[0]>>4)+1) * ((surf->extents[1]>>4)+1)*3; // LordHavoc: *3 for colored lighting\n\t\t\t\t}\n\n\t\t\t\tcolor[0] += (float) ((int) ((((((((r11-r10) * dsfrac) >> 4) + r10)-((((r01-r00) * dsfrac) >> 4) + r00)) * dtfrac) >> 4) + ((((r01-r00) * dsfrac) >> 4) + r00)));\n\t\t\t\tcolor[1] += (float) ((int) ((((((((g11-g10) * dsfrac) >> 4) + g10)-((((g01-g00) * dsfrac) >> 4) + g00)) * dtfrac) >> 4) + ((((g01-g00) * dsfrac) >> 4) + g00)));\n\t\t\t\tcolor[2] += (float) ((int) ((((((((b11-b10) * dsfrac) >> 4) + b10)-((((b01-b00) * dsfrac) >> 4) + b00)) * dtfrac) >> 4) + ((((b01-b00) * dsfrac) >> 4) + b00)));\n\t\t\t}\n\t\t\treturn true; // success\n\t\t}\n\n\t// go down back side\n\t\treturn RecursiveLightPoint (color, node->children[front >= 0], mid, end);\n\t}\n}\n\nvec3_t lightcolor; // LordHavoc: used by model rendering\nint R_LightPoint (vec3_t p)\n{\n\tvec3_t\t\tend;\n\tif (!cl.worldmodel->lightdata)\n\t{\n\t\tlightcolor[0] = lightcolor[1] = lightcolor[2] = 255;\n\t\treturn 255;\n\t}\n\n\tend[0] = p[0];\n\tend[1] = p[1];\n\tend[2] = p[2] - 8192; //johnfitz -- was 2048\n\tlightcolor[0] = lightcolor[1] = lightcolor[2] = 0;\n\tRecursiveLightPoint (lightcolor, cl.worldmodel->nodes, p, end);\n\treturn ((lightcolor[0] + lightcolor[1] + lightcolor[2]) * (1.0f / 3.0f));\n}\n// LordHavoc: .lit support end\n"
  },
  {
    "path": "source/gl_rmain.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_main.c\n\n#include \"quakedef.h\"\n#include <math_neon.h>\n\nentity_t\tr_worldentity;\n\nbool\tr_cache_thrash;\t\t// compatability\n\nvec3_t\t\tmodelorg, r_entorigin;\nentity_t\t*currententity;\n\nint\t\t\tr_visframecount;\t// bumped when going to a new PVS\nint\t\t\tr_framecount;\t\t// used for dlight push checking\n\nmplane_t\tfrustum[4];\n\nint\t\t\tc_brush_polys, c_alias_polys;\n\nbool\tenvmap;\t\t\t\t// true during envmap command capture \n\nint\t\t\tcurrenttexture = -1;\t\t// to avoid unnecessary texture sets\n\nint\t\t\tcnttextures[2] = {-1, -1};     // cached\n\nint\t\t\tparticletexture;\t// little dot for particles\nint\t\t\tplayertextures;\t\t// up to 16 color translated skins\n\nint\t\t\tmirrortexturenum;\t// quake texturenum, not gltexturenum\nbool\tmirror;\nmplane_t\t*mirror_plane;\n\n//\n// view origin\n//\nvec3_t\tvup;\nvec3_t\tvpn;\nvec3_t\tvright;\nvec3_t\tr_origin;\n\nfloat\tr_world_matrix[16];\nfloat\tr_base_world_matrix[16];\n\nextern\tcvar_t\t\tv_gamma; // muff\nextern\tcvar_t\t\tgl_outline;\n\nfloat r_fovx, r_fovy;\n\n// idea originally nicked from LordHavoc\n// re-worked + extended - muff 5 Feb 2001\n// called inside polyblend\nfloat *gamma_vertices = NULL;\nvoid DoGamma()\n{\n\n\tif (v_gamma.value < 0.2)\n\t\tv_gamma.value = 0.2;\n\n\tif (v_gamma.value >= 1)\n\t{\n\t\tv_gamma.value = 1;\n\t\treturn;\n\t}\n\n\t//believe it or not this actually does brighten the picture!!\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\tglBlendFunc(GL_DST_COLOR, GL_ONE_MINUS_SRC_ALPHA);\n\tfloat color[4] = {1, 1, 1, v_gamma.value};\n\t\n\tif (gamma_vertices == NULL) {\n\t\tgamma_vertices = malloc(3 * 4 * sizeof(float));\n\t\tgamma_vertices[0] = gamma_vertices[3] = gamma_vertices[6] = gamma_vertices[9] = 10;\n\t\tgamma_vertices[1] = gamma_vertices[2] = gamma_vertices[5] = gamma_vertices[10] = 100;\n\t\tgamma_vertices[4] = gamma_vertices[7] = gamma_vertices[8] = gamma_vertices[11] = -100;\n\t}\n\n\tglUniform4fv(monocolor, 1, color);\n\tvglVertexAttribPointerMapped(0, gamma_vertices);\n\t\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n\t\n\t//if we do this twice, we double the brightening effect for a wider range of gamma's\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n}\n\n//\n// screen size info\n//\nrefdef_t\tr_refdef;\n\nmleaf_t\t\t*r_viewleaf, *r_oldviewleaf;\n\ntexture_t\t*r_notexture_mip;\n\nint\t\td_lightstylevalue[256];\t// 8.8 fraction of base light value\n\n\nvoid R_MarkLeaves (void);\n\nCVAR\t(r_norefresh, 0, CVAR_NONE)\nCVAR\t(r_drawentities, 1, CVAR_NONE)\nCVAR\t(r_drawviewmodel, 1, CVAR_ARCHIVE)\nCVAR\t(r_speeds, 0, CVAR_NONE)\nCVAR\t(r_fullbright, 0, CVAR_NONE)\nCVAR\t(r_lightmap, 0, CVAR_NONE)\nCVAR\t(r_shadows, 1, CVAR_ARCHIVE) \nCVAR\t(r_mirroralpha, 0.8, CVAR_ARCHIVE)\nCVAR\t(r_wateralpha, 1.0, CVAR_ARCHIVE)\nCVAR\t(r_dynamic, 1, CVAR_ARCHIVE)\nCVAR\t(r_novis, 0, CVAR_NONE)\nCVAR\t(gl_xflip, 0, CVAR_ARCHIVE)\n\n// fenix@io.com: model interpolation\nCVAR\t(r_interpolate_model_animation, 1, CVAR_ARCHIVE)\nCVAR\t(r_interpolate_model_transform, 1, CVAR_ARCHIVE)\n\nCVAR\t(gl_finish, 0, CVAR_NONE)\nCVAR\t(gl_clear, 0, CVAR_NONE)\nCVAR\t(gl_cull, 1, CVAR_NONE)\nCVAR\t(gl_texsort, 1, CVAR_NONE)\nCVAR\t(gl_smoothmodels, 1, CVAR_NONE)\nCVAR\t(gl_affinemodels, 1, CVAR_NONE)\nCVAR\t(gl_polyblend, 1, CVAR_NONE)\nCVAR\t(gl_flashblend, 0, CVAR_NONE)\nCVAR\t(gl_playermip, 0, CVAR_NONE)\nCVAR\t(gl_nocolors, 0, CVAR_NONE)\nCVAR\t(gl_keeptjunctions, 1, CVAR_NONE)\nCVAR\t(gl_reporttjunctions, 0, CVAR_NONE)\nCVAR\t(gl_doubleeyes, 1, CVAR_NONE)\nCVAR\t(gl_overbright, 0, CVAR_ARCHIVE)\n\n// Torch flares. KH\nCVAR\t(gl_torchflares, 1, CVAR_ARCHIVE)\n\n// BEGIN STEREO DEFS\nint stereoCameraSelect = -1; // 1 = left, -1 = right\nCVAR\t(st_separation, 0, CVAR_ARCHIVE)\t// CON: st_separation -> separation Between Cameras\nCVAR\t(st_zeropdist, 20, CVAR_ARCHIVE)\t// CON: st_zeropdist ->  Dist to zero parallax\nCVAR\t(st_fustbal, 1, CVAR_ARCHIVE)\t\t// CON: st_fustbal ->  frustumBalance adjust\n// END Stereo Defs\n\nextern bool gl_warp;\n\n/*\n=================\nR_CullBox\n\nReturns true if the box is completely outside the frustom\n=================\n*/\nbool R_CullBox (vec3_t mins, vec3_t maxs)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<4 ; i++)\n\t\tif (BoxOnPlaneSide (mins, maxs, &frustum[i]) == 2)\n\t\t\treturn true;\n\treturn false;\n}\n\n\nvoid R_RotateForEntity (entity_t *e)\n{\n    glTranslatef (e->origin[0],  e->origin[1],  e->origin[2]);\n\n    glRotatef (e->angles[1],  0, 0, 1);\n    glRotatef (-e->angles[0],  0, 1, 0);\n    glRotatef (e->angles[2],  1, 0, 0);\n}\n\n\n/*\n=============\nR_BlendedRotateForEntity\n\nfenix@io.com: model transform interpolation\n=============\n*/\nvoid R_BlendedRotateForEntity (entity_t *e)\n{\n\tfloat timepassed;\n\tfloat blend;\n\tvec3_t d;\n\tint i;\n\n\t// positional interpolation\n\n\ttimepassed = realtime - e->translate_start_time; \n\n\tif (e->translate_start_time == 0 || timepassed > 1)\n\t{\n\t\te->translate_start_time = realtime;\n\t\tVectorCopy (e->origin, e->origin1);\n\t\tVectorCopy (e->origin, e->origin2);\n\t}\n\n\tif (!VectorCompare (e->origin, e->origin2))\n\t{\n\t\te->translate_start_time = realtime;\n\t\tVectorCopy (e->origin2, e->origin1);\n\t\tVectorCopy (e->origin,  e->origin2);\n\t\tblend = 0;\n\t}else{\n\t\tblend =  timepassed / 0.1;\n\n\t\tif (cl.paused || blend > 1) blend = 1;\n\t}\n\n\tVectorSubtract (e->origin2, e->origin1, d);\n\n\tglTranslatef (\n\t\te->origin1[0] + (blend * d[0]),\n\t\te->origin1[1] + (blend * d[1]),\n\t\te->origin1[2] + (blend * d[2]));\n\n\t// orientation interpolation (Euler angles, yuck!)\n\n\ttimepassed = realtime - e->rotate_start_time; \n\n\tif (e->rotate_start_time == 0 || timepassed > 1)\n\t{\n\t\te->rotate_start_time = realtime;\n\t\tVectorCopy (e->angles, e->angles1);\n\t\tVectorCopy (e->angles, e->angles2);\n\t}\n\n\tif (!VectorCompare (e->angles, e->angles2))\n\t{\n\t\te->rotate_start_time = realtime;\n\t\tVectorCopy (e->angles2, e->angles1);\n\t\tVectorCopy (e->angles,  e->angles2);\n\t\tblend = 0;\n\t}else{\n\t\tblend = timepassed / 0.1;\n \n\t\tif (cl.paused || blend > 1) blend = 1;\n\t}\n\n\tVectorSubtract (e->angles2, e->angles1, d);\n\n\t// always interpolate along the shortest path\n\tfor (i = 0; i < 3; i++) \n\t{\n\t\tif (d[i] > 180){\n\t\t\td[i] -= 360;\n\t\t}else if (d[i] < -180){\n\t\t\td[i] += 360;\n\t\t}\n\t}\n\n\tglRotatef ( e->angles1[1] + ( blend * d[1]),  0, 0, 1);\n\tglRotatef (-e->angles1[0] + (-blend * d[0]),  0, 1, 0);\n\tglRotatef ( e->angles1[2] + ( blend * d[2]),  1, 0, 0);\n}\n\n/*\n=============================================================\n\n  SPRITE MODELS\n\n=============================================================\n*/\n\n/*\n================\nR_GetSpriteFrame\n================\n*/\nmspriteframe_t *R_GetSpriteFrame (entity_t *currententity)\n{\n\tmsprite_t\t\t*psprite;\n\tmspritegroup_t\t*pspritegroup;\n\tmspriteframe_t\t*pspriteframe;\n\tint\t\t\t\ti, numframes, frame;\n\tfloat\t\t\t*pintervals, fullinterval, targettime, time;\n\n\tpsprite = currententity->model->cache.data;\n\tframe = currententity->frame;\n\n\tif ((frame >= psprite->numframes) || (frame < 0))\n\t{\n\t\tCon_Printf (\"R_DrawSprite: no such frame %d\\n\", frame);\n\t\tframe = 0;\n\t}\n\n\tif (psprite->frames[frame].type == SPR_SINGLE)\n\t{\n\t\tpspriteframe = psprite->frames[frame].frameptr;\n\t}\n\telse\n\t{\n\t\tpspritegroup = (mspritegroup_t *)psprite->frames[frame].frameptr;\n\t\tpintervals = pspritegroup->intervals;\n\t\tnumframes = pspritegroup->numframes;\n\t\tfullinterval = pintervals[numframes-1];\n\n\t\ttime = cl.time + currententity->syncbase;\n\n\t// when loading in Mod_LoadSpriteGroup, we guaranteed all interval values\n\t// are positive, so we don't have to worry about division by 0\n\t\ttargettime = time - ((int)(time / fullinterval)) * fullinterval;\n\n\t\tfor (i=0 ; i<(numframes-1) ; i++)\n\t\t{\n\t\t\tif (pintervals[i] > targettime)\n\t\t\t\tbreak;\n\t\t}\n\n\t\tpspriteframe = pspritegroup->frames[i];\n\t}\n\n\treturn pspriteframe;\n}\n\n\n/*\n=================\nR_DrawSpriteModel\n\n=================\n*/\nfloat *sprite_model_tcoords = NULL;\nvoid R_DrawSpriteModel (entity_t *e)\n{\n\tvec3_t\tpoint;\n\tmspriteframe_t\t*frame;\n\tfloat\t\t*up, *right;\n\tvec3_t\t\tv_forward, v_right, v_up;\n\tmsprite_t\t\t*psprite;\n\n\t// don't even bother culling, because it's just a single\n\t// polygon without a surface cache\n\tframe = R_GetSpriteFrame (e);\n\tpsprite = currententity->model->cache.data;\n\n\tif (psprite->type == SPR_ORIENTED)\n\t{\t// bullet marks on walls\n\t\tAngleVectors (currententity->angles, v_forward, v_right, v_up);\n\t\tup = v_up;\n\t\tright = v_right;\n\t}\n\telse\n\t{\t// normal sprite\n\t\tup = vup;\n\t\tright = vright;\n\t}\n\n\tGL_Color(1,1,1,1);\n\n    GL_Bind(frame->gl_texturenum);\n\tGL_EnableState(GL_ALPHA_TEST);\n\n\tfloat* pPoint = gVertexBuffer;\n\t\n\tif (sprite_model_tcoords == NULL) {\n\t\tsprite_model_tcoords = (float *)malloc(sizeof(float) * 8);\n\t\tsprite_model_tcoords[0] = sprite_model_tcoords[2] = sprite_model_tcoords[3] = sprite_model_tcoords[5] = 0;\n\t\tsprite_model_tcoords[1] = sprite_model_tcoords[4] = sprite_model_tcoords[6] = sprite_model_tcoords[7] = 1;\n\t}\n\t\n\tVectorMA (e->origin, frame->down, up, point);\n\tVectorMA (point, frame->left, right, gVertexBuffer);\n\tgVertexBuffer += 3;\n\n\tVectorMA (e->origin, frame->up, up, point);\n\tVectorMA (point, frame->left, right, gVertexBuffer);\n\tgVertexBuffer += 3;\n\n\tVectorMA (e->origin, frame->up, up, point);\n\tVectorMA (point, frame->right, right, gVertexBuffer);\n\tgVertexBuffer += 3;\n\n\tVectorMA (e->origin, frame->down, up, point);\n\tVectorMA (point, frame->right, right, gVertexBuffer);\n\tgVertexBuffer += 3;\n\t\n\tvglVertexAttribPointerMapped(0, pPoint);\n\tvglVertexAttribPointerMapped(1, sprite_model_tcoords);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n\t\n\n\tGL_DisableState(GL_ALPHA_TEST);\n\n}\n\n/*\n=============================================================\n\n  ALIAS MODELS\n\n=============================================================\n*/\n\n\n#define NUMVERTEXNORMALS\t162\n\nconst float\tr_avertexnormals[NUMVERTEXNORMALS][3] = {\n#include \"anorms.h\"\n};\n\nvec3_t\tshadevector;\nextern vec3_t lightcolor; // LordHavoc: .lit support to the definitions at the top\n\n// precalculated dot products for quantized angles\n#define SHADEDOT_QUANT 16\nconst float\tr_avertexnormal_dots[SHADEDOT_QUANT][256] =\n#include \"anorm_dots.h\"\n;\n\nfloat\t*shadedots = (float*)r_avertexnormal_dots[0];\n\nint\tlastposenum;\n\n// fenix@io.com: model animation interpolation\nint lastposenum0;\n\n//  Gongo - cel shade tutorial\n//  cel shading table\nfloat celshade[16] = { 0.2, 0.2, 0.2, 0.5, 0.5, 0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };\n\n/*\n=============\nGL_DrawAliasFrame\n=============\n*/\nvoid GL_DrawAliasFrame (aliashdr_t *paliashdr, int posenum)\n{\n\tint\t\t\ti;  //  for \"for\" loops\n\tvec3_t\t\tl;  //  new - used for cel shading\n\tfloat\t\tl2;  //  cel shading lookup value\n\ttrivertx_t *verts;\n\tint\t\t*order;\n\tint\t\tcount;\n\t\n\tGL_EnableState(GL_COLOR_ARRAY);\n\t\n\tlastposenum = posenum;\n\n\tverts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\tverts += posenum * paliashdr->poseverts;\n\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\t\n\twhile (1)\n\t{\n\t\t// get the vertex count and primitive type\n\t\tcount = *order++;\n\t\tif (!count)\n\t\t\tbreak;\t\t// done\n\t\t\n\t\tint primType;\n\t\tif (count < 0)\n\t\t{\n\t\t\tcount = -count;\n\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t}\n\t\telse\n\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t\n\t\tfloat *pColor = gColorBuffer;\n\t\tfloat *pPos = gVertexBuffer;\n\t\tfloat *pTexCoord = gTexCoordBuffer;\n\t\tint c;\n\t\tfor (c = 0; c < count; ++c)\n\t\t{\n\t\t\t// texture coordinates come from the draw list\n\t\t\t*gTexCoordBuffer++ = ((float *)order)[0];\n\t\t\t*gTexCoordBuffer++ = ((float *)order)[1];\n\t\t\torder += 2;\n\t\t\t\n\t\t\t//  calculate light as vector so that intensity is it's length\n\t\t\tfor ( i = 0; i < 3; i++ )\n\t\t\t{\n\t\t\t\tif (r_fullbright.value || !cl.worldmodel->lightdata) {\n\t\t\t\t\tl[i] = lightcolor[i];\n\t\t\t\t} else {\n\t\t\t\t\tl[i] = shadedots[verts->lightnormalindex] * lightcolor[i];  //  shade as usual\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tif (gl_outline.value > 0)\n\t\t\t{\n\t\t\t\tl2 = sqrt( (l[0]*l[0]) + (l[1]*l[1]) + (l[2]*l[2]) );  // get the length of the lighting vector (intensity)\n\t\t\t\tif ( l2 > 1.0 )  // if it's greater than 1.0\n\t\t\t\t\tl2 = 1.0;  //  we'll clamp down to 1.0, since it'll be the same shade anyway\n\t\t\t\tl2 = celshade[(int)(l2 * 15)];  //  lookup the value in the cel shade lighting table\n\t\t\t\tl2 *= 1.25;  //  brighten things up a bit\n\t\t\t\tVectorNormalize (l);  //  bring the lighting vector length to 1 so that we can scale it to exactly the value we want\n\t\t\t\tVectorScale (l, l2, l);  //  scale the light to the clamped cel shaded value\n\t\t\t\tfor ( i = 0; i < 3; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( l[i] > 1.0 )  //  check for overbrights\n\t\t\t\t\t\tl[i] = 1.0;  //  clamp down to 1.0\n\t\t\t\t\tif ( l[i] <= 0.0 )  //  check for no light\n\t\t\t\t\t\tl[i] = 0.15;  //  provide some minimum light\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t*gColorBuffer++ = l[0];\n\t\t\t*gColorBuffer++ = l[1];\n\t\t\t*gColorBuffer++ = l[2];\n\t\t\t*gColorBuffer++ = 1.0f;\n\t\t\t*gVertexBuffer++ = verts->v[0];\n\t\t\t*gVertexBuffer++ = verts->v[1];\n\t\t\t*gVertexBuffer++ = verts->v[2];\n\t\t\t++verts;\n\t\t}\n\t\t\n\t\tvglVertexAttribPointerMapped(0, pPos);\n\t\tvglVertexAttribPointerMapped(1, pTexCoord);\n\t\tvglVertexAttribPointerMapped(2, pColor);\n\t\tGL_DrawPolygon(primType, count);\n\t\t\n\t}\n\t\n\tGL_DisableState(GL_COLOR_ARRAY);\n\t\n\tif (gl_outline.value > 0) {\n\t\n\t\tverts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\t\tverts += posenum * paliashdr->poseverts;\n\t\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\t\n\t\tglPolygonMode (GL_BACK, GL_LINE);  //  we're drawing the outlined edges\n\t\tglEnable (GL_CULL_FACE);  //  enable culling so that we don't draw the entire wireframe\n\t\tglLineWidth(gl_outline.value);\n\t\tglCullFace (GL_FRONT);  //  get rid of the front facing wireframe\n\t\tglFrontFace (GL_CW);  //  hack to avoid using the depth buffer tests\n\t\tglEnable (GL_BLEND);\n\t\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  //  make sure the outline shows up\n\t\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\n\t\twhile (1)\n\t\t{\n\t\t\t// get the vertex count and primitive type\n\t\t\tcount = *order++;\n\t\t\tif (!count)\n\t\t\t\tbreak;\t\t// done\n\t\t\t\n\t\t\tint primType;\n\t\t\tif (count < 0)\n\t\t\t{\n\t\t\t\tcount = -count;\n\t\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t\t}\n\t\t\telse\n\t\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t\t\n\t\t\tfloat *pPos = gVertexBuffer;\n\t\t\tint c;\n\t\t\tfor (c = 0; c < count; ++c)\n\t\t\t{\n\t\t\t\torder += 2;\n\t\t\t\n\t\t\t\t*gVertexBuffer++ = verts->v[0];\n\t\t\t\t*gVertexBuffer++ = verts->v[1];\n\t\t\t\t*gVertexBuffer++ = verts->v[2];\n\t\t\t\t++verts;\n\t\t\t}\n\t\t\t\n\t\t\tfloat color[] = {0.0f, 0.0f, 0.0f, 1.0f};\n\t\t\tglUniform4fv(monocolor, 1, color);\n\t\t\tvglVertexAttribPointerMapped(0, pPos);\n\t\t\tGL_DrawPolygon(primType, count);\n\t\t\n\t\t}\n\t\t\n\t\tglPolygonMode (GL_BACK, GL_FILL);  //  get out of wireframe mode\n\t\tglFrontFace (GL_CCW);  //  end of hack for depth buffer\n\t\tglCullFace (GL_BACK);  //  back to normal face culling\n\t\tglDisable (GL_CULL_FACE);\n\t\tglDisable (GL_BLEND);\n\t\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\t\n\t}\n\t\n}\n\n/*\n=============\nGL_DrawAliasBlendedFrame\n\nfenix@io.com: model animation interpolation\n=============\n*/\nvoid GL_DrawAliasBlendedFrame (aliashdr_t *paliashdr, int pose1, int pose2, float blend)\n{\n\tint\t\t\ti;  //  for \"for\" loops\n\tvec3_t\t\tl;  //  new - used for cel shading\n\tfloat\t\tl2;  //  cel shading lookup value\n\ttrivertx_t* verts1;\n\ttrivertx_t* verts2;\n\tint*\t\torder;\n\tint\t\t count;\n\tvec3_t\t  d;\n\textern vec3_t lightcolor; // LordHavoc: .lit support to the definitions at the top\n\t\n\tGL_EnableState(GL_COLOR_ARRAY);\t\n\t\t\n\tlastposenum0 = pose1;\n\tlastposenum  = pose2;\n\t\t\n\tverts1  = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\tverts2  = verts1;\n\n\tverts1 += pose1 * paliashdr->poseverts;\n\tverts2 += pose2 * paliashdr->poseverts;\n\n\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\t\t\t\n\tfor (;;)\n\t{\n\t\t// get the vertex count and primitive type\n\t\tcount = *order++;\n\t\t\n\t\tif (!count) break;\n\t\t\n\t\tint primType;\n\t\tint c;\n\t\tif (count < 0)\n\t\t{\n\t\t\tcount = -count;\n\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t}else{\n\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t}\n\n\t\tfloat *pColor = gColorBuffer;\n\t\tfloat *pPos = gVertexBuffer;\n\t\tfloat *pTexCoord = gTexCoordBuffer;\n\t\tc = count;\n\t\tdo\n\t\t{\n\t\t\t// texture coordinates come from the draw list\n\t\t\t*gTexCoordBuffer++ = ((float *)order)[0];\n\t\t\t*gTexCoordBuffer++ = ((float *)order)[1];\n\t\t\torder += 2;\n\n\t\t\t// normals and vertexes come from the frame list\n\t\t\t// blend the light intensity from the two frames together\n\t\t\td[0] = shadedots[verts2->lightnormalindex] -\n\t\t\t\tshadedots[verts1->lightnormalindex];\n\t\t\t\n\t\t\t//  calculate light as vector so that intensity is it's length\n\t\t\tfor ( i = 0; i < 3; i++ )\n\t\t\t{\n\t\t\t\tl[i] = (shadedots[verts1->lightnormalindex] + (blend * d[0]));  //  shade as usual\n\t\t\t\tl[i] *= lightcolor[i];  //  apply colored lighting\n\n\t\t\t}\n\n\t\t\tif (gl_outline.value > 0)\n\t\t\t{\n\t\t\t\tl2 = sqrt( (l[0]*l[0]) + (l[1]*l[1]) + (l[2]*l[2]) );  // get the length of the lighting vector (intensity)\n\t\t\t\tif ( l2 > 1.0 )  // if it's greater than 1.0\n\t\t\t\t\tl2 = 1.0;  //  we'll clamp down to 1.0, since it'll be the same shade anyway\n\t\t\t\tl2 = celshade[(int)(l2 * 15)];  //  lookup the value in the cel shade lighting table\n\t\t\t\tl2 *= 1.25;  //  brighten things up a bit\n\t\t\t\tVectorNormalize (l);  //  bring the lighting vector length to 1 so that we can scale it to exactly the value we want\n\t\t\t\tVectorScale (l, l2, l);  //  scale the light to the clamped cel shaded value\n\t\t\t\tfor ( i = 0; i < 3; i++ )\n\t\t\t\t{\n\t\t\t\t\tif ( l[i] > 1.0 )  //  check for overbrights\n\t\t\t\t\t\tl[i] = 1.0;  //  clamp down to 1.0\n\t\t\t\t\tif ( l[i] <= 0.0 )  //  check for no light\n\t\t\t\t\t\tl[i] = 0.15;  //  provide some minimum light\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\t*gColorBuffer++ = l[0];\n\t\t\t*gColorBuffer++ = l[1];\n\t\t\t*gColorBuffer++ = l[2];\n\t\t\t*gColorBuffer++ = 1.0f;\n\t\t\t\n\t\t\tVectorSubtract(verts2->v, verts1->v, d);\n\n\t\t\t// blend the vertex positions from each frame together\n\t\t\t*gVertexBuffer++ = verts1->v[0] + (blend * d[0]);\n\t\t\t*gVertexBuffer++ = verts1->v[1] + (blend * d[1]);\n\t\t\t*gVertexBuffer++ = verts1->v[2] + (blend * d[2]);\n\n\t\t\tverts1++;\n\t\t\tverts2++;\n\t\t} while (--count);\n\t\t\n\t\tvglVertexAttribPointerMapped(0, pPos);\n\t\tvglVertexAttribPointerMapped(1, pTexCoord);\n\t\tvglVertexAttribPointerMapped(2, pColor);\n\t\tGL_DrawPolygon(primType, c);\n\t}\n\t\n\tGL_DisableState(GL_COLOR_ARRAY);\n\t\n\tif (gl_outline.value > 0) {\n\t\n\t\tverts1  = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\t\tverts2  = verts1;\n\n\t\tverts1 += pose1 * paliashdr->poseverts;\n\t\tverts2 += pose2 * paliashdr->poseverts;\n\n\t\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\t\n\t\tglPolygonMode (GL_BACK, GL_LINE);  //  we're drawing the outlined edges\n\t\tglEnable (GL_CULL_FACE);  //  enable culling so that we don't draw the entire wireframe\n\t\tglLineWidth(gl_outline.value);\n\t\tglCullFace (GL_FRONT);  //  get rid of the front facing wireframe\n\t\tglFrontFace (GL_CW);  //  hack to avoid using the depth buffer tests\n\t\tglEnable (GL_BLEND);\n\t\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);  //  make sure the outline shows up\n\t\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\n\t\tfor (;;)\n\t\t{\n\t\t\t// get the vertex count and primitive type\n\t\t\tcount = *order++;\n\t\t\n\t\t\tif (!count) break;\n\t\t\n\t\t\tint primType;\n\t\t\tint c;\n\t\t\tif (count < 0)\n\t\t\t{\n\t\t\t\tcount = -count;\n\t\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t\t}else{\n\t\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t\t}\n\n\t\t\tfloat *pPos = gVertexBuffer;\n\t\t\tc = count;\n\t\t\n\t\t\t//  now draw the model again\n\t\t\tdo\n\t\t\t{\n\t\t\t\n\t\t\t\torder += 2;\n\t\t\t\n\t\t\t\tVectorSubtract(verts2->v, verts1->v, d);\n\n\t\t\t\t// blend the vertex positions from each frame together\n\t\t\t\t*gVertexBuffer++ = verts1->v[0] + (blend * d[0]);\n\t\t\t\t*gVertexBuffer++ = verts1->v[1] + (blend * d[1]);\n\t\t\t\t*gVertexBuffer++ = verts1->v[2] + (blend * d[2]);\n\n\t\t\t\tverts1++;\n\t\t\t\tverts2++;\n\t\t\t} while (--count);\n\t\t\n\t\t\tfloat color[] = {0.0f, 0.0f, 0.0f, 1.0f};\n\t\t\tglUniform4fv(monocolor, 1, color);\n\t\t\tvglVertexAttribPointerMapped(0, pPos);\n\t\t\tGL_DrawPolygon(primType, c);\n\t\t}\n\t\n\t\tglPolygonMode (GL_BACK, GL_FILL);  //  get out of wireframe mode\n\t\tglFrontFace (GL_CCW);  //  end of hack for depth buffer\n\t\tglCullFace (GL_BACK);  //  back to normal face culling\n\t\tglDisable (GL_CULL_FACE);\n\t\tglDisable (GL_BLEND);\n\t\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\t\n\t}\n\t\n}\n\n/*\n=============\nGL_DrawAliasShadow\n=============\n*/\nextern\tvec3_t\t\t\tlightspot;\n\nvoid GL_DrawAliasShadow (aliashdr_t *paliashdr, int posenum)\n{\n\tfloat\ts, t, l;\n\tint\t\ti, j;\n\tint\t\tindex;\n\ttrivertx_t\t*v, *verts;\n\tint\t\tlist;\n\tint\t\t*order;\n\tvec3_t\tpoint;\n\tfloat\t*normal;\n\tfloat\theight, lheight;\n\tint\t\tcount;\n\n\tlheight = currententity->origin[2] - lightspot[2];\n\n\theight = 0;\n\tverts = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\tverts += posenum * paliashdr->poseverts;\n\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\n\theight = -lheight + 1.0;\n\n\twhile (1)\n\t{\n\t\t// get the vertex count and primitive type\n\t\tcount = *order++;\n\t\tif (!count)\n\t\t\tbreak;\t\t// done\n\t\t\n\t\tint primType;\n\t\tint c;\n\t\tfloat* pVertex;\n\t\t\n\t\tif (count < 0)\n\t\t{\n\t\t\tcount = -count;\n\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t}else\n\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t\n\t\tpVertex = gVertexBuffer;\n\t\tfor(c = 0; c < count; c++)\n\t\t{\n\t\t\t// texture coordinates come from the draw list\n\t\t\t// (skipped for shadows) glTexCoord2fv ((float *)order);\n\t\t\torder += 2;\n\n\t\t\t// normals and vertexes come from the frame list\n\t\t\tgVertexBuffer[0] = verts->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];\n\t\t\tgVertexBuffer[1] = verts->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];\n\t\t\tgVertexBuffer[2] = verts->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];\n\n\t\t\tgVertexBuffer[0] -= shadevector[0]*(pVertex[2]+lheight);\n\t\t\tgVertexBuffer[1] -= shadevector[1]*(pVertex[2]+lheight);\n\t\t\tgVertexBuffer[2] = height;\n\t//\t\theight -= 0.001;\n\n\t\t\tgVertexBuffer += 3;\n\t\t\tverts++;\n\t\t\t\n\t\t}\n\n\t\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\tconst float color[] = {0,0,0,0.5f};\n\t\tglUniform4fv(monocolor, 1, color);\n\t\tvglVertexAttribPointerMapped(0, pVertex);\n\t\tGL_DrawPolygon(primType, count);\n\t\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\t}\t\n}\n\n/*\n=============\nGL_DrawAliasBlendedShadow\n\nfenix@io.com: model animation interpolation\n=============\n*/\nvoid GL_DrawAliasBlendedShadow (aliashdr_t *paliashdr, int pose1, int pose2, entity_t* e)\n{\n\ttrivertx_t* verts1;\n\ttrivertx_t* verts2;\n\tint*\t\t  order;\n\tvec3_t\t\tpoint1;\n\tvec3_t\t\tpoint2;\n\tvec3_t\t\td;\n\tfloat\t\t height;\n\tfloat\t\t lheight;\n\tint count;\n\tfloat\t\t blend;\n\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\n\tblend = (realtime - e->frame_start_time) / e->frame_interval;\n\n\tif (blend > 1) blend = 1;\n\n\tlheight = e->origin[2] - lightspot[2];\n\theight  = -lheight + 1.0;\n\n\tverts1 = (trivertx_t *)((byte *)paliashdr + paliashdr->posedata);\n\tverts2 = verts1;\n\n\tverts1 += pose1 * paliashdr->poseverts;\n\tverts2 += pose2 * paliashdr->poseverts;\n\n\torder = (int *)((byte *)paliashdr + paliashdr->commands);\n\n\tfor (;;){\n\t\t// get the vertex count and primitive type\n\t\tcount = *order++;\n\n\t\tif (!count) break;\n\n\t\tint primType;\n\t\tint c;\n\t\tfloat* pVertex;\n\t\t\n\t\tif (count < 0){\n\t\t\tcount = -count;\n\t\t\tprimType = GL_TRIANGLE_FAN;\n\t\t}else{\n\t\t\tprimType = GL_TRIANGLE_STRIP;\n\t\t}\n\n\t\tpVertex = gVertexBuffer;\n\t\tc = count;\n\t\tdo{\n\t\t\torder += 2;\n\n\t\t\tpoint1[0] = verts1->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];\n\t\t\tpoint1[1] = verts1->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];\n\t\t\tpoint1[2] = verts1->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];\n\t\t  \n\t\t\tpoint1[0] -= shadevector[0]*(point1[2]+lheight);\n\t\t\tpoint1[1] -= shadevector[1]*(point1[2]+lheight);\n\n\t\t\tpoint2[0] = verts2->v[0] * paliashdr->scale[0] + paliashdr->scale_origin[0];\n\t\t\tpoint2[1] = verts2->v[1] * paliashdr->scale[1] + paliashdr->scale_origin[1];\n\t\t\tpoint2[2] = verts2->v[2] * paliashdr->scale[2] + paliashdr->scale_origin[2];\n\n\t\t\tpoint2[0] -= shadevector[0]*(point2[2]+lheight);\n\t\t\tpoint2[1] -= shadevector[1]*(point2[2]+lheight);\n\n\t\t\tVectorSubtract(point2, point1, d);\n\t\t\t\n\t\t\tgVertexBuffer[0] = point1[0] + (blend * d[0]);\n\t\t\tgVertexBuffer[1] = point1[1] + (blend * d[1]);\n\t\t\tgVertexBuffer[2] = height;\n\t\t\tgVertexBuffer += 3;\n\t\t\t\n\t\t\tverts1++;\n\t\t\tverts2++;\n\t\t} while (--count);\n\n\t\tconst float color[4] = {0,0,0,0.5f};\n\t\tglUniform4fv(monocolor, 1, color);\n\t\tvglVertexAttribPointerMapped(0, pVertex);\n\t\tGL_DrawPolygon(primType, c);\n\t}\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n}\n\n/*\n=================\nR_SetupAliasFrame\n\n=================\n*/\nvoid R_SetupAliasFrame (int frame, aliashdr_t *paliashdr)\n{\n\tint\t\t\t\tpose, numposes;\n\tfloat\t\t\tinterval;\n\n\tif ((frame >= paliashdr->numframes) || (frame < 0))\n\t{\n\t\tCon_DPrintf (\"R_AliasSetupFrame: no such frame %d\\n\", frame);\n\t\tframe = 0;\n\t}\n\n\tpose = paliashdr->frames[frame].firstpose;\n\tnumposes = paliashdr->frames[frame].numposes;\n\n\tif (numposes > 1)\n\t{\n\t\tinterval = paliashdr->frames[frame].interval;\n\t\tpose += (int)(cl.time / interval) % numposes;\n\t}\n\n\tGL_DrawAliasFrame (paliashdr, pose);\n}\n\n/*\n=================\nR_SetupAliasBlendedFrame\n\nfenix@io.com: model animation interpolation\n=================\n*/\nvoid R_SetupAliasBlendedFrame (int frame, aliashdr_t *paliashdr, entity_t* e)\n{\n\tint\tpose;\n\tint\tnumposes;\n\tfloat blend;\n\n\tif ((frame >= paliashdr->numframes) || (frame < 0))\n\t{\n\t\tCon_DPrintf (\"R_AliasSetupFrame: no such frame %d\\n\", frame);\n\t\tframe = 0;\n\t}\n\n\tpose = paliashdr->frames[frame].firstpose;\n\tnumposes = paliashdr->frames[frame].numposes;\n\n\tif (numposes > 1)\n\t{\n\t\te->frame_interval = paliashdr->frames[frame].interval;\n\t\tpose += (int)(cl.time / e->frame_interval) % numposes;\n\t}else {\n\t\t/* One tenth of a second is a good for most Quake animations.\n\t\tIf the nextthink is longer then the animation is usually meant to pause\n\t\t(e.g. check out the shambler magic animation in shambler.qc).  If its\n\t\tshorter then things will still be smoothed partly, and the jumps will be\n\t\tless noticable because of the shorter time.  So, this is probably a good\n\t\tassumption. */\n\t\te->frame_interval = 0.1;\n\t}\n\n\tif (e->pose2 != pose)\n\t{\n\t\te->frame_start_time = realtime;\n\t\te->pose1 = e->pose2;\n\t\te->pose2 = pose;\n\t\tblend = 0;\n\t}else{\n\t\tblend = (realtime - e->frame_start_time) / e->frame_interval;\n\t}\n\t\t\n\t// wierd things start happening if blend passes 1\n\tif (cl.paused || blend > 1) blend = 1;\n\t\n\tGL_DrawAliasBlendedFrame (paliashdr, e->pose1, e->pose2, blend);\n}\n\n/*\n=================\nR_DrawAliasModel\n\n=================\n*/\nvoid R_DrawAliasModel (entity_t *e)\n{\n\tint\t\t\ti, j;\n\tint\t\t\tlnum;\n\tvec3_t\t\tdist;\n\tfloat\t\tadd;\n\tmodel_t\t\t*clmodel;\n\tvec3_t\t\tmins, maxs;\n\taliashdr_t\t*paliashdr;\n\ttrivertx_t\t*verts, *v;\n\tint\t\t\tindex;\n\tfloat\t\ts, t, an;\n\tint\t\t\tanim;\n\t\n\tbool    torch = false; // Flags is this model is a torch\n\n\tclmodel = currententity->model;\n\n\tVectorAdd (currententity->origin, clmodel->mins, mins);\n\tVectorAdd (currententity->origin, clmodel->maxs, maxs);\n\n\tif (R_CullBox (mins, maxs))\n\t\treturn;\n\n\n\tVectorCopy (currententity->origin, r_entorigin);\n\tVectorSubtract (r_origin, r_entorigin, modelorg);\n\t\n\t//\n\t// get lighting information\n\t//\n\t// LordHavoc: .lit support begin\n\tR_LightPoint(currententity->origin); // LordHavoc: lightcolor is all that matters from this\n\t// LordHavoc: .lit support end\n\n\t// LordHavoc: .lit support begin\n\tif (e == &cl.viewent)\n\t{\n\t\tif (lightcolor[0] < 24)\n\t\t\tlightcolor[0] = 24;\n\t\tif (lightcolor[1] < 24)\n\t\t\tlightcolor[1] = 24;\n\t\tif (lightcolor[2] < 24)\n\t\t\tlightcolor[2] = 24;\n\t}\n\t// LordHavoc: .lit support end\n\n\tfor (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)\n\t{\n\t\tif (cl_dlights[lnum].die >= cl.time)\n\t\t{\n\t\t\tVectorSubtract (currententity->origin,\n\t\t\t\t\t\t\tcl_dlights[lnum].origin,\n\t\t\t\t\t\t\tdist);\n\t\t\tadd = cl_dlights[lnum].radius - Length(dist);\n\t\t\t// LordHavoc: .lit support begin\n\t\t\tif (add > 0)\n\t\t\t{\n\t\t\t\tlightcolor[0] += add * cl_dlights[lnum].color[0];\n\t\t\t\tlightcolor[1] += add * cl_dlights[lnum].color[1];\n\t\t\t\tlightcolor[2] += add * cl_dlights[lnum].color[2];\n\t\t\t}\n\t\t\t// LordHavoc: .lit support end\n\t\t}\n\t}\n\n\t// ZOID: never allow players to go totally black\n\ti = currententity - cl_entities;\n\tif (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, \"progs/player.mdl\") */)\n\t{\n\t\t// LordHavoc: .lit support begin\n\t\tif (lightcolor[0] < 8)\n\t\t\tlightcolor[0] = 8;\n\t\tif (lightcolor[1] < 8)\n\t\t\tlightcolor[1] = 8;\n\t\tif (lightcolor[2] < 8)\n\t\t\tlightcolor[2] = 8;\n\t\t// LordHavoc: .lit support end\n\t}\n\n\t// HACK HACK HACK -- no fullbright colors, so make torches full light\n\tif (!strcmp (clmodel->name, \"progs/flame2.mdl\")\n\t\t|| !strcmp (clmodel->name, \"progs/flame.mdl\") )\n\t{\n\t\ttorch = true; // This model is a torch. KH\n\t\t// LordHavoc: .lit support begin\n\t\tlightcolor[0] = lightcolor[1] = lightcolor[2] = 256;\n\t\t// LordHavoc: .lit support end\n\t}\n\t\n\tshadedots = (float*)r_avertexnormal_dots[((int)(e->angles[1] * (SHADEDOT_QUANT / 360.0))) & (SHADEDOT_QUANT - 1)];\n\t// LordHavoc: .lit support begin\n\tVectorScale(lightcolor, 1.0f / 200.0f, lightcolor);\n\t// LordHavoc: .lit support end\n\t\n\tfloat cs[2];\n\tan = e->angles[1]/180*M_PI;\n\tsincosf_neon(-an, cs);\n\tshadevector[0] = cs[1];\n\tshadevector[1] = cs[0];\n\tshadevector[2] = 1;\n\tVectorNormalize (shadevector);\n\n\t//\n\t// locate the proper data\n\t//\n\tpaliashdr = (aliashdr_t *)Mod_Extradata (currententity->model);\n\n\tc_alias_polys += paliashdr->numtris;\n\n\t//\n\t// draw all the triangles\n\t//\n\n    glPushMatrix ();\n\t\n\t// fenix@io.com: model transform interpolation\n\tif (r_interpolate_model_transform.value){\n\t\tR_BlendedRotateForEntity (e);\n\t}else{\n\t\tR_RotateForEntity (e);\n\t}\n\n\tif (!strcmp (clmodel->name, \"progs/eyes.mdl\") && gl_doubleeyes.value) {\n\t\tglTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2] - 30);\n// double size of eyes, since they are really hard to see in gl\n\t\tglScalef (paliashdr->scale[0]*2, paliashdr->scale[1]*2, paliashdr->scale[2]*2);\n\t} else {\n\t\tglTranslatef (paliashdr->scale_origin[0], paliashdr->scale_origin[1], paliashdr->scale_origin[2]);\n\t\tglScalef (paliashdr->scale[0], paliashdr->scale[1], paliashdr->scale[2]);\n\t}\n\n\tanim = (int)(cl.time*10) & 3;\n    GL_Bind(paliashdr->gl_texturenum[currententity->skinnum][anim]);\n\n\t// we can't dynamically colormap textures, so they are cached\n\t// seperately for the players.  Heads are just uncolored.\n\tif (currententity->colormap != vid.colormap && !gl_nocolors.value)\n\t{\n\t\ti = currententity - cl_entities;\n\t\tif (i >= 1 && i<=cl.maxclients /* && !strcmp (currententity->model->name, \"progs/player.mdl\") */)\n\t\t    GL_Bind(playertextures - 1 + i);\n\t}\n\n\t//->if (gl_smoothmodels.value)\n\t//->\tglShadeModel (GL_SMOOTH);\n\tGL_EnableState(GL_MODULATE);\n\n\t//->if (gl_affinemodels.value)\n\t//->\tglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);\n\n\t// fenix@io.com: model animation interpolation\n\tif (r_interpolate_model_animation.value)\n\t{\n\t\tR_SetupAliasBlendedFrame (currententity->frame, paliashdr, currententity);\n\t}else{\n\t\tR_SetupAliasFrame (currententity->frame, paliashdr);\n\t}\n\n\tGL_EnableState(GL_REPLACE);\n\n\t//->glShadeModel (GL_FLAT);\n\t//->if (gl_affinemodels.value)\n\t//->\tglHint (GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);\n\n\tglPopMatrix ();\n\t\n\tif (torch && gl_torchflares.value) {\n\t\t// Draw torch flares. KH\n\t\t// NOTE: It would be better if we batched these up.\n\t\t//       All those state changes are not nice. KH\n\t\t\n\t\t// This relies on unchanged game code!\n\t\tconst int TORCH_STYLE = 1; // Flicker.\n\n\t\tvec3_t  lightorigin;    // Origin of torch.\n\t\tvec3_t  v;              // Vector to torch.\n\t\tfloat   radius;         // Radius of torch flare.\n\t\tfloat   distance;       // Vector distance to torch.\n\t\tfloat   intensity;      // Intensity of torch flare.\n\n\t\t// NOTE: I don't think this is centered on the model.\n\t\tVectorCopy(currententity->origin, lightorigin);\n\n\t\tradius = 20.0f;\n\t\tVectorSubtract(lightorigin, r_origin, v);\n\n\t\t// See if view is outside the light.\n\t\tdistance = Length(v);\n\t\tif (distance > radius) {\n\t\t    glDepthMask (0);\n\t\t    //->glShadeModel (GL_SMOOTH);\n\t\t    glEnable (GL_BLEND);\n\t\t    glBlendFunc (GL_ONE, GL_ONE);\n\n\t\t    // Translate the glow to coincide with the flame. KH\n\t\t    glPushMatrix();\n\t\t    glTranslatef(0.0f, 0.0f, 8.0f);\n\t\t\t\n\t\t\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\t\tGL_EnableState(GL_COLOR_ARRAY);\n\t\t\tfloat* pPos = gVertexBuffer;\n\t\t\tfloat* pColor = gColorBuffer;\n\t\t\t\n\t\t    // Diminish torch flare inversely with distance.\n\t\t    intensity = (1024.0f - distance) / 1024.0f;\n\n\t\t    // Invert (fades as you approach).\n\t\t    intensity = (1.0f - intensity);\n\n\t\t    // Clamp, but don't let the flare disappear.\n\t\t    if (intensity > 1.0f) intensity = 1.0f;\n\t\t    if (intensity < 0.0f) intensity = 0.0f;\n\n\t\t    // Now modulate with flicker.\n\t\t    i = (int)(cl.time*10);\n\t\t    if (!cl_lightstyle[TORCH_STYLE].length) {\n\t\t        j = 256;\n\t\t    } else {\n\t\t        j = i % cl_lightstyle[TORCH_STYLE].length;\n\t\t        j = cl_lightstyle[TORCH_STYLE].map[j] - 'a';\n\t\t        j = j*22;\n\t\t    }\n\t\t    intensity *= ((float)j / 255.0f);\n\n\t\t    // Set yellow intensity\t\t\t\n\t\t\t*gColorBuffer++ = 0.8f*intensity;\n\t\t\t*gColorBuffer++ = 0.4f*intensity;\n\t\t\t*gColorBuffer++ = 0.1f;\n\t\t\t*gColorBuffer++ = 1.0f;\n\t\t\t\n\t\t    for (i=0 ; i<3 ; i++)\n\t\t        *gVertexBuffer++ = lightorigin[i] - vpn[i]*radius;\n\t\t\t\n\t\t    for (i=16; i>=0; i--) {\n\t\t\t\t*gColorBuffer++ = 0.0f;\n\t\t\t\t*gColorBuffer++ = 0.0f;\n\t\t\t\t*gColorBuffer++ = 0.0f;\n\t\t\t\t*gColorBuffer++ = 0.0f;\n\t\t        for (j=0; j<3; j++)\n\t\t            *gVertexBuffer++ =  lightorigin[j] + \n\t\t            vright[j]*costablef[i]*radius +\n\t\t            vup[j]*sintablef[i]*radius;\n\t\t    }\n\t\t\t\n\t\t\tvglVertexAttribPointerMapped(0, pPos);\n\t\t\tvglVertexAttribPointerMapped(1, pColor);\n\t\t    GL_DrawPolygon(GL_TRIANGLE_FAN, 18);\n\t\t\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\t\t\tGL_DisableState(GL_COLOR_ARRAY);\n\t\t\t\n\t\t    // Restore previous matrix! KH\n\t\t    glPopMatrix();\n\n\t\t    GL_Color(1,1,1,1);\n\t\t    glDisable (GL_BLEND);\n\t\t    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\t    glDepthMask (1);\n\t\t}\n\t}\n\n\tif (r_shadows.value) {\n\t\t//\n\t\t// Test for models that we don't want to shadow. KH\n\t\t// Not a nice way to do it...\n\t\t//\n\n\t\t// Torches. Early-out to avoid the strcmp's. KH\n\t\tif (torch)\n\t\t    return;\n\t\t// Grenades. KH\n\t\tif (!strcmp (clmodel->name, \"progs/grenade.mdl\"))\n\t\t    return;\n\t\t// Lightning bolts. KH\n\t\tif (!strncmp (clmodel->name, \"progs/bolt\", 10))\n\t\treturn;\n\t\n\t\tglPushMatrix ();\n\t\t\n\t\t// fenix@io.com: model transform interpolation\n\t\tif (r_interpolate_model_transform.value){\n\t\t\tR_BlendedRotateForEntity (e);\n\t\t}else{\n\t\t\tR_RotateForEntity (e);\n\t\t}\n\t\t\t\n\t\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\t\tglEnable (GL_BLEND);\n\t\t\n\t\t// fenix@io.com: model animation interpolation\n\t\tif (r_interpolate_model_animation.value){\n\t\t\tGL_DrawAliasBlendedShadow (paliashdr, lastposenum0, lastposenum, currententity);\n\t\t}else{\n\t\t\tGL_DrawAliasShadow (paliashdr, lastposenum);\n\t\t}\n\t\t\t\n\t\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\t\tglDisable (GL_BLEND);\n\t\tGL_Color(1,1,1,1);\n\t\tglPopMatrix ();\n\t}\n\n}\n\n//==================================================================================\n\n/*\n=============\nR_DrawEntitiesOnList\n=============\n*/\nvoid R_DrawEntitiesOnList (void)\n{\n\tint\t\ti;\n\n\tif (!r_drawentities.value)\n\t\treturn;\n\t\n\t// draw sprites seperately, because of alpha blending\n\tfor (i=0 ; i<cl_numvisedicts ; i++)\n\t{\n\t\tcurrententity = cl_visedicts[i];\n\t\tif (currententity == &cl_entities[cl.viewentity]) currententity->angles[0] *= 0.3;\n\t\tswitch (currententity->model->type)\n\t\t{\n\t\tcase mod_alias:\n\t\t\tR_DrawAliasModel (currententity);\n\t\t\tbreak;\n\t\tcase mod_brush:\n\t\t\tglEnable(GL_POLYGON_OFFSET_FILL);\n\t\t\tR_DrawBrushModel (currententity);\n\t\t\tglDisable(GL_POLYGON_OFFSET_FILL);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\t}\n\t\n\tfor (i=0 ; i<cl_numvisedicts ; i++)\n\t{\n\t\tcurrententity = cl_visedicts[i];\n\n\t\tswitch (currententity->model->type)\n\t\t{\n\t\tcase mod_sprite:\n\t\t\tR_DrawSpriteModel (currententity);\n\t\t\tbreak;\n\t\t}\n\t}\n\n\t//glEnable (GL_DEPTH_TEST);\n\n}\n/*\n=============\nR_DrawViewModel\n=============\n*/\nvoid R_DrawViewModel (void)\n{\n\t// fenix@io.com: model transform interpolation\n\tfloat old_interpolate_model_transform;\n\t\n\tif (!r_drawviewmodel.value)\n\t\treturn;\n\n\tif (chase_active.value)\n\t\treturn;\n\n\tif (envmap)\n\t\treturn;\n\n\tif (!r_drawentities.value)\n\t\treturn;\n\n\tif (cl.items & IT_INVISIBILITY)\n\t\treturn;\n\n\tif (cl.stats[STAT_HEALTH] <= 0)\n\t\treturn;\n\n\tcurrententity = &cl.viewent;\n\tif (!currententity->model)\n\t\treturn;\n\n\t// hack the depth range to prevent view model from poking into walls\n\tglDepthRangef (gldepthmin, gldepthmin + 0.3f*(gldepthmax-gldepthmin));\n\t\n\t// fenix@io.com: model transform interpolation\n\told_interpolate_model_transform = r_interpolate_model_transform.value;\n\tr_interpolate_model_transform.value = false;\n\tR_DrawAliasModel (currententity);\n\tr_interpolate_model_transform.value = old_interpolate_model_transform;\n\t\n\tglDepthRangef (gldepthmin, gldepthmax);\n}\n\n\n/*\n============\nR_PolyBlend\n============\n*/\nvoid R_PolyBlend (void)\n{\n\tif (!gl_polyblend.value)\n\t\treturn;\n\n\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\tGL_DisableState(GL_ALPHA_TEST);\n\tglEnable (GL_BLEND);\n\tglDisable (GL_DEPTH_TEST);\n\tGL_DisableState(GL_TEXTURE_COORD_ARRAY);\n\n    glLoadIdentity ();\n\n    glRotatef (-90,  1, 0, 0);\t    // put Z going up\n    glRotatef (90,  0, 0, 1);\t    // put Z going up\n\n\tGL_Color(v_blend[0],v_blend[1],v_blend[2],v_blend[3]);\n\t\n\tif (v_blend[3]) {\n\t\n\t\tif (gamma_vertices == NULL) {\n\t\t\tgamma_vertices = malloc(3 * 4 * sizeof(float));\n\t\t\tgamma_vertices[0] = gamma_vertices[3] = gamma_vertices[6] = gamma_vertices[9] = 10;\n\t\t\tgamma_vertices[1] = gamma_vertices[2] = gamma_vertices[5] = gamma_vertices[10] = 100;\n\t\t\tgamma_vertices[4] = gamma_vertices[7] = gamma_vertices[8] = gamma_vertices[11] = -100;\n\t\t}\n\n\t\tvglVertexAttribPointerMapped(0, gamma_vertices);\n\t\tglUniform4fv(monocolor, 1, v_blend);\n\t\tGL_DrawPolygon(GL_TRIANGLE_FAN, 4);\n\t\t\n\t}\n\t\n\t//gamma trick based on LordHavoc - muff\n\tif (v_gamma.value != 1)\n\t\tDoGamma();\n\t\n\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\tglDisable (GL_BLEND);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\tGL_EnableState(GL_ALPHA_TEST);\n}\n\n\nint SignbitsForPlane (mplane_t *out)\n{\n\tint\tbits, j;\n\n\t// for fast box on planeside test\n\n\tbits = 0;\n\tfor (j=0 ; j<3 ; j++)\n\t{\n\t\tif (out->normal[j] < 0)\n\t\t\tbits |= 1<<j;\n\t}\n\treturn bits;\n}\n\n\nvoid R_SetFrustum (void)\n{\n\tint\t\ti;\n\n\tif (r_refdef.fov_x == 90) \n\t{\n\t\t// front side is visible\n\n\t\tVectorAdd (vpn, vright, frustum[0].normal);\n\t\tVectorSubtract (vpn, vright, frustum[1].normal);\n\n\t\tVectorAdd (vpn, vup, frustum[2].normal);\n\t\tVectorSubtract (vpn, vup, frustum[3].normal);\n\t}\n\telse\n\t{\n\t\t// rotate VPN right by FOV_X/2 degrees\n\t\tRotatePointAroundVector( frustum[0].normal, vup, vpn, -(90-r_refdef.fov_x / 2 ) );\n\t\t// rotate VPN left by FOV_X/2 degrees\n\t\tRotatePointAroundVector( frustum[1].normal, vup, vpn, 90-r_refdef.fov_x / 2 );\n\t\t// rotate VPN up by FOV_X/2 degrees\n\t\tRotatePointAroundVector( frustum[2].normal, vright, vpn, 90-r_refdef.fov_y / 2 );\n\t\t// rotate VPN down by FOV_X/2 degrees\n\t\tRotatePointAroundVector( frustum[3].normal, vright, vpn, -( 90 - r_refdef.fov_y / 2 ) );\n\t}\n\n\tfor (i=0 ; i<4 ; i++)\n\t{\n\t\tfrustum[i].type = PLANE_ANYZ;\n\t\tfrustum[i].dist = DotProduct (r_origin, frustum[i].normal);\n\t\tfrustum[i].signbits = SignbitsForPlane (&frustum[i]);\n\t}\n}\n\n\n\n/*\n===============\nR_SetupFrame\n===============\n*/\nvoid R_SetupFrame (void)\n{\n\tint\t\t\t\tedgecount;\n\tvrect_t\t\t\tvrect;\n\tfloat\t\t\tw, h;\n\n// don't allow cheats in multiplayer\n\tif (cl.maxclients > 1)\n\t\tCvar_Set (\"r_fullbright\", \"0\");\n\n\tR_AnimateLight ();\n\n\tr_framecount++;\n\n// build the transformation matrix for the given view angles\n\tVectorCopy (r_refdef.vieworg, r_origin);\n\n\tAngleVectors (r_refdef.viewangles, vpn, vright, vup);\n\n// current viewleaf\n\tr_oldviewleaf = r_viewleaf;\n\tr_viewleaf = Mod_PointInLeaf (r_origin, cl.worldmodel);\n\n\tV_SetContentsColor (r_viewleaf->contents);\n\tV_CalcBlend ();\n\n\tr_cache_thrash = false;\n\n\tc_brush_polys = 0;\n\tc_alias_polys = 0;\n\n}\n\n#define NEARCLIP 4\n#define FARCLIP  4096\nvoid GL_SetFrustum(float fovx, float fovy)\n{\n\tfloat xmax, ymax;\n\txmax = NEARCLIP * tan( fovx * M_PI / 360.0 );\n\tymax = NEARCLIP * tan( fovy * M_PI / 360.0 );\n\t\n\tif (st_separation.value != 0) {\n\t\tfloat stereo_add = (st_separation.value * st_fustbal.value * (4.0f / (4 + st_zeropdist.value))) * stereoCameraSelect;\n\t\tglFrustum(-xmax + stereo_add, xmax + stereo_add, -ymax, ymax, NEARCLIP, FARCLIP);\n\t\tglTranslatef(st_separation.value * stereoCameraSelect, 0, 0);\n\t} else glFrustum(-xmax, xmax, -ymax, ymax, NEARCLIP, FARCLIP);\n}\n\n/*\n=============\nR_SetupGL\n=============\n*/\nvoid R_SetupGL (void)\n{\n\tint\t\ti;\n\textern\tint glwidth, glheight;\n\n\t//\n\t// set up viewpoint\n\t//\n\tglMatrixMode(GL_PROJECTION);\n\tglLoadIdentity ();\n\tglViewport (glx + r_refdef.vrect.x,\n\t\tgly + glheight - r_refdef.vrect.y - r_refdef.vrect.height,\n\t\tr_refdef.vrect.width,\n\t\tr_refdef.vrect.height);\n\t\t\t\t\n    GL_SetFrustum (r_refdef.fov_x, r_refdef.fov_y);\n\n\tif (mirror)\n\t{\n\t\tif (mirror_plane->normal[2])\n\t\t\tglScalef (1, -1, 1);\n\t\telse\n\t\t\tglScalef (-1, 1, 1);\n\t\tglCullFace(GL_BACK);\n\t}\n\telse\n\t\tglCullFace(GL_FRONT);\n\n\tglMatrixMode(GL_MODELVIEW);\n    glLoadIdentity ();\n\n    glRotatef (-90,  1, 0, 0);\t    // put Z going up\n    glRotatef (90,  0, 0, 1);\t    // put Z going up\n\tif (gl_xflip.value){\n\t\tglScalef (1, -1, 1);\n\t\tglCullFace(GL_BACK);\n\t}\n    glRotatef (-r_refdef.viewangles[2],  1, 0, 0);\n    glRotatef (-r_refdef.viewangles[0],  0, 1, 0);\n    glRotatef (-r_refdef.viewangles[1],  0, 0, 1);\n    glTranslatef (-r_refdef.vieworg[0],  -r_refdef.vieworg[1],  -r_refdef.vieworg[2]);\n\n\tglGetFloatv (GL_MODELVIEW_MATRIX, r_world_matrix);\n\n\t//\n\t// set drawing parms\n\t//\n\tif (gl_cull.value)\n\t\tglEnable(GL_CULL_FACE);\n\telse\n\t\tglDisable(GL_CULL_FACE);\n\n\tglDisable(GL_BLEND);\n\tGL_DisableState(GL_ALPHA_TEST);\n\tglEnable(GL_DEPTH_TEST);\n}\n\n/*\n================\nR_RenderScene\n\nr_refdef must be set before the first call\n================\n*/\nvoid R_RenderScene (void)\n{\n\tR_SetupFrame ();\n\n\tR_SetFrustum ();\n\n\tR_SetupGL ();\n\n\tR_MarkLeaves ();\t// done here so we know if we're in water\n\n\tR_DrawWorld ();\t\t// adds static entities to the list\n\n\tS_ExtraUpdate ();\t// don't let sound get messed up if going slow\n\t\t\n\tR_DrawEntitiesOnList ();\n\n\tR_RenderDlights ();\n\t\n\tR_DrawParticles ();\n\n}\n\n\n/*\n=============\nR_Clear\n=============\n*/\nvoid R_Clear (void)\n{\n\tif (gl_clear.value){\n\t\tglClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\n\t}else{\n\t\tglClear (GL_DEPTH_BUFFER_BIT);\n\t}\n\t\n\tif (r_mirroralpha.value != 1.0 && st_separation.value == 0)\n\t\tgldepthmax = 0.5;\n\telse\n\t\tgldepthmax = 1;\n\t\t\n\tgldepthmin = 0;\n\tglDepthFunc (GL_LEQUAL);\n\tglDepthRangef (gldepthmin, gldepthmax);\n}\n\n/*\n=============\nR_Mirror\n=============\n*/\nvoid R_Mirror (void)\n{\n\tfloat\t\td;\n\tmsurface_t\t*s;\n\tentity_t\t*ent;\n\n\tif (!mirror)\n\t\treturn;\n\n\tmemcpy (r_base_world_matrix, r_world_matrix, sizeof(r_base_world_matrix));\n\n\td = DotProduct (r_refdef.vieworg, mirror_plane->normal) - mirror_plane->dist;\n\tVectorMA (r_refdef.vieworg, -2*d, mirror_plane->normal, r_refdef.vieworg);\n\n\td = DotProduct (vpn, mirror_plane->normal);\n\tVectorMA (vpn, -2*d, mirror_plane->normal, vpn);\n\n\tr_refdef.viewangles[0] = -asin (vpn[2])/M_PI*180;\n\tr_refdef.viewangles[1] = atan2 (vpn[1], vpn[0])/M_PI*180;\n\tr_refdef.viewangles[2] = -r_refdef.viewangles[2];\n\n\tent = &cl_entities[cl.viewentity];\n\tif (cl_numvisedicts < MAX_VISEDICTS)\n\t{\n\t\tcl_visedicts[cl_numvisedicts] = ent;\n\t\tcl_numvisedicts++;\n\t}\n\n\tgldepthmin = 0.5f;\n\tgldepthmax = 1.0f;\n\tglDepthRangef (gldepthmin, gldepthmax);\n\tglDepthFunc (GL_LEQUAL);\n\n\tR_RenderScene ();\n\tR_DrawWaterSurfaces ();\n\n\tgldepthmin = 0.0f;\n\tgldepthmax = 0.5f;\n\tglDepthRangef (gldepthmin, gldepthmax);\n\tglDepthFunc (GL_LEQUAL);\n\n\t// blend on top\n\tglEnable (GL_BLEND);\n\t\n\t//mirror fix - from QER\n\tGL_EnableState(GL_MODULATE);\n\t//mirror fix\n\t\n\tglMatrixMode(GL_PROJECTION);\n\tif (mirror_plane->normal[2])\n\t\tglScalef (1,-1,1);\n\telse\n\t\tglScalef (-1,1,1);\n\tglCullFace(GL_FRONT);\n\tglMatrixMode(GL_MODELVIEW);\n\n\tglLoadMatrixf (r_base_world_matrix);\n\n\tGL_Color(1,1,1,st_separation.value != 0 ? 1 : r_mirroralpha.value);\n\ts = cl.worldmodel->textures[mirrortexturenum]->texturechain;\n\tfor ( ; s ; s=s->texturechain)\n\t\tR_RenderBrushPoly (s);\n\tcl.worldmodel->textures[mirrortexturenum]->texturechain = NULL;\n\tglDisable (GL_BLEND);\n\tGL_Color(1,1,1,1);\n\t\n\t//mirror fix - from QER\n\tGL_EnableState(GL_REPLACE);\n\t//mirror fix\n\t\n}\n\n/*\n================\nR_RenderView\n\nr_refdef must be set before the first call\n================\n*/\nvoid R_RenderView (void)\n{\n\tdouble\ttime1, time2;\n\n\tif (r_norefresh.value)\n\t\treturn;\n\n\tif (!r_worldentity.model || !cl.worldmodel)\n\t\tSys_Error (\"R_RenderView: NULL worldmodel\");\n\n\tif (r_speeds.value)\n\t{\n\t\ttime1 = Sys_FloatTime ();\n\t\tc_brush_polys = 0;\n\t\tc_alias_polys = 0;\n\t}\n\n\tmirror = false;\n\t\n\tif (st_separation.value != 0) {\n\t\tstereoCameraSelect = 1;\n\t\tglColorMask( GL_TRUE, GL_FALSE, GL_FALSE ,GL_TRUE );\n\t\tR_Clear ();\t\t\t\n\t\tR_RenderScene ();\n\t\tR_DrawViewModel ();\n\t\tR_DrawWaterSurfaces ();\n\t\tR_Mirror ();\n\t\t\n\t\tstereoCameraSelect = -1;\n\t\tglColorMask( GL_FALSE, GL_TRUE, GL_TRUE ,GL_TRUE );\n\t\tR_Clear ();\n\t\tR_RenderScene ();\t\t\n\t\tR_DrawViewModel ();\n\t\tR_DrawWaterSurfaces ();\n\t\tR_Mirror ();\n\t\tglColorMask( GL_TRUE, GL_TRUE, GL_TRUE ,GL_TRUE );\n\t} else {\n\t\tR_Clear ();\n\t\tR_RenderScene ();\n\t\tR_DrawViewModel ();\n\t\tR_DrawWaterSurfaces ();\n\t\tR_Mirror ();\n\t}\n\t\n\tR_PolyBlend ();\n\n\tif (r_speeds.value)\n\t{\n\t\ttime2 = Sys_FloatTime ();\n\t\tCon_Printf (\"%3i ms  %4i wpoly %4i epoly\\n\", (int)((time2-time1)*1000), c_brush_polys, c_alias_polys); \n\t}\n}\n"
  },
  {
    "path": "source/gl_rmisc.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_misc.c\n\n#include \"quakedef.h\"\n\nextern cvar_t gl_torchflares;\nextern cvar_t gl_compress;\n\n/*\n==================\nR_InitTextures\n==================\n*/\nvoid\tR_InitTextures (void)\n{\n\tint\t\tx,y, m;\n\tbyte\t*dest;\n\n// create a simple checkerboard texture for the default\n\tr_notexture_mip = Hunk_AllocName (sizeof(texture_t) + 16*16+8*8+4*4+2*2, \"notexture\");\n\t\n\tr_notexture_mip->width = r_notexture_mip->height = 16;\n\tr_notexture_mip->offsets[0] = sizeof(texture_t);\n\tr_notexture_mip->offsets[1] = r_notexture_mip->offsets[0] + 16*16;\n\tr_notexture_mip->offsets[2] = r_notexture_mip->offsets[1] + 8*8;\n\tr_notexture_mip->offsets[3] = r_notexture_mip->offsets[2] + 4*4;\n\t\n\tfor (m=0 ; m<4 ; m++)\n\t{\n\t\tdest = (byte *)r_notexture_mip + r_notexture_mip->offsets[m];\n\t\tfor (y=0 ; y< (16>>m) ; y++)\n\t\t\tfor (x=0 ; x< (16>>m) ; x++)\n\t\t\t{\n\t\t\t\tif (  (y< (8>>m) ) ^ (x< (8>>m) ) )\n\t\t\t\t\t*dest++ = 0;\n\t\t\t\telse\n\t\t\t\t\t*dest++ = 0xff;\n\t\t\t}\n\t}\t\n}\n\nbyte\tdottexture[8][8] =\n{\n\t{0,1,1,0,0,0,0,0},\n\t{1,1,1,1,0,0,0,0},\n\t{1,1,1,1,0,0,0,0},\n\t{0,1,1,0,0,0,0,0},\n\t{0,0,0,0,0,0,0,0},\n\t{0,0,0,0,0,0,0,0},\n\t{0,0,0,0,0,0,0,0},\n\t{0,0,0,0,0,0,0,0},\n};\nvoid R_InitParticleTexture (void)\n{\n\tint\t\tx,y;\n\tbyte\tdata[8][8][4];\n\n\t//\n\t// particle texture\n\t//\n\tparticletexture = texture_extension_number++;\n    GL_Bind(particletexture);\n\n\tfor (x=0 ; x<8 ; x++)\n\t{\n\t\tfor (y=0 ; y<8 ; y++)\n\t\t{\n\t\t\tdata[y][x][0] = 255;\n\t\t\tdata[y][x][1] = 255;\n\t\t\tdata[y][x][2] = 255;\n\t\t\tdata[y][x][3] = dottexture[x][y]*255;\n\t\t}\n\t}\n\tglTexImage2D (GL_TEXTURE_2D, 0, gl_alpha_format, 8, 8, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);\n\n\tGL_EnableState(GL_MODULATE);\n\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n}\n\n/*\n===============\nR_Envmap_f\n\nGrab six views for environment mapping tests\n===============\n*/\nvoid R_Envmap_f (void)\n{\n}\n\n/*\n===============\nR_Init\n===============\n*/\nvoid R_Init (void)\n{\t\n\textern byte *hunk_base;\n\textern cvar_t gl_finish;\n\n\tCmd_AddCommand (\"timerefresh\", R_TimeRefresh_f);\t\n\tCmd_AddCommand (\"envmap\", R_Envmap_f);\t\n\tCmd_AddCommand (\"pointfile\", R_ReadPointFile_f);\t\n\n\tCvar_RegisterVariable (&r_norefresh);\n\tCvar_RegisterVariable (&r_lightmap);\n\tCvar_RegisterVariable (&r_fullbright);\n\tCvar_RegisterVariable (&r_drawentities);\n\tCvar_RegisterVariable (&r_drawviewmodel);\n\tCvar_RegisterVariable (&r_shadows);\n\tCvar_RegisterVariable (&r_mirroralpha);\n\tCvar_RegisterVariable (&r_wateralpha);\n\tCvar_RegisterVariable (&r_dynamic);\n\tCvar_RegisterVariable (&r_novis);\n\tCvar_RegisterVariable (&r_speeds);\n\t\n\t// fenix@io.com: register new cvars for model interpolation\n    Cvar_RegisterVariable (&r_interpolate_model_animation);\n    Cvar_RegisterVariable (&r_interpolate_model_transform);\n\t\n\tCvar_RegisterVariable (&gl_finish);\n\tCvar_RegisterVariable (&gl_clear);\n\tCvar_RegisterVariable (&gl_texsort);\n\t\n\tCvar_RegisterVariable (&gl_compress);\n\n\tCvar_RegisterVariable (&gl_cull);\n\tCvar_RegisterVariable (&gl_smoothmodels);\n\tCvar_RegisterVariable (&gl_affinemodels);\n\tCvar_RegisterVariable (&gl_polyblend);\n\tCvar_RegisterVariable (&gl_flashblend);\n\tCvar_RegisterVariable (&gl_playermip);\n\tCvar_RegisterVariable (&gl_nocolors);\n\n\tCvar_RegisterVariable (&gl_keeptjunctions);\n\tCvar_RegisterVariable (&gl_reporttjunctions);\n\n\tCvar_RegisterVariable (&gl_doubleeyes);\n\t\n\tCvar_RegisterVariable (&gl_torchflares); // Torch flares. KH\n\tCvar_RegisterVariable (&gl_xflip);\n\tCvar_RegisterVariable (&gl_overbright);\n\n\tR_InitParticles ();\n\tR_InitParticleTexture ();\n\n\tplayertextures = texture_extension_number;\n\ttexture_extension_number += 16;\n}\n\n/*\n===============\nR_TranslatePlayerSkin\n\nTranslates a skin texture by the per-player color lookup\n===============\n*/\nvoid R_TranslatePlayerSkin (int playernum)\n{\n\tint\t\ttop, bottom;\n\tbyte\t*translate = malloc(256*sizeof(byte));\n\tunsigned\t*translate32 = malloc(256*sizeof(unsigned));\n\tint\t\ti, j, s;\n\tmodel_t\t*model;\n\taliashdr_t *paliashdr;\n\tbyte\t*original;\n\tunsigned *pixels, *out;\n\tunsigned\tscaled_width, scaled_height;\n\tint\t\t\tinwidth, inheight;\n\tbyte\t\t*inrow;\n\tunsigned\tfrac, fracstep;\n\textern\tbyte\t\t**player_8bit_texels_tbl;\n\n\ttop = cl.scores[playernum].colors & 0xf0;\n\tbottom = (cl.scores[playernum].colors &15)<<4;\n\n\tfor (i=0 ; i<256 ; i++)\n\t\ttranslate[i] = i;\n\n\tfor (i=0 ; i<16 ; i++)\n\t{\n\t\tif (top < 128)\t// the artists made some backwards ranges.  sigh.\n\t\t\ttranslate[TOP_RANGE+i] = top+i;\n\t\telse\n\t\t\ttranslate[TOP_RANGE+i] = top+15-i;\n\t\t\t\t\n\t\tif (bottom < 128)\n\t\t\ttranslate[BOTTOM_RANGE+i] = bottom+i;\n\t\telse\n\t\t\ttranslate[BOTTOM_RANGE+i] = bottom+15-i;\n\t}\n\n\t//\n\t// locate the original skin pixels\n\t//\n\tcurrententity = &cl_entities[1+playernum];\n\tmodel = currententity->model;\n\tif (!model){\n\t\tfree(translate);\n\t\tfree(translate32);\n\t\treturn;\t\t// player doesn't have a model yet\n\t}\n\tif (model->type != mod_alias){\n\t\tfree(translate);\n\t\tfree(translate32);\n\t\treturn; // only translate skins on alias models\n\t}\n\tpaliashdr = (aliashdr_t *)Mod_Extradata (model);\n\ts = paliashdr->skinwidth * paliashdr->skinheight;\n\tif (currententity->skinnum < 0 || currententity->skinnum >= paliashdr->numskins) {\n\t\tCon_Printf(\"(%d): Invalid player skin #%d\\n\", playernum, currententity->skinnum);\n\t\toriginal = (byte *)paliashdr + paliashdr->texels[0];\n\t} else\n\t\toriginal = (byte *)paliashdr + paliashdr->texels[currententity->skinnum];\n\tif (s & 3)\n\t\tSys_Error (\"R_TranslateSkin: s&3\");\n\n\tinwidth = paliashdr->skinwidth;\n\tinheight = paliashdr->skinheight;\n\n\t// because this happens during gameplay, do it fast\n\t// instead of sending it through gl_upload 8\n    GL_Bind(playertextures + playernum);\n\n\tscaled_width = gl_max_size.value < 512 ? gl_max_size.value : 512;\n\tscaled_height = gl_max_size.value < 256 ? gl_max_size.value : 256;\n\n\t// allow users to crunch sizes down even more if they want\n\tscaled_width >>= (int)gl_playermip.value;\n\tscaled_height >>= (int)gl_playermip.value;\n\n\t#define PIXEL_COUNT (512*256)\n\t#define PIXELS_SIZE (PIXEL_COUNT * sizeof(unsigned))\n\tpixels = (unsigned*) malloc(PIXELS_SIZE);\n\tif(!pixels)\n\t{\n\t\tfree(translate);\n\t\tfree(translate32);\n\t\tSys_Error(\"Out of memory.\");\n\t}\n\n\tfor (i=0 ; i<256 ; i++)\n\t\ttranslate32[i] = d_8to24table[translate[i]];\n\n\tout = pixels;\n\tfracstep = inwidth*0x10000/scaled_width;\n\tfor (i=0 ; i<scaled_height ; i++, out += scaled_width)\n\t{\n\t\tinrow = original + inwidth*(i*inheight/scaled_height);\n\t\tfrac = fracstep >> 1;\n\t\tfor (j=0 ; j<scaled_width ; j+=4)\n\t\t{\n\t\t\tout[j] = translate32[inrow[frac>>16]];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+1] = translate32[inrow[frac>>16]];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+2] = translate32[inrow[frac>>16]];\n\t\t\tfrac += fracstep;\n\t\t\tout[j+3] = translate32[inrow[frac>>16]];\n\t\t\tfrac += fracstep;\n\t\t}\n\t}\n\tglTexImage2D (GL_TEXTURE_2D, 0, gl_compress.value ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : gl_solid_format, scaled_width, scaled_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);\n\n\tGL_EnableState(GL_MODULATE);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\tfree(pixels);\n\tfree(translate);\n\tfree(translate32);\n}\n\n\n/*\n===============\nR_NewMap\n===============\n*/\nvoid R_NewMap (void)\n{\n\tint\t\ti;\n\t\n\tfor (i=0 ; i<256 ; i++)\n\t\td_lightstylevalue[i] = 264;\t\t// normal light value\n\n\tmemset (&r_worldentity, 0, sizeof(r_worldentity));\n\tr_worldentity.model = cl.worldmodel;\n\n// clear out efrags in case the level hasn't been reloaded\n// FIXME: is this one short?\n\tfor (i=0 ; i<cl.worldmodel->numleafs ; i++)\n\t\tcl.worldmodel->leafs[i].efrags = NULL;\n\t\t \t\n\tr_viewleaf = NULL;\n\tR_ClearParticles ();\n\n\tGL_BuildLightmaps ();\n\n\t// identify sky texture\n\tskytexturenum = -1;\n\tmirrortexturenum = -1;\n\tfor (i=0 ; i<cl.worldmodel->numtextures ; i++)\n\t{\n\t\tif (!cl.worldmodel->textures[i])\n\t\t\tcontinue;\n\t\tif (!strncmp(cl.worldmodel->textures[i]->name,\"sky\",3) )\n\t\t\tskytexturenum = i;\n\t\tif (!strncmp(cl.worldmodel->textures[i]->name,\"window02_1\",10) )\n\t\t\tmirrortexturenum = i;\n \t\tcl.worldmodel->textures[i]->texturechain = NULL;\n\t}\n}\n\n\n/*\n====================\nR_TimeRefresh_f\n\nFor program optimization\n====================\n*/\nvoid R_TimeRefresh_f (void)\n{\n}\n\nvoid D_FlushCaches (void)\n{\n}\n\n\n"
  },
  {
    "path": "source/gl_rsurf.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_surf.c: surface-related refresh code\n\n#include \"quakedef.h\"\n#include \"gl_fullbright.h\"\n#include <math_neon.h>\n\nint\t\t\tskytexturenum;\n\n#ifndef GL_RGBA4\n#define\tGL_RGBA4\t0\n#endif\n\n\nint\t\tlightmap_bytes;\t\t// 1, 2, or 4\n\nint\t\tlightmap_textures;\n\nextern int   gl_filter_min;\nextern int   gl_filter_max;\n\nunsigned\t\tblocklights[3*18*18]; // LordHavoc: .lit support (*3 for RGB) to the definitions at the top\n\n#define\tBLOCK_WIDTH\t\t128\n#define\tBLOCK_HEIGHT\t128\n\n#define\tMAX_LIGHTMAPS\t64\nint\t\t\tactive_lightmaps;\n\ntypedef struct glRect_s {\n\tunsigned char l,t,w,h;\n} glRect_t;\n\nglpoly_t\t*lightmap_polys[MAX_LIGHTMAPS];\nbool\tlightmap_modified[MAX_LIGHTMAPS];\nglRect_t\tlightmap_rectchange[MAX_LIGHTMAPS];\n\nint\t\t\tallocated[MAX_LIGHTMAPS][BLOCK_WIDTH];\n\n// the lightmap texture data needs to be kept in\n// main memory so texsubimage can update properly\nbyte\t\tlightmaps[4*MAX_LIGHTMAPS*BLOCK_WIDTH*BLOCK_HEIGHT];\n\n// For gl_texsort 0\nmsurface_t  *skychain = NULL;\nmsurface_t  *waterchain = NULL;\n\n/*\n===============\nR_AddDynamicLights\n===============\n*/\nvoid R_AddDynamicLights (msurface_t *surf)\n{\n\t// LordHavoc: .lit support begin\n\tfloat\t\tcred, cgreen, cblue, brightness;\n\tunsigned\t*bl;\n\t// LordHavoc: .lit support end\n\tint\t\t\tlnum;\n\tint\t\t\tsd, td;\n\tfloat\t\tdist, rad, minlight;\n\tvec3_t\t\timpact, local;\n\tint\t\t\ts, t;\n\tint\t\t\ti;\n\tint\t\t\tsmax, tmax;\n\tmtexinfo_t\t*tex;\n\n\tsmax = (surf->extents[0]>>4)+1;\n\ttmax = (surf->extents[1]>>4)+1;\n\ttex = surf->texinfo;\n\n\tfor (lnum=0 ; lnum<MAX_DLIGHTS ; lnum++)\n\t{\n\t\tif ( !(surf->dlightbits & (1<<lnum) ) )\n\t\t\tcontinue;\t\t// not lit by this light\n\n\t\trad = cl_dlights[lnum].radius;\n\t\tdist = DotProduct (cl_dlights[lnum].origin, surf->plane->normal) -\n\t\t\t\tsurf->plane->dist;\n\t\trad -= fabs(dist);\n\t\tminlight = cl_dlights[lnum].minlight;\n\t\tif (rad < minlight)\n\t\t\tcontinue;\n\t\tminlight = rad - minlight;\n\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\timpact[i] = cl_dlights[lnum].origin[i] -\n\t\t\t\t\tsurf->plane->normal[i]*dist;\n\t\t}\n\n\t\tlocal[0] = DotProduct (impact, tex->vecs[0]) + tex->vecs[0][3];\n\t\tlocal[1] = DotProduct (impact, tex->vecs[1]) + tex->vecs[1][3];\n\n\t\tlocal[0] -= surf->texturemins[0];\n\t\tlocal[1] -= surf->texturemins[1];\n\t\t\n\t\t// LordHavoc: .lit support begin\n\t\tbl = blocklights;\n\t\tcred = cl_dlights[lnum].color[0] * 256.0f;\n\t\tcgreen = cl_dlights[lnum].color[1] * 256.0f;\n\t\tcblue = cl_dlights[lnum].color[2] * 256.0f;\n\t\t// LordHavoc: .lit support end\n\t\t\n\t\tfor (t = 0 ; t<tmax ; t++)\n\t\t{\n\t\t\ttd = local[1] - t*16;\n\t\t\tif (td < 0)\n\t\t\t\ttd = -td;\n\t\t\tfor (s=0 ; s<smax ; s++)\n\t\t\t{\n\t\t\t\tsd = local[0] - s*16;\n\t\t\t\tif (sd < 0)\n\t\t\t\t\tsd = -sd;\n\t\t\t\tif (sd > td)\n\t\t\t\t\tdist = sd + (td>>1);\n\t\t\t\telse\n\t\t\t\t\tdist = td + (sd>>1);\n\t\t\t\tif (dist < minlight){\n\t\t\t\t\t// LordHavoc: .lit support begin\n\t\t\t\t\tbrightness = rad - dist;\n\t\t\t\t\tbl[0] += (int) (brightness * cred);\n\t\t\t\t\tbl[1] += (int) (brightness * cgreen);\n\t\t\t\t\tbl[2] += (int) (brightness * cblue);\n\t\t\t\t\t// LordHavoc: .lit support end\n\t\t\t\t}\n\t\t\t\tbl += 3;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n===============\nR_BuildLightMap\n\nCombine and scale multiple lightmaps into the 8.8 format in blocklights\n===============\n*/\nvoid R_BuildLightMap (msurface_t *surf, byte *dest, int stride)\n{\n\tint\t\t\tblocksize, smax, tmax;\n\tint\t\t\tt;\n\tint\t\t\ti, j, size;\n\tbyte\t\t*lightmap;\n\tunsigned\tscale;\n\tint\t\t\tmaps;\n\tint\t\t\tlightadj[4];\n\tunsigned\t*bl;\n\n\tsurf->cached_dlight = (surf->dlightframe == r_framecount);\n\n\tsmax = (surf->extents[0]>>4)+1;\n\ttmax = (surf->extents[1]>>4)+1;\n\tsize = smax*tmax;\n\tlightmap = surf->samples;\n\n// set to full bright if no light data\n\tif (r_fullbright.value || !cl.worldmodel->lightdata)\n\t{\n\t\t// LordHavoc: .lit support begin\n\t\tbl = blocklights;\n\t\tfor (i=0 ; i<size ; i++)\n\t\t{\n\t\t\t*bl++ = 255*256;\n\t\t\t*bl++ = 255*256;\n\t\t\t*bl++ = 255*256;\n\t\t}\n\t\t// LordHavoc: .lit support end\n\t\tgoto store;\n\t}\n\n// clear to no light\n\t// LordHavoc: .lit support begin\n\tbl = blocklights;\n\tfor (i=0 ; i<size ; i++)\n\t{\n\t\t*bl++ = 0;\n\t\t*bl++ = 0;\n\t\t*bl++ = 0;\n\t}\n\t// LordHavoc: .lit support end\t\n\t\n// add all the lightmaps\n\tif (lightmap){\n\t\tfor (maps = 0; maps < MAXLIGHTMAPS && surf->styles[maps] != 255; maps++)\n\t\t{\n\t\t\tscale = (float)d_lightstylevalue[surf->styles[maps]];\n\t\t\tsurf->cached_light[maps] = scale;\t// 8.8 fraction\n\t\t\t// LordHavoc: .lit support begin\n\t\t\tbl = blocklights;\n\t\t\tfor (i=0 ; i<size ; i++)\n\t\t\t{\n\t\t\t\t*bl++ += *lightmap++ * scale;\n\t\t\t\t*bl++ += *lightmap++ * scale;\n\t\t\t\t*bl++ += *lightmap++ * scale;\n\t\t\t}\n\t\t\t// LordHavoc: .lit support end\n\t\t}\n\t}\n\t\n// add all the dynamic lights\n\tif (surf->dlightframe == r_framecount)\n\t\tR_AddDynamicLights (surf);\n\n// bound, invert, and shift\nstore:\n\tstride -= (smax<<2);\n\tbl = blocklights;\n\tfor (i=0 ; i<tmax ; i++, dest += stride)\n\t{\n\t\tif (gl_overbright.value >= 2) {\n\t\t\tfor (j=0 ; j<smax ; j++)\n\t\t\t{\n\t\t\t\t// LordHavoc: .lit support begin\n\t\t\t\t// LordHavoc: positive lighting (would be 255-t if it were inverse like glquake was)\n\t\t\t\tt = bl[0] >> 7;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[1] >> 7;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[2] >> 7;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tbl += 3;\n\t\t\t\t*dest++ = 255;\n\t\t\t\t// LordHavoc: .lit support end\n\t\t\t}\n\t\t} else if (gl_overbright.value) {\n\t\t\tfor (j=0 ; j<smax ; j++)\n\t\t\t{\n\t\t\t\t// LordHavoc: .lit support begin\n\t\t\t\t// LordHavoc: positive lighting (would be 255-t if it were inverse like glquake was)\n\t\t\t\tt = bl[0]; t = (t >> 8) + (t >> 9);if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[1]; t = (t >> 8) + (t >> 9);if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[2]; t = (t >> 8) + (t >> 9);if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tbl += 3;\n\t\t\t\t*dest++ = 255;\n\t\t\t\t// LordHavoc: .lit support end\n\t\t\t}\n\t\t} else {\n\t\t\tfor (j=0 ; j<smax ; j++)\n\t\t\t{\n\t\t\t\t// LordHavoc: .lit support begin\n\t\t\t\t// LordHavoc: positive lighting (would be 255-t if it were inverse like glquake was)\n\t\t\t\tt = bl[0] >> 8;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[1] >> 8;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tt = bl[2] >> 8;if (t > 255) t = 255;*dest++ = t;\n\t\t\t\tbl += 3;\n\t\t\t\t*dest++ = 255;\n\t\t\t\t// LordHavoc: .lit support end\n\t\t\t}\n\t\t}\n\t}\n\t\n}\n\n\n/*\n===============\nR_TextureAnimation\n\nReturns the proper texture for a given time and base texture\n===============\n*/\ntexture_t *R_TextureAnimation (texture_t *base)\n{\n\tint\t\treletive;\n\tint\t\tcount;\n\n\tif (currententity->frame)\n\t{\n\t\tif (base->alternate_anims)\n\t\t\tbase = base->alternate_anims;\n\t}\n\t\n\tif (!base->anim_total)\n\t\treturn base;\n\n\treletive = (int)(cl.time*10) % base->anim_total;\n\n\tcount = 0;\t\n\twhile (base->anim_min > reletive || base->anim_max <= reletive)\n\t{\n\t\tbase = base->anim_next;\n\t\tif (!base)\n\t\t\tSys_Error (\"R_TextureAnimation: broken cycle\");\n\t\tif (++count > 100)\n\t\t\tSys_Error (\"R_TextureAnimation: infinite cycle\");\n\t}\n\n\treturn base;\n}\n\n\n/*\n=============================================================\n\n\tBRUSH MODELS\n\n=============================================================\n*/\n\n\nextern\tint\t\tsolidskytexture;\nextern\tint\t\talphaskytexture;\nextern\tfloat\tspeedscale;\t\t// for top sky and bottom sky\n\nvoid DrawGLWaterPoly (glpoly_t *p);\nvoid DrawGLWaterPolyLightmap (glpoly_t *p);\n\n/*\n================\nDrawGLWaterPoly\n\nWarp the vertex coordinates\n================\n*/\nvoid DrawGLWaterPoly (glpoly_t *p)\n{\n\tint\t\ti;\n\tfloat\t*v;\n\tfloat\ts, t, os, ot;\n\tvec3_t\tnv;\n\n\tv = p->verts[0];\n\n\tfloat* pnv = gVertexBuffer;\n\tfloat* pnt = gTexCoordBuffer;\n\tfor (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)\n\t{\n\t\tfloat sinv2 = sinf_neon(v[2]*0.05f+realtime);\n\t\tgVertexBuffer[0] = v[0] + 8*sinf_neon(v[1]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[1] = v[1] + 8*sinf_neon(v[0]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[2] = v[2];\n\t\tgTexCoordBuffer[0] = v[3];\n\t\tgTexCoordBuffer[1] = v[4];\n\t\tgVertexBuffer +=3;\n\t\tgTexCoordBuffer +=2;\n\t}\n\t\n\tvglVertexAttribPointerMapped(0, pnv);\n\tvglVertexAttribPointerMapped(1, pnt);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n}\n\nvoid DrawGLWaterPolyLightmap (glpoly_t *p)\n{\n\tint\t\ti;\n\tfloat\t*v;\n\tfloat\ts, t, os, ot;\n\tvec3_t\tnv;\n\n\tv = p->verts[0];\n\n\tfloat* pnv = gVertexBuffer;\n\tfloat* pnt = gTexCoordBuffer;\n\tfor (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)\n\t{\n\t\tfloat sinv2 = sinf_neon(v[2]*0.05f+realtime);\n\t\tgVertexBuffer[0] = v[0] + 8*sinf_neon(v[1]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[1] = v[1] + 8*sinf_neon(v[0]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[2] = v[2];\n\t\tgTexCoordBuffer[0] = v[5];\n\t\tgTexCoordBuffer[1] = v[6];\n\t\tgVertexBuffer +=3;\n\t\tgTexCoordBuffer +=2;\n\t}\n\tvglVertexAttribPointerMapped(0, pnv);\n\tvglVertexAttribPointerMapped(1, pnt);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n}\n\nvoid DrawGLWaterPolyWithLightmap(glpoly_t *p, int t1, int t2)\n{\n\tGL_Bind (t1);\n\tint\t\ti;\n\tfloat\t*v;\n\tfloat\ts, t, os, ot;\n\tvec3_t\tnv;\n\n\tv = p->verts[0];\n\n\tfloat *pnv = gVertexBuffer;\n\tfloat *pnt = gTexCoordBuffer;\n\tfloat *pnt2 = gTexCoordBuffer;\n\tpnt2 += ((p->numverts+1) * 2);\n\tfloat *gTexCoordBuffer2 = pnt2;\n\t\n\tfor (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)\n\t{\n\t\tfloat sinv2 = sinf_neon(v[2]*0.05f+realtime);\n\t\tgVertexBuffer[0] = v[0] + 8*sinf_neon(v[1]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[1] = v[1] + 8*sinf_neon(v[0]*0.05f+realtime)*sinv2;\n\t\tgVertexBuffer[2] = v[2];\n\t\tgTexCoordBuffer[0] = v[3];\n\t\tgTexCoordBuffer[1] = v[4];\n\t\tgTexCoordBuffer2[0] = v[5];\n\t\tgTexCoordBuffer2[1] = v[6];\n\t\tgVertexBuffer +=3;\n\t\tgTexCoordBuffer +=2;\n\t\tgTexCoordBuffer2 +=2;\n\t}\n\tvglVertexAttribPointerMapped(0, pnv);\n\tvglVertexAttribPointerMapped(1, pnt);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n\n\tGL_Bind (t2);\n\tglEnable (GL_BLEND);\n\tvglVertexAttribPointerMapped(1, pnt2);\n\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n\tglDisable (GL_BLEND);\n\t\n\tgTexCoordBuffer = gTexCoordBuffer2;\n}\n\n/*\n================\nDrawGLPoly\n================\n*/\nvoid DrawGLPoly (glpoly_t *p)\n{\n\tint i;\t\n\tfloat* v = p->verts[0];\n\tfloat* pnv = gVertexBuffer;\n\tfloat* pnt = gTexCoordBuffer;\n\t\n\tfor (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)\n\t{\n\t\tgVertexBuffer[0] = v[0];\n\t\tgVertexBuffer[1] = v[1];\n\t\tgVertexBuffer[2] = v[2];\n\t\tgTexCoordBuffer[0] = v[3];\n\t\tgTexCoordBuffer[1] = v[4];\n\t\tgVertexBuffer += 3;\n\t\tgTexCoordBuffer +=2;\n\t}\n\t\n\tvglVertexAttribPointerMapped(0, pnv);\n\tvglVertexAttribPointerMapped(1, pnt);\n    GL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n}\n\nvoid DrawGLPolyLightmap (glpoly_t *p)\n{\n\tint i;\t\n\tfloat* v = p->verts[0];\n\tfloat* pnv = gVertexBuffer;\n\tfloat* pnt = gTexCoordBuffer;\n\t\n\tfor (i=0 ; i<p->numverts ; i++, v+= VERTEXSIZE)\n\t{\n\t\tgVertexBuffer[0] = v[0];\n\t\tgVertexBuffer[1] = v[1];\n\t\tgVertexBuffer[2] = v[2];\n\t\tgTexCoordBuffer[0] = v[5];\n\t\tgTexCoordBuffer[1] = v[6];\n\t\tgVertexBuffer += 3;\n\t\tgTexCoordBuffer +=2;\n\t}\n\t\n\tvglVertexAttribPointerMapped(0, pnv);\n\tvglVertexAttribPointerMapped(1, pnt);\n    GL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n}\n\n\n/*\n================\nR_BlendLightmaps\n================\n*/\n\nvoid R_BlendLightmaps (void)\n{\n\tint\t\t\ti, j;\n\tglpoly_t\t*p;\n\tfloat\t\t*v;\n\tglRect_t\t*theRect;\n\n\tif (r_fullbright.value)\n\t\treturn;\n\n\tGL_EnableState(GL_MODULATE);\n\tGL_Color(1,1,1,1);\n\tglDepthMask(GL_FALSE);\t\t// don't bother writing Z\n\tglBlendFunc (GL_ZERO, GL_SRC_COLOR);\n\tglEnable (GL_BLEND);\n\t\n\tfor (i=0 ; i<MAX_LIGHTMAPS ; i++)\n\t{\n\t\tp = lightmap_polys[i];\n\t\tif (!p)\n\t\t\tcontinue;\n\t\tGL_Bind(lightmap_textures+i);\n\t\tif (lightmap_modified[i])\n\t\t{\n\t\t\tlightmap_modified[i] = false;\n\t\t\ttheRect = &lightmap_rectchange[i];\n\t\t\tglTexSubImage2D(GL_TEXTURE_2D, 0, 0, theRect->t, \n\t\t\t\tBLOCK_WIDTH, theRect->h, gl_lightmap_format, GL_UNSIGNED_BYTE,\n\t\t\t\tlightmaps+(i* BLOCK_HEIGHT + theRect->t) *BLOCK_WIDTH*lightmap_bytes);\n\t\t\ttheRect->l = BLOCK_WIDTH;\n\t\t\ttheRect->t = BLOCK_HEIGHT;\n\t\t\ttheRect->h = 0;\n\t\t\ttheRect->w = 0;\n\t\t}\n\t\tfor ( ; p ; p=p->chain)\n\t\t{\n\t\t\tif (p->flags & SURF_UNDERWATER)\n\t\t\t\tDrawGLWaterPolyLightmap (p);\n\t\t\telse\n\t\t\t{\n\t\t\t\tDrawGLPolyLightmap(p);\n\t\t\t}\n\t\t}\n\t}\n\n\tGL_EnableState(GL_REPLACE);\n\tglDisable (GL_BLEND);\n\tglDepthMask (GL_TRUE);\t\t// back to normal Z buffering\n}\n\n/*\n================\nR_RenderBrushPoly\n================\n*/\nvoid R_RenderBrushPoly (msurface_t *fa)\n{\n\ttexture_t\t*t;\n\tbyte\t\t*base;\n\tint\t\t\tmaps;\n\tglRect_t    *theRect;\n\tint smax, tmax;\n\n\tc_brush_polys++;\n\n\tif (fa->flags & SURF_DRAWSKY)\n\t{\t// warp texture, no lightmaps\n\t\tEmitBothSkyLayers (fa);\n\t\treturn;\n\t}\n\t\t\n\tt = R_TextureAnimation (fa->texinfo->texture);\n\tGL_Bind (t->gl_texturenum);\n\n\tif (fa->flags & SURF_DRAWTURB)\n\t{\t// warp texture, no lightmaps\n\t\tEmitWaterPolys (fa);\n\t\treturn;\n\t}\n\n\tif (fa->flags & SURF_UNDERWATER)\n\t\tDrawGLWaterPoly (fa->polys);\n\telse\n\t\tDrawGLPoly (fa->polys);\n\n\tfa->draw_this_frame = 1;\n\n\t// add the poly to the proper lightmap chain\n\n\tfa->polys->chain = lightmap_polys[fa->lightmaptexturenum];\n\tlightmap_polys[fa->lightmaptexturenum] = fa->polys;\n\t\n\tif (fa->overbright != gl_overbright.value)//MH\n\t{\n\t\tfa->overbright = gl_overbright.value;\n\t\tgoto dynamic;\n\t}\n\n\t// check for lightmap modification\n\tfor (maps = 0 ; maps < MAXLIGHTMAPS && fa->styles[maps] != 255 ;\n\t\t maps++)\n\t\tif (d_lightstylevalue[fa->styles[maps]] != fa->cached_light[maps])\n\t\t\tgoto dynamic;\n\n\tif (fa->dlightframe == r_framecount\t// dynamic this frame\n\t\t|| fa->cached_dlight)\t\t\t// dynamic previously\n\t{\ndynamic:\n\t\tif (r_dynamic.value)\n\t\t{\n\t\t\tlightmap_modified[fa->lightmaptexturenum] = true;\n\t\t\ttheRect = &lightmap_rectchange[fa->lightmaptexturenum];\n\t\t\tif (fa->light_t < theRect->t) {\n\t\t\t\tif (theRect->h)\n\t\t\t\t\ttheRect->h += theRect->t - fa->light_t;\n\t\t\t\ttheRect->t = fa->light_t;\n\t\t\t}\n\t\t\tif (fa->light_s < theRect->l) {\n\t\t\t\tif (theRect->w)\n\t\t\t\t\ttheRect->w += theRect->l - fa->light_s;\n\t\t\t\ttheRect->l = fa->light_s;\n\t\t\t}\n\t\t\tsmax = (fa->extents[0]>>4)+1;\n\t\t\ttmax = (fa->extents[1]>>4)+1;\n\t\t\tif ((theRect->w + theRect->l) < (fa->light_s + smax))\n\t\t\t\ttheRect->w = (fa->light_s-theRect->l)+smax;\n\t\t\tif ((theRect->h + theRect->t) < (fa->light_t + tmax))\n\t\t\t\ttheRect->h = (fa->light_t-theRect->t)+tmax;\n\t\t\tbase = lightmaps + fa->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;\n\t\t\tbase += fa->light_t * BLOCK_WIDTH * lightmap_bytes + fa->light_s * lightmap_bytes;\n\t\t\tR_BuildLightMap (fa, base, BLOCK_WIDTH*lightmap_bytes);\n\t\t}\n\t}\n}\n\n/*\n================\nR_MirrorChain\n================\n*/\nvoid R_MirrorChain (msurface_t *s)\n{\n\tif (mirror)\n\t\treturn;\n\tmirror = true;\n\tmirror_plane = s->plane;\n}\n\n/*\n================\nR_DrawWaterSurfaces\n================\n*/\nvoid R_DrawWaterSurfaces (void)\n{\n\tint\t\t\ti;\n\tmsurface_t\t*s;\n\ttexture_t\t*t;\n\n\tif (r_wateralpha.value == 1.0)\n\t\treturn;\n\n\t//\n\t// go back to the world matrix\n\t//\n\n    glLoadMatrixf (r_world_matrix);\n\n\tif (r_wateralpha.value < 1.0) {\n\t\tglEnable(GL_BLEND);\n\t\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\tGL_EnableState(GL_MODULATE);\n\t\tGL_DisableState(GL_ALPHA_TEST);\n\t\tglDepthMask(GL_FALSE);\n\t\tglEnable (GL_BLEND);\n\t\tGL_Color(1,1,1,r_wateralpha.value);\n\t\tGL_EnableState(GL_MODULATE);\n\t}\n\n\tfor (i=0 ; i<cl.worldmodel->numtextures ; i++)\n\t{\n\t\tt = cl.worldmodel->textures[i];\n\t\tif (!t)\n\t\t\tcontinue;\n\t\ts = t->texturechain;\n\t\tif (!s)\n\t\t\tcontinue;\n\t\tif ( !(s->flags & SURF_DRAWTURB ) )\n\t\t\tcontinue;\n\n\t\t// set modulate mode explicitly\n\t\t\t\n\t\tGL_Bind (t->gl_texturenum);\n\n\t\tfor ( ; s ; s=s->texturechain)\n\t\t\tEmitWaterPolys (s);\n\t\t\t\n\t\tt->texturechain = NULL;\n\t}\n\n\tif (r_wateralpha.value < 1.0) {\n\t\tGL_EnableState(GL_REPLACE);\n\t\tGL_EnableState(GL_ALPHA_TEST);\n\t\tGL_Color(1,1,1,1);\n\t\tglDisable (GL_BLEND);\n\t\tglDepthMask(GL_TRUE);\n\t}\n\n}\n\n/*\n================\nDrawTextureChains\n================\n*/\nvoid DrawTextureChains (void)\n{\n\tint\t\ti;\n\tmsurface_t\t*s;\n\ttexture_t\t*t;\n\n\tfor (i=0 ; i<cl.worldmodel->numtextures ; i++)\n\t{\n\t\tt = cl.worldmodel->textures[i];\n\t\tif (!t)\n\t\t\tcontinue;\n\t\ts = t->texturechain;\n\t\tif (!s)\n\t\t\tcontinue;\n\t\tif (i == skytexturenum)\n\t\t\tR_DrawSkyChain (s);\n\t\telse if (i == mirrortexturenum && r_mirroralpha.value != 1.0 && st_separation.value == 0)\n\t\t{\n\t\t\tR_MirrorChain (s);\n\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif ((s->flags & SURF_DRAWTURB) && r_wateralpha.value != 1.0)\n\t\t\t\tcontinue;\t// draw translucent water later\n\t\t\tfor ( ; s ; s=s->texturechain)\n\t\t\t\tR_RenderBrushPoly (s);\n\t\t}\n\n\t\tt->texturechain = NULL;\n\t}\n}\n\n/*\n=================\nR_DrawBrushModel\n=================\n*/\nvoid R_DrawBrushModel (entity_t *e)\n{\n\tint\t\t\tj, k;\n\tvec3_t\t\tmins, maxs;\n\tint\t\t\ti, numsurfaces;\n\tmsurface_t\t*psurf;\n\tfloat\t\tdot;\n\tmplane_t\t*pplane;\n\tmodel_t\t\t*clmodel;\n\tbool\trotated;\n\tbool\ttransparent;\n\t\n\tcurrententity = e;\n\tcurrenttexture = -1;\n\n\tclmodel = e->model;\n\n\tif (e->angles[0] || e->angles[1] || e->angles[2])\n\t{\n\t\trotated = true;\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\tmins[i] = e->origin[i] - clmodel->radius;\n\t\t\tmaxs[i] = e->origin[i] + clmodel->radius;\n\t\t}\n\t}\n\telse\n\t{\n\t\trotated = false;\n\t\tVectorAdd (e->origin, clmodel->mins, mins);\n\t\tVectorAdd (e->origin, clmodel->maxs, maxs);\n\t}\n\n\tif (R_CullBox (mins, maxs))\n\t\treturn;\n\t\n\ttransparent = ISTRANSPARENT(e);\n\tif (transparent) {\n\t\tglEnable(GL_BLEND);\n\t\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\tGL_EnableState(GL_MODULATE);\n\t\tGL_DisableState(GL_ALPHA_TEST);\n\t\tglDepthMask(GL_FALSE);\n\t\tGL_Color(1,1,1,e->alpha);\n\t} else\n\t\tGL_Color(1,1,1,1);\n\t\n\tmemset (lightmap_polys, 0, sizeof(lightmap_polys));\n\n\tVectorSubtract (r_refdef.vieworg, e->origin, modelorg);\n\tif (rotated)\n\t{\n\t\tvec3_t\ttemp;\n\t\tvec3_t\tforward, right, up;\n\n\t\tVectorCopy (modelorg, temp);\n\t\tAngleVectors (e->angles, forward, right, up);\n\t\tmodelorg[0] = DotProduct (temp, forward);\n\t\tmodelorg[1] = -DotProduct (temp, right);\n\t\tmodelorg[2] = DotProduct (temp, up);\n\t}\n\n\tpsurf = &clmodel->surfaces[clmodel->firstmodelsurface];\n\n// calculate dynamic lighting for bmodel if it's not an\n// instanced model\n\tif (clmodel->firstmodelsurface != 0 && !gl_flashblend.value)\n\t{\n\t\tfor (k=0 ; k<MAX_DLIGHTS ; k++)\n\t\t{\n\t\t\tif ((cl_dlights[k].die < cl.time) ||\n\t\t\t\t(!cl_dlights[k].radius))\n\t\t\t\tcontinue;\n\n\t\t\tR_MarkLights (&cl_dlights[k], 1<<k,\n\t\t\t\tclmodel->nodes + clmodel->hulls[0].firstclipnode);\n\t\t}\n\t}\n\n    glPushMatrix ();\n\te->angles[0] = -e->angles[0];\t// stupid quake bug\n\tR_RotateForEntity (e);\n\te->angles[0] = -e->angles[0];\t// stupid quake bug\n\n\t//\n\t// draw texture\n\t//\n\tfor (i=0 ; i<clmodel->nummodelsurfaces ; i++, psurf++)\n\t{\n\t// find which side of the node we are on\n\t\tpplane = psurf->plane;\n\n\t\tdot = DotProduct (modelorg, pplane->normal) - pplane->dist;\n\n\t// draw the polygon\n\t\tif (((psurf->flags & SURF_PLANEBACK) && (dot < -BACKFACE_EPSILON)) ||\n\t\t\t(!(psurf->flags & SURF_PLANEBACK) && (dot > BACKFACE_EPSILON)))\n\t\t{\n\t\t\tR_RenderBrushPoly (psurf);\n\t\t\tif (transparent) psurf->draw_this_frame = 0;\n\t\t}\n\t}\n\n\tif (transparent) \n\t\tGL_EnableState(GL_ALPHA_TEST);\n\t//else FIXME: Disabling lightmaps (as it should be) causes some glitches related to some depth bug most likely\n\t\tR_BlendLightmaps ();\n\t\n\tDrawFullBrightTextures (clmodel->surfaces, clmodel->numsurfaces);\n\t\n\tglPopMatrix ();\n}\n\n/*\n=============================================================\n\n\tWORLD MODEL\n\n=============================================================\n*/\n\n/*\n================\nR_RecursiveWorldNode\n================\n*/\nvoid R_RecursiveWorldNode (mnode_t *node)\n{\n\tint\t\t\ti, c, side, *pindex;\n\tvec3_t\t\tacceptpt, rejectpt;\n\tmplane_t\t*plane;\n\tmsurface_t\t*surf, **mark;\n\tmleaf_t\t\t*pleaf;\n\tdouble\t\td, dot;\n\tvec3_t\t\tmins, maxs;\n\n\tif (node->contents == CONTENTS_SOLID)\n\t\treturn;\t\t// solid\n\n\tif (node->visframe != r_visframecount)\n\t\treturn;\n\tif (R_CullBox (node->minmaxs, node->minmaxs+3))\n\t\treturn;\n\t\n// if a leaf node, draw stuff\n\tif (node->contents < 0)\n\t{\n\t\tpleaf = (mleaf_t *)node;\n\n\t\tmark = pleaf->firstmarksurface;\n\t\tc = pleaf->nummarksurfaces;\n\n\t\tif (c)\n\t\t{\n\t\t\tdo\n\t\t\t{\n\t\t\t\t(*mark)->visframe = r_framecount;\n\t\t\t\tmark++;\n\t\t\t} while (--c);\n\t\t}\n\n\t// deal with model fragments in this leaf\n\t\tif (pleaf->efrags)\n\t\t\tR_StoreEfrags (&pleaf->efrags);\n\n\t\treturn;\n\t}\n\n// node is just a decision point, so go down the apropriate sides\n\n// find which side of the node we are on\n\tplane = node->plane;\n\n\tswitch (plane->type)\n\t{\n\tcase PLANE_X:\n\t\tdot = modelorg[0] - plane->dist;\n\t\tbreak;\n\tcase PLANE_Y:\n\t\tdot = modelorg[1] - plane->dist;\n\t\tbreak;\n\tcase PLANE_Z:\n\t\tdot = modelorg[2] - plane->dist;\n\t\tbreak;\n\tdefault:\n\t\tdot = DotProduct (modelorg, plane->normal) - plane->dist;\n\t\tbreak;\n\t}\n\n\tif (dot >= 0)\n\t\tside = 0;\n\telse\n\t\tside = 1;\n\n// recurse down the children, front side first\n\tR_RecursiveWorldNode (node->children[side]);\n\n// draw stuff\n\tc = node->numsurfaces;\n\n\tif (c)\n\t{\n\t\tsurf = cl.worldmodel->surfaces + node->firstsurface;\n\n\t\tif (dot < 0 -BACKFACE_EPSILON)\n\t\t\tside = SURF_PLANEBACK;\n\t\telse if (dot > BACKFACE_EPSILON)\n\t\t\tside = 0;\n\t\t{\n\t\t\tfor ( ; c ; c--, surf++)\n\t\t\t{\n\t\t\t\tif (surf->visframe != r_framecount)\n\t\t\t\t\tcontinue;\n\n\t\t\t\t// don't backface underwater surfaces, because they warp\n\t\t\t\tif ( !(surf->flags & SURF_UNDERWATER) && ( (dot < 0) ^ !!(surf->flags & SURF_PLANEBACK)) )\n\t\t\t\t\tcontinue;\t\t// wrong side\n\n\t\t\t\t// just store it out\n\t\t\t\tif (!mirror\n\t\t\t\t|| surf->texinfo->texture != cl.worldmodel->textures[mirrortexturenum])\n\t\t\t\t{\n\t\t\t\t\tsurf->texturechain = surf->texinfo->texture->texturechain;\n\t\t\t\t\tsurf->texinfo->texture->texturechain = surf;\n\t\t\t\t}\n\n\t\t\t}\n\t\t}\n\n\t}\n\n// recurse down the back side\n\tR_RecursiveWorldNode (node->children[!side]);\n}\n\n\n\n/*\n=============\nR_DrawWorld\n=============\n*/\nvoid R_DrawWorld (void)\n{\n\tentity_t\tent;\n\tint\t\t\ti;\n\n\tmemset (&ent, 0, sizeof(ent));\n\tent.model = cl.worldmodel;\n\n\tVectorCopy (r_refdef.vieworg, modelorg);\n\n\tcurrententity = &ent;\n\tcurrenttexture = -1;\n\n\tGL_Color(1,1,1,1);\n\tmemset (lightmap_polys, 0, sizeof(lightmap_polys));\n\n\tR_RecursiveWorldNode (cl.worldmodel->nodes);\n\n\tDrawTextureChains ();\n\n\tR_BlendLightmaps ();\n\n\tDrawFullBrightTextures (cl.worldmodel->surfaces, cl.worldmodel->numsurfaces);\n\n}\n\n\n/*\n===============\nR_MarkLeaves\n===============\n*/\nvoid R_MarkLeaves (void)\n{\n\tbyte\t*vis;\n\tmnode_t\t*node;\n\tint\t\ti;\n\tbyte\tsolid[4096];\n\n\tif (r_oldviewleaf == r_viewleaf && !r_novis.value)\n\t\treturn;\n\t\n\tif (mirror)\n\t\treturn;\n\n\tr_visframecount++;\n\tr_oldviewleaf = r_viewleaf;\n\n\tif (r_novis.value)\n\t{\n\t\tvis = solid;\n\t\tmemset (solid, 0xff, (cl.worldmodel->numleafs+7)>>3);\n\t}\n\telse\n\t\tvis = Mod_LeafPVS (r_viewleaf, cl.worldmodel);\n\t\t\n\tfor (i=0 ; i<cl.worldmodel->numleafs ; i++)\n\t{\n\t\tif (vis[i>>3] & (1<<(i&7)))\n\t\t{\n\t\t\tnode = (mnode_t *)&cl.worldmodel->leafs[i+1];\n\t\t\tdo\n\t\t\t{\n\t\t\t\tif (node->visframe == r_visframecount)\n\t\t\t\t\tbreak;\n\t\t\t\tnode->visframe = r_visframecount;\n\t\t\t\tnode = node->parent;\n\t\t\t} while (node);\n\t\t}\n\t}\n}\n\n\n\n/*\n=============================================================================\n\n  LIGHTMAP ALLOCATION\n\n=============================================================================\n*/\n\n// returns a texture number and the position inside it\nint AllocBlock (int w, int h, int *x, int *y)\n{\n\tint\t\ti, j;\n\tint\t\tbest, best2;\n\tint\t\tbestx;\n\tint\t\ttexnum;\n\n\tfor (texnum=0 ; texnum<MAX_LIGHTMAPS ; texnum++)\n\t{\n\t\tbest = BLOCK_HEIGHT;\n\n\t\tfor (i=0 ; i<BLOCK_WIDTH-w ; i++)\n\t\t{\n\t\t\tbest2 = 0;\n\n\t\t\tfor (j=0 ; j<w ; j++)\n\t\t\t{\n\t\t\t\tif (allocated[texnum][i+j] >= best)\n\t\t\t\t\tbreak;\n\t\t\t\tif (allocated[texnum][i+j] > best2)\n\t\t\t\t\tbest2 = allocated[texnum][i+j];\n\t\t\t}\n\t\t\tif (j == w)\n\t\t\t{\t// this is a valid spot\n\t\t\t\t*x = i;\n\t\t\t\t*y = best = best2;\n\t\t\t}\n\t\t}\n\n\t\tif (best + h > BLOCK_HEIGHT)\n\t\t\tcontinue;\n\n\t\tfor (i=0 ; i<w ; i++)\n\t\t\tallocated[texnum][*x + i] = best + h;\n\n\t\treturn texnum;\n\t}\n\n\tSys_Error (\"AllocBlock: full\");\n}\n\n\nmvertex_t\t*r_pcurrentvertbase;\nmodel_t\t\t*currentmodel;\n\nint\tnColinElim;\n\n/*\n================\nBuildSurfaceDisplayList\n================\n*/\nvoid BuildSurfaceDisplayList (msurface_t *fa)\n{\n\tint\t\t\ti, lindex, lnumverts, s_axis, t_axis;\n\tmedge_t\t\t*pedges, *r_pedge;\n\tmplane_t\t*pplane;\n\tint\t\t\tvertpage, newverts, newpage, lastvert;\n\tbool\tvisible;\n\tfloat\t\t*vec;\n\tfloat\t\ts, t;\n\tglpoly_t\t*poly;\n\n// reconstruct the polygon\n\tpedges = currentmodel->edges;\n\tlnumverts = fa->numedges;\n\tvertpage = 0;\n\n\t//\n\t// draw texture\n\t//\n\tpoly = Hunk_Alloc (sizeof(glpoly_t) + (lnumverts-4) * VERTEXSIZE*sizeof(float));\n\tpoly->next = fa->polys;\n\tpoly->flags = fa->flags;\n\tfa->polys = poly;\n\tpoly->numverts = lnumverts;\n\n\tfor (i=0 ; i<lnumverts ; i++)\n\t{\n\t\tlindex = currentmodel->surfedges[fa->firstedge + i];\n\n\t\tif (lindex > 0)\n\t\t{\n\t\t\tr_pedge = &pedges[lindex];\n\t\t\tvec = r_pcurrentvertbase[r_pedge->v[0]].position;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tr_pedge = &pedges[-lindex];\n\t\t\tvec = r_pcurrentvertbase[r_pedge->v[1]].position;\n\t\t}\n\t\ts = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];\n\t\ts /= fa->texinfo->texture->width;\n\n\t\tt = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];\n\t\tt /= fa->texinfo->texture->height;\n\n\t\tVectorCopy (vec, poly->verts[i]);\n\t\tpoly->verts[i][3] = s;\n\t\tpoly->verts[i][4] = t;\n\n\t\t//\n\t\t// lightmap texture coordinates\n\t\t//\n\t\ts = DotProduct (vec, fa->texinfo->vecs[0]) + fa->texinfo->vecs[0][3];\n\t\ts -= fa->texturemins[0];\n\t\ts += fa->light_s*16;\n\t\ts += 8;\n\t\ts /= BLOCK_WIDTH*16; //fa->texinfo->texture->width;\n\n\t\tt = DotProduct (vec, fa->texinfo->vecs[1]) + fa->texinfo->vecs[1][3];\n\t\tt -= fa->texturemins[1];\n\t\tt += fa->light_t*16;\n\t\tt += 8;\n\t\tt /= BLOCK_HEIGHT*16; //fa->texinfo->texture->height;\n\n\t\tpoly->verts[i][5] = s;\n\t\tpoly->verts[i][6] = t;\n\t}\n\n\t//\n\t// remove co-linear points - Ed\n\t//\n\tif (!gl_keeptjunctions.value && !(fa->flags & SURF_UNDERWATER) )\n\t{\n\t\tfor (i = 0 ; i < lnumverts ; ++i)\n\t\t{\n\t\t\tvec3_t v1, v2;\n\t\t\tfloat *prev, *this, *next;\n\t\t\tfloat f;\n\n\t\t\tprev = poly->verts[(i + lnumverts - 1) % lnumverts];\n\t\t\tthis = poly->verts[i];\n\t\t\tnext = poly->verts[(i + 1) % lnumverts];\n\n\t\t\tVectorSubtract( this, prev, v1 );\n\t\t\tVectorNormalize( v1 );\n\t\t\tVectorSubtract( next, prev, v2 );\n\t\t\tVectorNormalize( v2 );\n\n\t\t\t// skip co-linear points\n\t\t\t#define COLINEAR_EPSILON 0.001\n\t\t\tif ((fabs( v1[0] - v2[0] ) <= COLINEAR_EPSILON) &&\n\t\t\t\t(fabs( v1[1] - v2[1] ) <= COLINEAR_EPSILON) && \n\t\t\t\t(fabs( v1[2] - v2[2] ) <= COLINEAR_EPSILON))\n\t\t\t{\n\t\t\t\tint j;\n\t\t\t\tfor (j = i + 1; j < lnumverts; ++j)\n\t\t\t\t{\n\t\t\t\t\tint k;\n\t\t\t\t\tfor (k = 0; k < VERTEXSIZE; ++k)\n\t\t\t\t\t\tpoly->verts[j - 1][k] = poly->verts[j][k];\n\t\t\t\t}\n\t\t\t\t--lnumverts;\n\t\t\t\t++nColinElim;\n\t\t\t\t// retry next vertex next time, which is now current vertex\n\t\t\t\t--i;\n\t\t\t}\n\t\t}\n\t}\n\tpoly->numverts = lnumverts;\n\n}\n\n/*\n========================\nGL_CreateSurfaceLightmap\n========================\n*/\nvoid GL_CreateSurfaceLightmap (msurface_t *surf)\n{\n\tint\t\tsmax, tmax, s; //, t, l, i;\n\tbyte\t*base;\n\n\tif (surf->flags & (SURF_DRAWSKY|SURF_DRAWTURB))\n\t\treturn;\n\n\tsmax = (surf->extents[0]>>4)+1;\n\ttmax = (surf->extents[1]>>4)+1;\n\n\tsurf->lightmaptexturenum = AllocBlock (smax, tmax, &surf->light_s, &surf->light_t);\n\tbase = lightmaps + surf->lightmaptexturenum*lightmap_bytes*BLOCK_WIDTH*BLOCK_HEIGHT;\n\tbase += (surf->light_t * BLOCK_WIDTH + surf->light_s) * lightmap_bytes;\n\tR_BuildLightMap (surf, base, BLOCK_WIDTH*lightmap_bytes);\n}\n\n\n/*\n==================\nGL_BuildLightmaps\n\nBuilds the lightmap texture\nwith all the surfaces from all brush models\n==================\n*/\nvoid GL_BuildLightmaps (void)\n{\n\tint\t\ti, j;\n\tmodel_t\t*m;\n\textern bool isPermedia;\n\n\tmemset (allocated, 0, sizeof(allocated));\n\n\tr_framecount = 1;\t\t// no dlightcache\n\n\tif (!lightmap_textures)\n\t{\n\t\tlightmap_textures = texture_extension_number;\n\t\ttexture_extension_number += MAX_LIGHTMAPS;\n\t}\n\n\tgl_lightmap_format = GL_RGBA;\n\tlightmap_bytes = 4;\n\n\tfor (j=1 ; j<MAX_MODELS ; j++)\n\t{\n\t\tm = cl.model_precache[j];\n\t\tif (!m)\n\t\t\tbreak;\n\t\tif (m->name[0] == '*')\n\t\t\tcontinue;\n\t\tr_pcurrentvertbase = m->vertexes;\n\t\tcurrentmodel = m;\n\t\tfor (i=0 ; i<m->numsurfaces ; i++)\n\t\t{\n\t\t\tGL_CreateSurfaceLightmap (m->surfaces + i);\n\t\t\tif ( m->surfaces[i].flags & SURF_DRAWTURB )\n\t\t\t\tcontinue;\n\t\t\tif ( m->surfaces[i].flags & SURF_DRAWSKY )\n\t\t\t\tcontinue;\n\t\t\tBuildSurfaceDisplayList (m->surfaces + i);\n\t\t}\n\t}\n\n\t//\n\t// upload all lightmaps that were filled\n\t//\n\tfor (i=0 ; i<MAX_LIGHTMAPS ; i++)\n\t{\n\t\tif (!allocated[i][0])\n\t\t\tbreak;\t\t// no more used\n\t\tlightmap_modified[i] = false;\n\t\tlightmap_rectchange[i].l = BLOCK_WIDTH;\n\t\tlightmap_rectchange[i].t = BLOCK_HEIGHT;\n\t\tlightmap_rectchange[i].w = 0;\n\t\tlightmap_rectchange[i].h = 0;\n\t\tGL_Bind(lightmap_textures + i);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\t\tglTexImage2D (GL_TEXTURE_2D, 0, lightmap_bytes\n\t\t, BLOCK_WIDTH, BLOCK_HEIGHT, 0, \n\t\tgl_lightmap_format, GL_UNSIGNED_BYTE, lightmaps+i*BLOCK_WIDTH*BLOCK_HEIGHT*lightmap_bytes);\n\t}\n\n}\n\n"
  },
  {
    "path": "source/gl_screen.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// screen.c -- master for refresh, status bar, console, chat, notify, etc\n\n#include \"quakedef.h\"\n\n/*\n\nbackground clear\nrendering\nturtle/net/ram icons\nsbar\ncenterprint / slow centerprint\nnotify lines\nintermission / finale overlay\nloading plaque\nconsole\nmenu\n\nrequired background clears\nrequired update regions\n\n\nsyncronous draw mode or async\nOne off screen buffer, with updates either copied or xblited\nNeed to double buffer?\n\n\nasync draw will require the refresh area to be cleared, because it will be\nxblited, but sync draw can just ignore it.\n\nsync\ndraw\n\nCenterPrint ()\nSlowPrint ()\nScreen_Update ();\nCon_Printf ();\n\nnet \nturn off messages option\n\nthe refresh is allways rendered, unless the console is full screen\n\n\nconsole is:\n\tnotify lines\n\thalf\n\tfull\n\t\n\n*/\n\n\nint\t\t\tglx, gly, glwidth, glheight;\n\n// only the refresh window will be updated unless these variables are flagged \nint\t\t\tscr_copytop;\nint\t\t\tscr_copyeverything;\n\nfloat\t\tscr_con_current;\nfloat\t\tscr_conlines;\t\t// lines of console to display\n\nfloat\t\toldscreensize, oldfov, oldsbaralpha;\n\nCVAR\t(viewsize, 100, CVAR_ARCHIVE)\nCVAR\t(fov,\t\t90, CVAR_ARCHIVE) // LIMITS: 10 - 170\n\nCVAR\t(scr_conspeed, 300, CVAR_NONE)\nCVAR\t(scr_centertime, 2, CVAR_NONE)\nCVAR\t(scr_sbaralpha, 0.50, CVAR_ARCHIVE)\nCVAR\t(scr_conscale, 1, CVAR_ARCHIVE)\nCVAR\t(scr_conwidth, 0, CVAR_ARCHIVE)\nCVAR\t(scr_conalpha, 0.75, CVAR_ARCHIVE)\nCVAR\t(scr_menuscale, 2, CVAR_ARCHIVE)\nCVAR\t(scr_sbarscale, 1, CVAR_ARCHIVE)\nCVAR\t(scr_crosshairscale, 1, CVAR_ARCHIVE)\n\nCVAR\t(showram, 1,\tCVAR_ARCHIVE)\nCVAR\t(showturtle, 0, CVAR_ARCHIVE)\nCVAR\t(showpause, 1, CVAR_NONE)\nCVAR\t(scr_printspeed, 8, CVAR_NONE)\nCVAR\t(gl_triplebuffer, 0, CVAR_ARCHIVE)\n\nextern\tcvar_t\tcrosshair;\n\nbool\tscr_initialized;\t\t// ready to draw\n\nqpic_t\t\t*scr_ram;\nqpic_t\t\t*scr_net;\nqpic_t\t\t*scr_turtle;\n\nint\t\t\tscr_fullupdate;\n\nint\t\t\tclearconsole;\nint\t\t\tclearnotify;\n\nint\t\t\tsb_lines;\n\nviddef_t\tvid;\t\t\t\t// global video state\n\nvrect_t\t\tscr_vrect;\n\nbool\tscr_disabled_for_loading;\nbool\tscr_drawloading;\nfloat\t\tscr_disabled_time;\n\nbool\tblock_drawing;\n\nvoid SCR_ScreenShot_f (void);\n\n/*\n===============================================================================\n\nCENTER PRINTING\n\n===============================================================================\n*/\n\nchar\t\tscr_centerstring[1024];\nfloat\t\tscr_centertime_start;\t// for slow victory printing\nfloat\t\tscr_centertime_off;\nint\t\t\tscr_center_lines;\nint\t\t\tscr_erase_lines;\nint\t\t\tscr_erase_center;\n\n/*\n==============\nSCR_CenterPrint\n\nCalled for important messages that should stay in the center of the screen\nfor a few moments\n==============\n*/\nvoid SCR_CenterPrint (char *str)\n{\n\tstrncpy (scr_centerstring, str, sizeof(scr_centerstring)-1);\n\tscr_centertime_off = scr_centertime.value;\n\tscr_centertime_start = cl.time;\n\n// count the number of lines for centering\n\tscr_center_lines = 1;\n\twhile (*str)\n\t{\n\t\tif (*str == '\\n')\n\t\t\tscr_center_lines++;\n\t\tstr++;\n\t}\n}\n\n\nvoid SCR_DrawCenterString (void)\n{\n\tchar\t*start;\n\tint\t\tl;\n\tint\t\tj;\n\tint\t\tx, y;\n\tint\t\tremaining;\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n// the finale prints the characters one at a time\n\tif (cl.intermission)\n\t\tremaining = scr_printspeed.value * (cl.time - scr_centertime_start);\n\telse\n\t\tremaining = 9999;\n\n\tscr_erase_center = 0;\n\tstart = scr_centerstring;\n\n\tif (scr_center_lines <= 4)\n\t\ty = 200*0.35;\t//johnfitz -- 320x200 coordinate system\n\telse\n\t\ty = 48;\n\n\tdo\t\n\t{\n\t// scan the width of the line\n\t\tfor (l=0 ; l<40 ; l++)\n\t\t\tif (start[l] == '\\n' || !start[l])\n\t\t\t\tbreak;\n\t\tx = (320 - l*8)/2;\t//johnfitz -- 320x200 coordinate system\n\t\tfor (j=0 ; j<l ; j++, x+=8)\n\t\t{\n\t\t\tDraw_Character (x, y, start[j]);\t\n\t\t\tif (!remaining--)\n\t\t\t\treturn;\n\t\t}\n\t\t\t\n\t\ty += 8;\n\n\t\twhile (*start && *start != '\\n')\n\t\t\tstart++;\n\n\t\tif (!*start)\n\t\t\tbreak;\n\t\tstart++;\t\t// skip the \\n\n\t} while (1);\n}\n\nvoid SCR_CheckDrawCenterString (void)\n{\n\tscr_copytop = 1;\n\tif (scr_center_lines > scr_erase_lines)\n\t\tscr_erase_lines = scr_center_lines;\n\n\tscr_centertime_off -= host_frametime;\n\t\n\tif (scr_centertime_off <= 0 && !cl.intermission)\n\t\treturn;\n\tif (key_dest != key_game)\n\t\treturn;\n\n\tSCR_DrawCenterString ();\n}\n\n//=============================================================================\n\n/*\n====================\nCalcFov\n====================\n*/\nfloat CalcFov (float fov_x, float width, float height)\n{\n        float   a;\n        float   x;\n\n        if (fov_x < 1 || fov_x > 179)\n                Sys_Error (\"Bad fov: %f\", fov_x);\n\n        x = width/tan(fov_x/360*M_PI);\n\n        a = atan (height/x);\n\n        a = a*360/M_PI;\n\n        return a;\n}\n\n/*\n=================\nSCR_CalcRefdef\n\nMust be called whenever vid changes\nInternal use only\n=================\n*/\nstatic void SCR_CalcRefdef (void)\n{\n\tvrect_t\t\tvrect;\n\tfloat\t\tsize, scale;\n\tint\t\th;\n\tbool\t\tfull = false;\n\n\n\tscr_fullupdate = 0;\t\t// force a background redraw\n\tvid.recalc_refdef = 0;\n\n// force the status bar to redraw\n\tSbar_Changed ();\n\n//========================================\n\t\n\t// bound viewsize\n\tif (viewsize.value < 30)\n\t\tCvar_Set (\"viewsize\",\"30\");\n\tif (viewsize.value > 120)\n\t\tCvar_Set (\"viewsize\",\"120\");\n\n\t// bound field of view\n\tif (fov.value < 10)\n\t\tCvar_Set (\"fov\",\"10\");\n\tif (fov.value > 170)\n\t\tCvar_Set (\"fov\",\"170\");\n\t\n\tvid.recalc_refdef = 0;\n\n\t//johnfitz -- rewrote this section\n\tsize = viewsize.value;\n\tscale = Q_CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0);\n\n\tif (size >= 120 || cl.intermission || scr_sbaralpha.value < 1) //johnfitz -- scr_sbaralpha.value\n\t\tsb_lines = 0;\n\telse if (size >= 110)\n\t\tsb_lines = 24 * scale;\n\telse\n\t\tsb_lines = 48 * scale;\n\n\tsize = fmin(viewsize.value, 100) / 100;\n\t//johnfitz\n\n\t//johnfitz -- rewrote this section\n\tr_refdef.vrect.width = fmax(glwidth * size, 96); //no smaller than 96, for icons\n\tr_refdef.vrect.height = fmin(glheight * size, glheight - sb_lines); //make room for sbar\n\tr_refdef.vrect.x = (glwidth - r_refdef.vrect.width)/2;\n\tr_refdef.vrect.y = (glheight - sb_lines - r_refdef.vrect.height)/2;\n\t//johnfitz\n\n\tr_refdef.fov_x = fov.value;\n\tr_refdef.fov_y = CalcFov (r_refdef.fov_x, r_refdef.vrect.width, r_refdef.vrect.height);\n\n\tscr_vrect = r_refdef.vrect;\n}\n\n\n/*\n=================\nSCR_SizeUp_f\n\nKeybinding command\n=================\n*/\nvoid SCR_SizeUp_f (void)\n{\n\tCvar_SetValue (\"viewsize\", viewsize.value+10);\n\tvid.recalc_refdef = 1;\n}\n\n\n/*\n=================\nSCR_SizeDown_f\n\nKeybinding command\n=================\n*/\nvoid SCR_SizeDown_f (void)\n{\n\tCvar_SetValue (\"viewsize\", viewsize.value-10);\n\tvid.recalc_refdef = 1;\n}\n\n//============================================================================\n\n/*\n==================\nSCR_Init\n==================\n*/\nvoid SCR_Init (void)\n{\n\tCvar_RegisterVariable (&viewsize);\n\tCvar_RegisterVariable (&fov);\n\tCvar_RegisterVariable (&scr_sbaralpha);\n\tCvar_RegisterVariable (&scr_conalpha);\n\tCvar_RegisterVariable (&scr_conwidth);\n\tCvar_RegisterVariable (&scr_conscale);\n\tCvar_RegisterVariable (&scr_menuscale);\n\tCvar_RegisterVariable (&scr_sbarscale);\n\tCvar_RegisterVariable (&scr_conspeed);\n\tCvar_RegisterVariable (&showram);\n\tCvar_RegisterVariable (&showturtle);\n\tCvar_RegisterVariable (&showpause);\n\tCvar_RegisterVariable (&scr_centertime);\n\tCvar_RegisterVariable (&scr_printspeed);\n\tCvar_RegisterVariable (&gl_triplebuffer);\n\n//\n// register our commands\n//\n\tCmd_AddCommand (\"screenshot\",SCR_ScreenShot_f);\n\tCmd_AddCommand (\"sizeup\",SCR_SizeUp_f);\n\tCmd_AddCommand (\"sizedown\",SCR_SizeDown_f);\n\n\tscr_ram = Draw_PicFromWad (\"ram\");\n\tscr_net = Draw_PicFromWad (\"net\");\n\tscr_turtle = Draw_PicFromWad (\"turtle\");\n\n\tscr_initialized = true;\n}\n\n\n\n/*\n==============\nSCR_DrawRam\n==============\n*/\nvoid SCR_DrawRam (void)\n{\n\tif (!showram.value)\n\t\treturn;\n\n\tif (!r_cache_thrash)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_DEFAULT); //johnfitz\n\t\n\tDraw_Pic (scr_vrect.x+32, scr_vrect.y, scr_ram);\n}\n\n/*\n==============\nSCR_DrawTurtle\n==============\n*/\nvoid SCR_DrawTurtle (void)\n{\n\tstatic int\tcount;\n\t\n\tif (!showturtle.value)\n\t\treturn;\n\n\tif (host_frametime < 0.1)\n\t{\n\t\tcount = 0;\n\t\treturn;\n\t}\n\n\tcount++;\n\tif (count < 3)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_DEFAULT); //johnfitz\n\t\n\tDraw_Pic (scr_vrect.x, scr_vrect.y, scr_turtle);\n}\n\n/*\n==============\nSCR_DrawNet\n==============\n*/\nvoid SCR_DrawNet (void)\n{\n\tif (realtime - cl.last_received_message < 0.3)\n\t\treturn;\n\tif (cls.demoplayback)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_DEFAULT); //johnfitz\n\n\tDraw_Pic (scr_vrect.x+64, scr_vrect.y, scr_net);\n}\n\n/*\n==============\nDrawPause\n==============\n*/\nvoid SCR_DrawPause (void)\n{\n\tqpic_t\t*pic;\n\n\tif (!showpause.value)\t\t// turn off for screenshots\n\t\treturn;\n\n\tif (!cl.paused)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n\tpic = Draw_CachePic (\"gfx/pause.lmp\");\n\tDraw_Pic ( (320 - pic->width)/2, \n\t\t(240 - 48 - pic->height)/2, pic);\n}\n\n\n\n/*\n==============\nSCR_DrawLoading\n==============\n*/\nvoid SCR_DrawLoading (void)\n{\n\tqpic_t\t*pic;\n\n\tif (!scr_drawloading)\n\t\treturn;\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\t\t\n\tpic = Draw_CachePic (\"gfx/loading.lmp\");\n\tDraw_Pic ( (320 - pic->width)/2, \n\t\t(240 - 48 - pic->height)/2, pic);\n}\n\n\n\n//=============================================================================\n\n\n/*\n==================\nSCR_SetUpToDrawConsole\n==================\n*/\nvoid SCR_SetUpToDrawConsole (void)\n{\n\t//johnfitz -- let's hack away the problem of slow console when host_timescale is <0\n\textern cvar_t host_timescale;\n\tfloat timescale;\n\t//johnfitz\n\t\n\tCon_CheckResize ();\n\t\n\tif (scr_drawloading)\n\t\treturn;\t\t// never a console with loading plaque\n\t\t\n// decide on the height of the console\n\tcon_forcedup = !cl.worldmodel || cls.signon != SIGNONS;\n\n\tif (con_forcedup)\n\t{\n\t\tscr_conlines = vid.height;\t\t// full screen\n\t\tscr_con_current = scr_conlines;\n\t}\n\telse if (key_dest == key_console)\n\t\tscr_conlines = vid.height/2;\t// half screen\n\telse\n\t\tscr_conlines = 0;\t\t\t\t// none visible\n\t\n\ttimescale = (host_timescale.value > 0) ? host_timescale.value : 1; //johnfitz -- timescale\n\t\n\tif (scr_conlines < scr_con_current)\n\t{\n\t\tscr_con_current -= scr_conspeed.value*host_frametime/timescale; //johnfitz -- timescale\n\t\tif (scr_conlines > scr_con_current)\n\t\t\tscr_con_current = scr_conlines;\n\n\t}\n\telse if (scr_conlines > scr_con_current)\n\t{\n\t\tscr_con_current += scr_conspeed.value*host_frametime/timescale; //johnfitz -- timescale\n\t\tif (scr_conlines < scr_con_current)\n\t\t\tscr_con_current = scr_conlines;\n\t}\n\n\tif (clearconsole++ < vid.numpages)\n\t{\n\t\tSbar_Changed ();\n\t}\n\telse if (clearnotify++ < vid.numpages)\n\t{\n\t}\n\telse\n\t\tcon_notifylines = 0;\n}\n\t\n/*\n==================\nSCR_DrawConsole\n==================\n*/\nvoid SCR_DrawConsole (void)\n{\n\tif (scr_con_current)\n\t{\n\t\tscr_copyeverything = 1;\n\t\tCon_DrawConsole (scr_con_current, true);\n\t\tclearconsole = 0;\n\t}\n\telse\n\t{\n\t\tif (key_dest == key_game || key_dest == key_message)\n\t\t\tCon_DrawNotify ();\t// only draw notify in game\n\t}\n}\n\n\n/* \n============================================================================== \n \n\t\t\t\t\t\tSCREEN SHOTS \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================== \nSCR_ScreenShot_f\n================== \n*/  \nvoid SCR_ScreenShot_f (void) \n{\n\tbyte\t\t*buffer;\n\tchar\t\tpcxname[80]; \n\tchar\t\tcheckname[MAX_OSPATH];\n\tint\t\t\ti, c, temp;\n// \n// find a file name to save it to \n// \n\tstrcpy(pcxname,\"quake00.tga\");\n\t\t\n\tfor (i=0 ; i<=99 ; i++) \n\t{ \n\t\tpcxname[5] = i/10 + '0'; \n\t\tpcxname[6] = i%10 + '0'; \n\t\tsprintf (checkname, \"%s/%s\", com_gamedir, pcxname);\n\t\tif (Sys_FileTime(checkname) == -1)\n\t\t\tbreak;\t// file doesn't exist\n\t} \n\tif (i==100) \n\t{\n\t\tCon_Printf (\"SCR_ScreenShot_f: Couldn't create a PCX file\\n\"); \n\t\treturn;\n \t}\n\n\n\tbuffer = malloc(glwidth*glheight*3 + 18);\n\tmemset (buffer, 0, 18);\n\tbuffer[2] = 2;\t\t// uncompressed type\n\tbuffer[12] = glwidth&255;\n\tbuffer[13] = glwidth>>8;\n\tbuffer[14] = glheight&255;\n\tbuffer[15] = glheight>>8;\n\tbuffer[16] = 24;\t// pixel size\n\n\tglReadPixels (glx, gly, glwidth, glheight, GL_RGB, GL_UNSIGNED_BYTE, buffer+18 ); \n\n\t// swap rgb to bgr\n\tc = 18+glwidth*glheight*3;\n\tfor (i=18 ; i<c ; i+=3)\n\t{\n\t\ttemp = buffer[i];\n\t\tbuffer[i] = buffer[i+2];\n\t\tbuffer[i+2] = temp;\n\t}\n\tCOM_WriteFile (pcxname, buffer, glwidth*glheight*3 + 18 );\n\n\tfree (buffer);\n\tCon_Printf (\"Wrote %s\\n\", pcxname);\n} \n\n\n//=============================================================================\n\n\n/*\n===============\nSCR_BeginLoadingPlaque\n\n================\n*/\nvoid SCR_BeginLoadingPlaque (void)\n{\n\tS_StopAllSounds (true);\n\n\tif (cls.state != ca_connected)\n\t\treturn;\n\tif (cls.signon != SIGNONS)\n\t\treturn;\n\t\n// redraw with no console and the loading plaque\n\tCon_ClearNotify ();\n\tscr_centertime_off = 0;\n\tscr_con_current = 0;\n\n\tscr_drawloading = true;\n\tscr_fullupdate = 0;\n\tSbar_Changed ();\n\tSCR_UpdateScreen ();\n\tscr_drawloading = false;\n\n\tscr_disabled_for_loading = true;\n\tscr_disabled_time = realtime;\n\tscr_fullupdate = 0;\n}\n\n/*\n===============\nSCR_EndLoadingPlaque\n\n================\n*/\nvoid SCR_EndLoadingPlaque (void)\n{\n\tscr_disabled_for_loading = false;\n\tscr_fullupdate = 0;\n\tCon_ClearNotify ();\n}\n\n//=============================================================================\n\nchar\t*scr_notifystring;\nbool\tscr_drawdialog;\n\nvoid SCR_DrawNotifyString (void)\n{\n\tchar\t*start;\n\tint\t\tl;\n\tint\t\tj;\n\tint\t\tx, y;\n\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\t\n\tstart = scr_notifystring;\n\n\ty = (int)(200*0.35);\n\n\tdo\t\n\t{\n\t// scan the width of the line\n\t\tfor (l=0 ; l<40 ; l++)\n\t\t\tif (start[l] == '\\n' || !start[l])\n\t\t\t\tbreak;\n\t\tx = (320 - l*8)/2;\n\t\tfor (j=0 ; j<l ; j++, x+=8)\n\t\t\tDraw_Character (x, y, start[j]);\t\n\t\t\t\n\t\ty += 8;\n\n\t\twhile (*start && *start != '\\n')\n\t\t\tstart++;\n\n\t\tif (!*start)\n\t\t\tbreak;\n\t\tstart++;\t\t// skip the \\n\n\t} while (1);\n}\n\n/*\n==================\nSCR_ModalMessage\n\nDisplays a text string in the center of the screen and waits for a Y or N\nkeypress.  \n==================\n*/\nint SCR_ModalMessage (char *text)\n{\n\tif (cls.state == ca_dedicated)\n\t\treturn true;\n\n\tscr_notifystring = text;\n \n// draw a fresh screen\n\tscr_fullupdate = 0;\n\tscr_drawdialog = true;\n\tSCR_UpdateScreen ();\n\tscr_drawdialog = false;\n\t\n\tS_ClearBuffer ();\t\t// so dma doesn't loop current sound\n\n\tdo\n\t{\n\t\tkey_count = -1;\t\t// wait for a key down and up\n\t\tSys_SendKeyEvents ();\n\t} while (key_lastpress != 'y' && key_lastpress != 'n' && key_lastpress != K_ESCAPE);\n\n\tscr_fullupdate = 0;\n\tSCR_UpdateScreen ();\n\n\treturn key_lastpress == 'y';\n}\n\n\n//=============================================================================\n\n/*\n===============\nSCR_BringDownConsole\n\nBrings the console down and fades the palettes back to normal\n================\n*/\nvoid SCR_BringDownConsole (void)\n{\n\tint\t\ti;\n\t\n\tscr_centertime_off = 0;\n\t\n\tfor (i=0 ; i<20 && scr_conlines != scr_con_current ; i++)\n\t\tSCR_UpdateScreen ();\n\n\tcl.cshifts[0].percent = 0;\t\t// no area contents palette on next frame\n\tVID_SetPalette (host_basepal);\n}\n\nvoid SCR_TileClear (void)\n{\n\tif (r_refdef.vrect.x > 0) {\n\t\t// left\n\t\tDraw_TileClear (0, 0, r_refdef.vrect.x, vid.height - sb_lines);\n\t\t// right\n\t\tDraw_TileClear (r_refdef.vrect.x + r_refdef.vrect.width, 0, \n\t\t\tvid.width - r_refdef.vrect.x + r_refdef.vrect.width, \n\t\t\tvid.height - sb_lines);\n\t}\n\tif (r_refdef.vrect.y > 0) {\n\t\t// top\n\t\tDraw_TileClear (r_refdef.vrect.x, 0, \n\t\t\tr_refdef.vrect.x + r_refdef.vrect.width, \n\t\t\tr_refdef.vrect.y);\n\t\t// bottom\n\t\tDraw_TileClear (r_refdef.vrect.x,\n\t\t\tr_refdef.vrect.y + r_refdef.vrect.height, \n\t\t\tr_refdef.vrect.width, \n\t\t\tvid.height - sb_lines - \n\t\t\t(r_refdef.vrect.height + r_refdef.vrect.y));\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\nWARNING: be very careful calling this from elsewhere, because the refresh\nneeds almost the entire 256k of stack space!\n==================\n*/\nvoid SCR_UpdateScreen (void)\n{\n\tvrect_t\t\tvrect;\n\n\tif (block_drawing)\n\t\treturn;\n\n\tvid.numpages = (int)(2 + gl_triplebuffer.value);\n\n\tscr_copytop = 0;\n\tscr_copyeverything = 0;\n\n\tif (scr_disabled_for_loading)\n\t{\n\t\tif (realtime - scr_disabled_time > 60)\n\t\t{\n\t\t\tscr_disabled_for_loading = false;\n\t\t\tCon_Printf (\"load failed.\\n\");\n\t\t}\n\t\telse\n\t\t\treturn;\n\t}\n\n\tif (!scr_initialized || !con_initialized)\n\t\treturn;\t\t\t\t// not initialized yet\n\n\n\tGL_BeginRendering (&glx, &gly, &glwidth, &glheight);\n\t\n\t//\n\t// determine size of refresh window\n\t//\n\tif (oldfov != fov.value)\n\t{\n\t\toldfov = fov.value;\n\t\tvid.recalc_refdef = true;\n\t}\n\n\tif (oldscreensize != viewsize.value)\n\t{\n\t\toldscreensize = viewsize.value;\n\t\tvid.recalc_refdef = true;\n\t}\n\t\n\tif (oldsbaralpha != scr_sbaralpha.value)\n\t{\n\t\toldsbaralpha = scr_sbaralpha.value;\n\t\tvid.recalc_refdef = true;\n\t}\n\n\tif (vid.recalc_refdef)\n\t\tSCR_CalcRefdef ();\n\n//\n// do 3D refresh drawing, and then update the screen\n//\n\tSCR_SetUpToDrawConsole ();\n\t\n\tV_RenderView ();\n\n\tGL_Set2D ();\n\n\t//\n\t// draw any areas not covered by the refresh\n\t//\n\tSCR_TileClear ();\n\n\tif (scr_drawdialog)\n\t{\n\t\tSbar_Draw ();\n\t\tDraw_FadeScreen ();\n\t\tSCR_DrawNotifyString ();\n\t\tscr_copyeverything = true;\n\t}\n\telse if (scr_drawloading)\n\t{\n\t\tSCR_DrawLoading ();\n\t\tSbar_Draw ();\n\t}\n\telse if (cl.intermission == 1 && key_dest == key_game)\n\t{\n\t\tSbar_IntermissionOverlay ();\n\t}\n\telse if (cl.intermission == 2 && key_dest == key_game)\n\t{\n\t\tSbar_FinaleOverlay ();\n\t\tSCR_CheckDrawCenterString ();\n\t}\n\telse\n\t{\n\t\tif (crosshair.value)\n\t\t\tDraw_Crosshair();\n\t\t\n\t\tSCR_DrawRam ();\n\t\tSCR_DrawNet ();\n\t\tSCR_DrawTurtle ();\n\t\tSCR_DrawPause ();\n\t\tSCR_CheckDrawCenterString ();\n\t\tSbar_Draw ();\n\t\tSCR_DrawConsole ();\t\n\t\tM_Draw ();\n\t}\n\n\tV_UpdatePalette ();\n\n\tGL_EndRendering ();\n}\n\n"
  },
  {
    "path": "source/gl_vidpsp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include <stdarg.h>\n#include <stdio.h>\n#include <vitasdk.h>\n#include <vitaGL.h>\n\n#include \"quakedef.h\"\n\nGLuint fb;\nint fb_tex = -1;\n\nfloat *gVertexBuffer;\nfloat *gColorBuffer;\nfloat *gTexCoordBuffer;\nfloat *gVertexBufferPtr;\nfloat *gColorBufferPtr;\nfloat *gTexCoordBufferPtr;\n\nextern uint8_t netcheck_dialog_running;\nextern cvar_t vid_vsync;\nextern bool benchmark;\nunsigned short\td_8to16table[256];\nunsigned\td_8to24table[256];\nunsigned char d_15to8table[65536];\nCVAR (show_fps, 0, CVAR_ARCHIVE)\nCVAR (gl_fog, 0, CVAR_ARCHIVE)\nextern int isKeyboard;\n\nint num_shades=32;\n\nint\td_con_indirect = 0;\n\nint\t\tsvgalib_inited=0;\nint\t\tUseMouse = 1;\nint\t\tUseKeyboard = 1;\n\nCVAR (vid_mode, 5, CVAR_NONE)\nCVAR (vid_redrawfull, 0, CVAR_NONE)\nCVAR (vid_waitforrefresh, 1, CVAR_ARCHIVE)\nCVAR (gl_outline, 0, CVAR_ARCHIVE)\nCVAR (gl_mipmap, 1, CVAR_ARCHIVE)\n\nint gl_ssaa = 1;\n\nextern cvar_t scr_conscale;\nextern cvar_t scr_conwidth;\n\nsigned char *framebuffer_ptr;\n\nint     mouse_buttons;\nint     mouse_buttonstate;\nint     mouse_oldbuttonstate;\nfloat   mouse_x, mouse_y;\nfloat\told_mouse_x, old_mouse_y;\nint\t\tmx, my;\n\nint scr_width = 1280, scr_height = 720;\n\n/*-----------------------------------------------------------------------*/\n\nint\t\ttexture_mode = GL_LINEAR;\n\nint\t\ttexture_extension_number = 1;\n\nfloat\t\tgldepthmin, gldepthmax;\n\nconst char *gl_vendor;\nconst char *gl_renderer;\nconst char *gl_version;\nconst char *gl_extensions;\n\nstatic float vid_gamma = 1.0;\n\nbool isPermedia = false;\n\nfloat sintablef[17] = {\n\t 0.000000f, 0.382683f, 0.707107f,\n\t 0.923879f, 1.000000f, 0.923879f,\n\t 0.707107f, 0.382683f, 0.000000f,\n\t-0.382683f,-0.707107f,-0.923879f,\n\t-1.000000f,-0.923879f,-0.707107f,\n\t-0.382683f, 0.000000f\n};\n\t\nfloat costablef[17] = {\n\t 1.000000f, 0.923879f, 0.707107f,\n\t 0.382683f, 0.000000f,-0.382683f,\n\t-0.707107f,-0.923879f,-1.000000f,\n\t-0.923879f,-0.707107f,-0.382683f,\n\t 0.000000f, 0.382683f, 0.707107f,\n\t 0.923879f, 1.000000f\n};\n\n/*-----------------------------------------------------------------------*/\nvoid D_BeginDirectRect (int x, int y, byte *pbitmap, int width, int height)\n{\n}\n\nvoid D_EndDirectRect (int x, int y, int width, int height)\n{\n}\n\nvoid VID_Shutdown(void)\n{\n}\n\nvoid VID_ShiftPalette(unsigned char *p)\n{\n//\tVID_SetPalette(p);\n}\n\nvoid VID_ChangeRes(float scale){\n\t\n}\n\nvoid\tVID_SetPalette (unsigned char *palette)\n{\n\tbyte\t*pal;\n\tunsigned r,g,b;\n\tunsigned v;\n\tint     r1,g1,b1;\n\tint\t\tj,k,l,m;\n\tunsigned short i;\n\tunsigned\t*table;\n\tFILE *f;\n\tsigned char s[255];\n\tint dist, bestdist;\n\tstatic bool palflag = false;\n\n//\n// 8 8 8 encoding\n//\n\tpal = palette;\n\ttable = d_8to24table;\n\tfor (i=0 ; i<256 ; i++)\n\t{\n\t\tr = pal[0];\n\t\tg = pal[1];\n\t\tb = pal[2];\n\t\tpal += 3;\n\t\t\n\t\tv = (255<<24) + (r<<0) + (g<<8) + (b<<16);\n\t\t*table++ = v;\n\t\t\n\t}\n\td_8to24table[255] &= 0xffffff;\t// 255 is transparent\n\t\n\t// JACK: 3D distance calcs - k is last closest, l is the distance.\n\tfor (i=0; i < (1<<15); i++) {\n\t\t/* Maps\n\t\t000000000000000\n\t\t000000000011111 = Red  = 0x1F\n\t\t000001111100000 = Blue = 0x03E0\n\t\t111110000000000 = Grn  = 0x7C00\n\t\t*/\n\t\tr = ((i & 0x1F) << 3)+4;\n\t\tg = ((i & 0x03E0) >> 2)+4;\n\t\tb = ((i & 0x7C00) >> 7)+4;\n\t\tpal = (unsigned char *)d_8to24table;\n\t\tfor (v=0,k=0,bestdist=10000*10000; v<256; v++,pal+=4) {\n\t\t\tr1 = (int)r - (int)pal[0];\n\t\t\tg1 = (int)g - (int)pal[1];\n\t\t\tb1 = (int)b - (int)pal[2];\n\t\t\tdist = (r1*r1)+(g1*g1)+(b1*b1);\n\t\t\tif (dist < bestdist) {\n\t\t\t\tk=v;\n\t\t\t\tbestdist = dist;\n\t\t\t}\n\t\t}\n\t\td_15to8table[i]=k;\n\t}\n\t\n}\n\n#define NUM_FRAG_SHADERS (9)\n#define NUM_VERT_SHADERS (4)\n#define MAX_INDICES (32768)\nuint16_t* indices;\n\nGLuint fs[9];\nGLuint vs[4];\nGLuint programs[9];\n\nvoid* GL_LoadShader(const char* filename, GLuint idx, GLboolean fragment) {\n\tFILE* f = fopen(filename, \"rb\");\n\tfseek(f, 0, SEEK_END);\n\tlong int size = ftell(f);\n\tfseek(f, 0, SEEK_SET);\n\tvoid* res = malloc(size);\n\tfread(res, 1, size, f);\n\tfclose(f);\n\tif (fragment)\n\t\tvglShaderGxpBinary(1, &fs[idx], res, size);\n\telse\n\t\tvglShaderGxpBinary(1, &vs[idx], res, size);\n\tfree(res);\n}\n\nstatic int state_mask = 0;\nGLint monocolor;\nGLint modulcolor[2];\n\nvoid GL_SetProgram() {\n\tswitch (state_mask) {\n\t\tcase 0x00: // Everything off\n\t\tcase 0x04: // Modulate\n\t\tcase 0x08: // Alpha Test\n\t\tcase 0x0C: // Alpha Test + Modulate\n\t\t\tglUseProgram(programs[NO_COLOR]);\n\t\t\tbreak;\n\t\tcase 0x01: // Texcoord\n\t\tcase 0x03: // Texcoord + Color\n\t\t\tglUseProgram(programs[TEX2D_REPL]);\n\t\t\tbreak;\n\t\tcase 0x02: // Color\n\t\tcase 0x06: // Color + Modulate\n\t\t\tglUseProgram(programs[RGBA_COLOR]);\n\t\t\tbreak;\n\t\tcase 0x05: // Modulate + Texcoord\n\t\t\tglUseProgram(programs[TEX2D_MODUL]);\n\t\t\tbreak;\n\t\tcase 0x07: // Modulate + Texcoord + Color\n\t\t\tglUseProgram(programs[TEX2D_MODUL_CLR]);\n\t\t\tbreak;\n\t\tcase 0x09: // Alpha Test + Texcoord\n\t\tcase 0x0B: // Alpha Test + Color + Texcoord\n\t\t\tglUseProgram(programs[TEX2D_REPL_A]);\n\t\t\tbreak;\n\t\tcase 0x0A: // Alpha Test + Color\n\t\tcase 0x0E: // Alpha Test + Modulate + Color\n\t\t\tglUseProgram(programs[RGBA_CLR_A]);\n\t\t\tbreak;\n\t\tcase 0x0D: // Alpha Test + Modulate + Texcoord\n\t\t\tglUseProgram(programs[TEX2D_MODUL_A]);\n\t\t\tbreak;\n\t\tcase 0x0F: // Alpha Test + Modulate + Texcood + Color\n\t\t\tglUseProgram(programs[FULL_A]);\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n}\n\nvoid GL_EnableState(GLenum state) {\t\n\tswitch (state) {\n\t\tcase GL_TEXTURE_COORD_ARRAY:\n\t\t\tstate_mask |= 0x01;\n\t\t\tbreak;\n\t\tcase GL_COLOR_ARRAY:\n\t\t\tstate_mask |= 0x02;\n\t\t\tbreak;\n\t\tcase GL_MODULATE:\n\t\t\tstate_mask |= 0x04;\n\t\t\tbreak;\n\t\tcase GL_REPLACE:\n\t\t\tstate_mask &= ~0x04;\n\t\t\tbreak;\n\t\tcase GL_ALPHA_TEST:\n\t\t\tstate_mask |= 0x08;\n\t\t\tbreak;\n\t}\n\tGL_SetProgram();\n}\n\nvoid GL_DisableState(GLenum state) {\t\n\tswitch (state) {\n\t\tcase GL_TEXTURE_COORD_ARRAY:\n\t\t\tstate_mask &= ~0x01;\n\t\t\tbreak;\n\t\tcase GL_COLOR_ARRAY:\n\t\t\tstate_mask &= ~0x02;\n\t\t\tbreak;\n\t\tcase GL_ALPHA_TEST:\n\t\t\tstate_mask &= ~0x08;\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tbreak;\n\t}\n\tGL_SetProgram();\n}\n\nstatic float cur_clr[4];\n\nvoid GL_DrawPolygon(GLenum prim, int num) {\n\tif (num == 0)\n\t\treturn;\n\tif (state_mask == 0x05)\n\t\tglUniform4fv(modulcolor[0], 1, cur_clr);\n\telse if (state_mask == 0x0D)\n\t\tglUniform4fv(modulcolor[1], 1, cur_clr);\n\tvglDrawObjects(prim, num, GL_TRUE);\n}\n\nvoid GL_Color(float r, float g, float b, float a) {\n\tcur_clr[0] = r;\n\tcur_clr[1] = g;\n\tcur_clr[2] = b;\n\tcur_clr[3] = a;\n}\n\nbool shaders_set = false;\nvoid GL_ResetShaders() {\n\tglFinish();\n\tif (shaders_set) {\n\t\tfor (int i = 0; i < NUM_FRAG_SHADERS; i++) {\n\t\t\tglDeleteProgram(programs[i]);\n\t\t}\n\t\tfor (int i = 0; i < NUM_FRAG_SHADERS; i++) {\n\t\t\tglDeleteShader(fs[i]);\n\t\t}\n\t\tfor (int i = 0; i < NUM_VERT_SHADERS; i++) {\n\t\t\tglDeleteShader(vs[i]);\n\t\t}\n\t} else\n\t\tshaders_set = true; \n\t\n\t// Loading shaders\n\tfor (int i = 0; i < NUM_FRAG_SHADERS; i++) {\n\t\tfs[i] = glCreateShader(GL_FRAGMENT_SHADER);\n\t}\n\tfor (int i = 0; i < NUM_VERT_SHADERS; i++) {\n\t\tvs[i] = glCreateShader(GL_VERTEX_SHADER);\n\t}\n\t\n\tif (gl_fog.value) {\n\t\tGL_LoadShader(\"app0:shaders/modulate_fog_f.gxp\", MODULATE, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_rgba_fog_f.gxp\", MODULATE_WITH_COLOR, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/replace_fog_f.gxp\", REPLACE, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_alpha_fog_f.gxp\", MODULATE_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_rgba_alpha_fog_f.gxp\", MODULATE_COLOR_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/replace_alpha_fog_f.gxp\", REPLACE_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/texture2d_fog_v.gxp\", TEXTURE2D, GL_FALSE);\n\t\tGL_LoadShader(\"app0:shaders/texture2d_rgba_fog_v.gxp\", TEXTURE2D_WITH_COLOR, GL_FALSE);\n\t} else {\n\t\tGL_LoadShader(\"app0:shaders/modulate_f.gxp\", MODULATE, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_rgba_f.gxp\", MODULATE_WITH_COLOR, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/replace_f.gxp\", REPLACE, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_alpha_f.gxp\", MODULATE_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/modulate_rgba_alpha_f.gxp\", MODULATE_COLOR_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/replace_alpha_f.gxp\", REPLACE_A, GL_TRUE);\n\t\tGL_LoadShader(\"app0:shaders/texture2d_v.gxp\", TEXTURE2D, GL_FALSE);\n\t\tGL_LoadShader(\"app0:shaders/texture2d_rgba_v.gxp\", TEXTURE2D_WITH_COLOR, GL_FALSE);\n\t}\n\t\n\tGL_LoadShader(\"app0:shaders/rgba_f.gxp\", RGBA_COLOR, GL_TRUE);\n\tGL_LoadShader(\"app0:shaders/vertex_f.gxp\", MONO_COLOR, GL_TRUE);\n\tGL_LoadShader(\"app0:shaders/rgba_alpha_f.gxp\", RGBA_A, GL_TRUE);\n\tGL_LoadShader(\"app0:shaders/rgba_v.gxp\", COLOR, GL_FALSE);\n\tGL_LoadShader(\"app0:shaders/vertex_v.gxp\", VERTEX_ONLY, GL_FALSE);\n\t\n\t// Setting up programs\n\tfor (int i = 0;i < NUM_FRAG_SHADERS; i++) {\n\t\tprograms[i] = glCreateProgram();\n\t\tswitch (i) {\n\t\t\tcase TEX2D_REPL:\n\t\t\t\tglAttachShader(programs[i], fs[REPLACE]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t\tcase TEX2D_MODUL:\n\t\t\t\tglAttachShader(programs[i], fs[MODULATE]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tmodulcolor[0] = glGetUniformLocation(programs[i], \"vColor\");\n\t\t\t\tbreak;\n\t\t\tcase TEX2D_MODUL_CLR:\n\t\t\t\tglAttachShader(programs[i], fs[MODULATE_WITH_COLOR]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D_WITH_COLOR]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 2, \"color\", 4, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t\tcase RGBA_COLOR:\n\t\t\t\tglAttachShader(programs[i], fs[RGBA_COLOR]);\n\t\t\t\tglAttachShader(programs[i], vs[COLOR]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"aPosition\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"aColor\", 4, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t\tcase NO_COLOR:\n\t\t\t\tglAttachShader(programs[i], fs[MONO_COLOR]);\n\t\t\t\tglAttachShader(programs[i], vs[VERTEX_ONLY]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"aPosition\", 3, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tmonocolor = glGetUniformLocation(programs[i], \"color\");\n\t\t\t\tbreak;\n\t\t\tcase TEX2D_REPL_A:\n\t\t\t\tglAttachShader(programs[i], fs[REPLACE_A]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t\tcase TEX2D_MODUL_A:\n\t\t\t\tglAttachShader(programs[i], fs[MODULATE_A]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tmodulcolor[1] = glGetUniformLocation(programs[i], \"vColor\");\n\t\t\t\tbreak;\n\t\t\tcase FULL_A:\n\t\t\t\tglAttachShader(programs[i], fs[MODULATE_COLOR_A]);\n\t\t\t\tglAttachShader(programs[i], vs[TEXTURE2D_WITH_COLOR]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"position\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"texcoord\", 2, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 2, \"color\", 4, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t\tcase RGBA_CLR_A:\n\t\t\t\tglAttachShader(programs[i], fs[RGBA_A]);\n\t\t\t\tglAttachShader(programs[i], vs[COLOR]);\n\t\t\t\tvglBindAttribLocation(programs[i], 0, \"aPosition\", 3, GL_FLOAT);\n\t\t\t\tvglBindAttribLocation(programs[i], 1, \"aColor\", 4, GL_FLOAT);\n\t\t\t\tglLinkProgram(programs[i]);\n\t\t\t\tbreak;\n\t\t}\n\t\tGLint tex = glGetUniformLocation(programs[i], \"tex\");\n\t\tif (tex != -1)\n\t\t\tglUniform1i(tex, 0);\n\t}\n}\n\nstatic void Callback_Fog_f(cvar_t *var)\n{\n\tif (gl_fog.value) \n\t\tCvar_SetValue(\"r_fullbright\", 1);\n\telse\n\t\tCvar_SetValue(\"r_fullbright\", 0);\n\n\tGL_ResetShaders();\n}\n\n/*\n===============\nGL_Init\n===============\n*/\nvoid GL_Init (void)\n{\n\tgl_vendor = glGetString (GL_VENDOR);\n\tCon_Printf (\"GL_VENDOR: %s\\n\", gl_vendor);\n\tgl_renderer = glGetString (GL_RENDERER);\n\tCon_Printf (\"GL_RENDERER: %s\\n\", gl_renderer);\n\n\tgl_version = glGetString (GL_VERSION);\n\tCon_Printf (\"GL_VERSION: %s\\n\", gl_version);\n\tgl_extensions = glGetString (GL_EXTENSIONS);\n\tCon_Printf (\"GL_EXTENSIONS: %s\\n\", gl_extensions);\n\n\tglClearColor (1,0,0,0);\n\tglCullFace(GL_FRONT);\n\n\tCvar_RegisterVariable (&gl_fog);\n\tCvar_SetCallback(&gl_fog, &Callback_Fog_f);\n\tGL_ResetShaders();\n\t\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);\n\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);\n\n\tglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n\t\n\tGL_EnableState(GL_ALPHA_TEST);\n\tGL_EnableState(GL_TEXTURE_COORD_ARRAY);\n\t\n\tglPolygonOffset(1, 14);\n\t\n\tCvar_RegisterVariable (&show_fps); // muff\n\tCvar_RegisterVariable(&vid_vsync);\n\t\n\tindices = (uint16_t*)malloc(sizeof(uint16_t)*MAX_INDICES);\n\tfor (int i = 0; i < MAX_INDICES; i++) {\n\t\tindices[i] = i;\n\t}\n\tgVertexBufferPtr = (float*)malloc(0x400000);\n\tgColorBufferPtr = (float*)malloc(0x200000);\n\tgTexCoordBufferPtr = (float*)malloc(0x200000);\n}\n\n/*\n=================\nGL_BeginRendering\n\n=================\n*/\nvoid GL_BeginRendering (int *x, int *y, int *width, int *height)\n{\n\t*x = *y = 0;\n\t*width = scr_width;\n\t*height = scr_height;\n\tif (gl_ssaa > 1) {\n\t\tif (fb_tex == -1) {\n\t\t\tvoid *buffer = malloc(vid.width * vid.height * 4);\n\t\t\tmemset(buffer, 0xFF, vid.width * vid.height * 4);\n\t\t\tfb_tex = GL_LoadTexture32 (\"***framebuffer***\", scr_width, scr_height, buffer, false, false, false);\n\t\t\tglTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, scr_width, scr_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);\n\t\t\tfree(buffer);\n\t\t\tglBindTexture(GL_TEXTURE_2D, fb_tex);\n\t\t\tglEnable(GL_TEXTURE_2D);\n\t\t\tglGenFramebuffers(1, &fb);\n\t\t\tglBindFramebuffer(GL_FRAMEBUFFER, fb);\n\t\t\tglFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, fb_tex, 0);\n\t\t} else\n\t\t\tglBindFramebuffer(GL_FRAMEBUFFER, fb);\n\t}\n\tvglIndexPointerMapped(indices);\n\tgVertexBuffer = gVertexBufferPtr;\n\tgColorBuffer = gColorBufferPtr;\n\tgTexCoordBuffer = gTexCoordBufferPtr;\n}\n\nvoid GL_EndRendering (void)\n{\n\tif (benchmark)\n\t\tGL_DrawBenchmark ();\n\telse\n\t\tGL_DrawFPS ();\n\t\n\tvglSwapBuffers(isKeyboard || netcheck_dialog_running);\n\tGL_SetCanvas(CANVAS_DEFAULT);\n\n\tif (gl_ssaa > 1) {\n\t\tglBindFramebuffer(GL_FRAMEBUFFER, 0);\n\t\tglMatrixMode(GL_PROJECTION);\n\t\tglLoadIdentity();\n\t\tglOrtho(0, 960, 544, 0, -1, 1);\n\t\tglMatrixMode(GL_MODELVIEW);\n\t\tglLoadIdentity();\n\t\tglBindTexture(GL_TEXTURE_2D, fb_tex);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\t\tglTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\t\tglClear(GL_COLOR_BUFFER_BIT);\n\t\tglBegin(GL_QUADS);\n\t\tglTexCoord2i(0, 0);\n\t\tglVertex3f(0, 0, 0);\n\t\tglTexCoord2i(1, 0);\n\t\tglVertex3f(960, 0, 0);\n\t\tglTexCoord2i(1, 1);\n\t\tglVertex3f(960, 544, 0);\n\t\tglTexCoord2i(0, 1);\n\t\tglVertex3f(0, 544, 0);\n\t\tglEnd();\n\t}\n}\n\nstatic void Check_Gamma (unsigned char *pal)\n{\n\tfloat\tf, inf;\n\tunsigned char\tpalette[768];\n\tint\t\ti;\n\n\tif ((i = COM_CheckParm(\"-gamma\")) == 0) {\n\t\tvid_gamma = 0.7; // default to 0.7 on non-3dfx hardware\n\t} else\n\t\tvid_gamma = atof(com_argv[i+1]);\n\n\tfor (i=0 ; i<768 ; i++)\n\t{\n\t\tf = pow ( (pal[i]+1)/256.0 , vid_gamma );\n\t\tinf = f*255 + 0.5;\n\t\tif (inf < 0)\n\t\t\tinf = 0;\n\t\tif (inf > 255)\n\t\t\tinf = 255;\n\t\tpalette[i] = inf;\n\t}\n\n\tmemcpy (pal, palette, sizeof(palette));\n}\n\nvoid VID_Init(unsigned char *palette)\n{\n\tint i;\n\tint width = scr_width, height = scr_height;\n\t\n\tCvar_RegisterVariable (&vid_mode);\n\tCvar_RegisterVariable (&vid_redrawfull);\n\tCvar_RegisterVariable (&vid_waitforrefresh);\n\tCvar_RegisterVariable (&gl_outline);\n\tCvar_RegisterVariable (&gl_mipmap);\n\t\n\tvid.maxwarpwidth = width;\n\tvid.maxwarpheight = height;\n\tvid.colormap = host_colormap;\n\tvid.fullbright = 0xFFFF;\n\tvid.aspect = (float) width / (float) height;\n\tvid.numpages = 2;\n\tvid.rowbytes = 2 * width;\n\tvid.width = width * gl_ssaa;\n\tvid.height = height * gl_ssaa;\n\n\tvid.conwidth = (scr_conwidth.value > 0) ? (int)scr_conwidth.value : (scr_conscale.value > 0) ? (int)(vid.width/scr_conscale.value) : vid.width;\n\tvid.conwidth = Q_CLAMP (320, vid.conwidth, vid.width);\n\tvid.conwidth &= 0xFFFFFFF8;\n\tvid.conheight = vid.conwidth * vid.height / vid.width;\n\t\n\tGL_Init();\n\n\tCheck_Gamma(palette);\n\tVID_SetPalette(palette);\n\n\tCon_SafePrintf (\"Video mode %dx%d initialized.\\n\", width, height);\n\n\tvid.recalc_refdef = 1;\t\t\t\t// force a surface cache flush\n}\n\nvoid Force_CenterView_f (void)\n{\n\tcl.viewangles[PITCH] = 0;\n}"
  },
  {
    "path": "source/gl_warp.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// gl_warp.c -- sky and water polygons\n\n#include \"quakedef.h\"\n\nextern\tmodel_t\t*loadmodel;\nextern cvar_t gl_compress;\n\n//int\t\tskytexturenum;\n\nint\t\tsolidskytexture;\nint\t\talphaskytexture;\nfloat\tspeedscale;\t\t// for top sky and bottom sky\n\nmsurface_t\t*warpface;\n\nextern cvar_t gl_subdivide_size;\n\nvoid BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)\n{\n\tint\t\ti, j;\n\tfloat\t*v;\n\n\tmins[0] = mins[1] = mins[2] = 9999;\n\tmaxs[0] = maxs[1] = maxs[2] = -9999;\n\tv = verts;\n\tfor (i=0 ; i<numverts ; i++)\n\t\tfor (j=0 ; j<3 ; j++, v++)\n\t\t{\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}\n\nvoid SubdividePolygon (int numverts, float *verts)\n{\n\tint\t\ti, j, k;\n\tvec3_t\tmins, maxs;\n\tfloat\tm;\n\tfloat\t*v;\n\tvec3_t\tfront[64], back[64];\n\tint\t\tf, b;\n\tfloat\tdist[64];\n\tfloat\tfrac;\n\tglpoly_t\t*poly;\n\tfloat\ts, t;\n\n\tif (numverts > 60)\n\t\tSys_Error (\"numverts = %i\", numverts);\n\n\tBoundPoly (numverts, verts, mins, maxs);\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tm = (mins[i] + maxs[i]) * 0.5;\n\t\tm = gl_subdivide_size.value * floor (m/gl_subdivide_size.value + 0.5);\n\t\tif (maxs[i] - m < 8)\n\t\t\tcontinue;\n\t\tif (m - mins[i] < 8)\n\t\t\tcontinue;\n\n\t\t// cut it\n\t\tv = verts + i;\n\t\tfor (j=0 ; j<numverts ; j++, v+= 3)\n\t\t\tdist[j] = *v - m;\n\n\t\t// wrap cases\n\t\tdist[j] = dist[0];\n\t\tv-=i;\n\t\tVectorCopy (verts, v);\n\n\t\tf = b = 0;\n\t\tv = verts;\n\t\tfor (j=0 ; j<numverts ; j++, v+= 3)\n\t\t{\n\t\t\tif (dist[j] >= 0)\n\t\t\t{\n\t\t\t\tVectorCopy (v, front[f]);\n\t\t\t\tf++;\n\t\t\t}\n\t\t\tif (dist[j] <= 0)\n\t\t\t{\n\t\t\t\tVectorCopy (v, back[b]);\n\t\t\t\tb++;\n\t\t\t}\n\t\t\tif (dist[j] == 0 || dist[j+1] == 0)\n\t\t\t\tcontinue;\n\t\t\tif ( (dist[j] > 0) != (dist[j+1] > 0) )\n\t\t\t{\n\t\t\t\t// clip point\n\t\t\t\tfrac = dist[j] / (dist[j] - dist[j+1]);\n\t\t\t\tfor (k=0 ; k<3 ; k++)\n\t\t\t\t\tfront[f][k] = back[b][k] = v[k] + frac*(v[3+k] - v[k]);\n\t\t\t\tf++;\n\t\t\t\tb++;\n\t\t\t}\n\t\t}\n\n\t\tSubdividePolygon (f, front[0]);\n\t\tSubdividePolygon (b, back[0]);\n\t\treturn;\n\t}\n\n\tpoly = Hunk_Alloc (sizeof(glpoly_t) + (numverts-4) * VERTEXSIZE*sizeof(float));\n\tpoly->next = warpface->polys;\n\twarpface->polys = poly;\n\tpoly->numverts = numverts;\n\tfor (i=0 ; i<numverts ; i++, verts+= 3)\n\t{\n\t\tVectorCopy (verts, poly->verts[i]);\n\t\ts = DotProduct (verts, warpface->texinfo->vecs[0]);\n\t\tt = DotProduct (verts, warpface->texinfo->vecs[1]);\n\t\tpoly->verts[i][3] = s;\n\t\tpoly->verts[i][4] = t;\n\t}\n}\n\n/*\n================\nGL_SubdivideSurface\n\nBreaks a polygon up along axial 64 unit\nboundaries so that turbulent and sky warps\ncan be done reasonably.\n================\n*/\nvoid GL_SubdivideSurface (msurface_t *fa)\n{\n\tvec3_t\t\tverts[64];\n\tint\t\t\tnumverts;\n\tint\t\t\ti;\n\tint\t\t\tlindex;\n\tfloat\t\t*vec;\n\ttexture_t\t*t;\n\n\twarpface = fa;\n\n\t//\n\t// convert edges back to a normal polygon\n\t//\n\tnumverts = 0;\n\tfor (i=0 ; i<fa->numedges ; i++)\n\t{\n\t\tlindex = loadmodel->surfedges[fa->firstedge + i];\n\n\t\tif (lindex > 0)\n\t\t\tvec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;\n\t\telse\n\t\t\tvec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;\n\t\tVectorCopy (vec, verts[numverts]);\n\t\tnumverts++;\n\t}\n\n\tSubdividePolygon (numverts, verts[0]);\n}\n\n//=========================================================\n\n\n\n// speed up sin calculations - Ed\nfloat\tturbsin[] =\n{\n\t#include \"gl_warp_sin.h\"\n};\n#define TURBSCALE (256.0 / (2 * M_PI))\n\n/*\n=============\nEmitWaterPolys\n\nDoes a water warp on the pre-fragmented glpoly_t chain\n=============\n*/\nvoid EmitWaterPolys (msurface_t *fa)\n{\n\tglpoly_t\t*p;\n\tfloat\t\t*v;\n\tint\t\t\ti;\n\tfloat\t\ts, t, os, ot;\n\n\n\tfor (p=fa->polys ; p ; p=p->next)\n\t{\n\t\tfloat *pUV = gTexCoordBuffer;\n\t\tfloat *pPoint = gVertexBuffer;\n\t\tfor (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)\n\t\t{\n\t\t\tos = v[3];\n\t\t\tot = v[4];\n\t\t\ts = os + turbsin[(int)((ot*0.125+realtime) * TURBSCALE) & 255];\n\t\t\ts *= (0.015625f);\n\t\t\tt = ot + turbsin[(int)((os*0.125+realtime) * TURBSCALE) & 255];\n\t\t\tt *= (0.015625f);\n\t\t\t*gTexCoordBuffer++ = s;\n\t\t\t*gTexCoordBuffer++ = t;\n\t\t\tmemcpy(gVertexBuffer, &v[0], sizeof(vec3_t));\n\t\t\tgVertexBuffer += 3;\n\t\t}\n\t\tvglVertexAttribPointerMapped(0, pPoint);\n\t\tvglVertexAttribPointerMapped(1, pUV);\n\t\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n\t}\n}\n\n\n\n\n/*\n=============\nEmitSkyPolys\n=============\n*/\nvoid EmitSkyPolys (msurface_t *fa)\n{\n\tglpoly_t\t*p;\n\tfloat\t\t*v;\n\tint\t\t\ti;\n\tfloat\ts, t;\n\tvec3_t\tdir;\n\tfloat\tlength;\n\n\tfor (p=fa->polys ; p ; p=p->next)\n\t{\n\t\tfloat *pUV = gTexCoordBuffer;\n\t\tfloat *pPoint = gVertexBuffer;\n\t\tfor (i=0,v=p->verts[0] ; i<p->numverts ; i++, v+=VERTEXSIZE)\n\t\t{\n\t\t\tVectorSubtract (v, r_origin, dir);\n\t\t\tdir[2] *= 3;    // flatten the sphere\n\t\t\tlength = dir[0]*dir[0] + dir[1]*dir[1] + dir[2]*dir[2];\n\t\t\tlength = sqrt (length);\n\t\t\tlength = 378/length;\n\t\t\tdir[0] *= length;\n\t\t\tdir[1] *= length;\n\t\t\ts = (speedscale + dir[0]) * (0.0078125f);\n\t\t\tt = (speedscale + dir[1]) * (0.0078125f);\n\t\t\t*gTexCoordBuffer++ = s;\n\t\t\t*gTexCoordBuffer++ = t;\n\t\t\tmemcpy(gVertexBuffer, &v[0], sizeof(vec3_t));\n\t\t\tgVertexBuffer += 3;\n\t\t}\n\t\tvglVertexAttribPointerMapped(0, pPoint);\n\t\tvglVertexAttribPointerMapped(1, pUV);\n\t\tGL_DrawPolygon(GL_TRIANGLE_FAN, p->numverts);\n\t}\n}\n\n/*\n===============\nEmitBothSkyLayers\n\nDoes a sky warp on the pre-fragmented glpoly_t chain\nThis will be called for brushmodels, the world\nwill have them chained together.\n===============\n*/\nvoid EmitBothSkyLayers (msurface_t *fa)\n{\n\tint\t\t\ti;\n\tint\t\t\tlindex;\n\tfloat\t\t*vec;\n\n\tGL_Bind (solidskytexture);\n\tspeedscale = realtime*8;\n\tspeedscale -= (int)speedscale & ~127 ;\n\n\tEmitSkyPolys (fa);\n\n\tglEnable (GL_BLEND);\n\tGL_Bind (alphaskytexture);\n\tspeedscale = realtime*16;\n\tspeedscale -= (int)speedscale & ~127 ;\n\n\tEmitSkyPolys (fa);\n\n\tglDisable (GL_BLEND);\n}\n\n#ifndef QUAKE2\n/*\n=================\nR_DrawSkyChain\n=================\n*/\nvoid R_DrawSkyChain (msurface_t *s)\n{\n\tmsurface_t\t*fa;\n\n\t// used when gl_texsort is on\n\tGL_Bind(solidskytexture);\n\tspeedscale = realtime*8;\n\tspeedscale -= (int)speedscale & ~127 ;\n\n\tfor (fa=s ; fa ; fa=fa->texturechain)\n\t\tEmitSkyPolys (fa);\n\n\tglEnable (GL_BLEND);\n\tGL_Bind (alphaskytexture);\n\tspeedscale = realtime*16;\n\tspeedscale -= (int)speedscale & ~127 ;\n\n\tfor (fa=s ; fa ; fa=fa->texturechain)\n\t\tEmitSkyPolys (fa);\n\n\tglDisable (GL_BLEND);\n}\n\n#endif\n\n//===============================================================\n\n/*\n=============\nR_InitSky\n\nA sky texture is 256*128, with the right side being a masked overlay\n==============\n*/\nvoid R_InitSky (miptex_t *mt)\n{\n\tint\t\t\ti, j, p;\n\tbyte\t\t*src;\n\tunsigned\ttrans[16384];\n\tunsigned\ttranspix;\n\tint\t\t\tr, g, b;\n\tunsigned\t*rgba;\n\t\n\tsrc = (byte *)mt + mt->offsets[0];\n\n\t// make an average value for the back to avoid\n\t// a fringe on the top level\n\n\tr = g = b = 0;\n\tfor (i=0 ; i<128 ; i++)\n\t\tfor (j=0 ; j<128 ; j++)\n\t\t{\n\t\t\tp = src[i*256 + j + 128];\n\t\t\trgba = &d_8to24table[p];\n\t\t\ttrans[(i*128) + j] = *rgba;\n\t\t\tr += ((byte *)rgba)[0];\n\t\t\tg += ((byte *)rgba)[1];\n\t\t\tb += ((byte *)rgba)[2];\n\t\t}\n\n\t((byte *)&transpix)[0] = r/(16384);\n\t((byte *)&transpix)[1] = g/(16384);\n\t((byte *)&transpix)[2] = b/(16384);\n\t((byte *)&transpix)[3] = 0;\n\n\n\tif (!solidskytexture)\n\t\tsolidskytexture = texture_extension_number++;\n\tGL_Bind (solidskytexture );\n\t\n\tglTexImage2D (GL_TEXTURE_2D, 0, gl_compress.value ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : gl_solid_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n\n\n\tfor (i=0 ; i<128 ; i++)\n\t\tfor (j=0 ; j<128 ; j++)\n\t\t{\n\t\t\tp = src[i*256 + j];\n\t\t\tif (p == 0)\n\t\t\t\ttrans[(i*128) + j] = transpix;\n\t\t\telse\n\t\t\t\ttrans[(i*128) + j] = d_8to24table[p];\n\t\t}\n\n\tif (!alphaskytexture)\n\t\talphaskytexture = texture_extension_number++;\n\tGL_Bind(alphaskytexture);\n\t\n\tglTexImage2D (GL_TEXTURE_2D, 0, gl_compress.value ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : gl_alpha_format, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, trans);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);\n\tglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);\n}"
  },
  {
    "path": "source/gl_warp_sin.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n 0, 0.19633, 0.392541, 0.588517, 0.784137, 0.979285, 1.17384, 1.3677,\n 1.56072, 1.75281, 1.94384, 2.1337, 2.32228, 2.50945, 2.69512, 2.87916,\n 3.06147, 3.24193, 3.42044, 3.59689, 3.77117, 3.94319, 4.11282, 4.27998,\n 4.44456, 4.60647, 4.76559, 4.92185, 5.07515, 5.22538, 5.37247, 5.51632,\n 5.65685, 5.79398, 5.92761, 6.05767, 6.18408, 6.30677, 6.42566, 6.54068,\n 6.65176, 6.75883, 6.86183, 6.9607, 7.05537, 7.14579, 7.23191, 7.31368,\n 7.39104, 7.46394, 7.53235, 7.59623, 7.65552, 7.71021, 7.76025, 7.80562,\n 7.84628, 7.88222, 7.91341, 7.93984, 7.96148, 7.97832, 7.99036, 7.99759,\n 8, 7.99759, 7.99036, 7.97832, 7.96148, 7.93984, 7.91341, 7.88222,\n 7.84628, 7.80562, 7.76025, 7.71021, 7.65552, 7.59623, 7.53235, 7.46394,\n 7.39104, 7.31368, 7.23191, 7.14579, 7.05537, 6.9607, 6.86183, 6.75883,\n 6.65176, 6.54068, 6.42566, 6.30677, 6.18408, 6.05767, 5.92761, 5.79398,\n 5.65685, 5.51632, 5.37247, 5.22538, 5.07515, 4.92185, 4.76559, 4.60647,\n 4.44456, 4.27998, 4.11282, 3.94319, 3.77117, 3.59689, 3.42044, 3.24193,\n 3.06147, 2.87916, 2.69512, 2.50945, 2.32228, 2.1337, 1.94384, 1.75281,\n 1.56072, 1.3677, 1.17384, 0.979285, 0.784137, 0.588517, 0.392541, 0.19633,\n 9.79717e-16, -0.19633, -0.392541, -0.588517, -0.784137, -0.979285, -1.17384, -1.3677,\n -1.56072, -1.75281, -1.94384, -2.1337, -2.32228, -2.50945, -2.69512, -2.87916,\n -3.06147, -3.24193, -3.42044, -3.59689, -3.77117, -3.94319, -4.11282, -4.27998,\n -4.44456, -4.60647, -4.76559, -4.92185, -5.07515, -5.22538, -5.37247, -5.51632,\n -5.65685, -5.79398, -5.92761, -6.05767, -6.18408, -6.30677, -6.42566, -6.54068,\n -6.65176, -6.75883, -6.86183, -6.9607, -7.05537, -7.14579, -7.23191, -7.31368,\n -7.39104, -7.46394, -7.53235, -7.59623, -7.65552, -7.71021, -7.76025, -7.80562,\n -7.84628, -7.88222, -7.91341, -7.93984, -7.96148, -7.97832, -7.99036, -7.99759,\n -8, -7.99759, -7.99036, -7.97832, -7.96148, -7.93984, -7.91341, -7.88222,\n -7.84628, -7.80562, -7.76025, -7.71021, -7.65552, -7.59623, -7.53235, -7.46394,\n -7.39104, -7.31368, -7.23191, -7.14579, -7.05537, -6.9607, -6.86183, -6.75883,\n -6.65176, -6.54068, -6.42566, -6.30677, -6.18408, -6.05767, -5.92761, -5.79398,\n -5.65685, -5.51632, -5.37247, -5.22538, -5.07515, -4.92185, -4.76559, -4.60647,\n -4.44456, -4.27998, -4.11282, -3.94319, -3.77117, -3.59689, -3.42044, -3.24193,\n -3.06147, -2.87916, -2.69512, -2.50945, -2.32228, -2.1337, -1.94384, -1.75281,\n -1.56072, -1.3677, -1.17384, -0.979285, -0.784137, -0.588517, -0.392541, -0.19633,\n"
  },
  {
    "path": "source/glquake.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// disable data conversion warnings\n\n#pragma warning(disable : 4244)     // MIPS\n#pragma warning(disable : 4136)     // X86\n#pragma warning(disable : 4051)     // ALPHA\n  \n#ifdef _WIN32\n#include <windows.h>\n#endif\n\n#include <vitaGL.h>\n\nvoid GL_BeginRendering (int *x, int *y, int *width, int *height);\nvoid GL_EndRendering (void);\n\n\n#ifdef _WIN32\n// Function prototypes for the Texture Object Extension routines\ntypedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,\n                    const GLboolean *);\ntypedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);\ntypedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);\ntypedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);\ntypedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);\ntypedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,\n                    const GLclampf *);\ntypedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);\n\nextern\tBINDTEXFUNCPTR bindTexFunc;\nextern\tDELTEXFUNCPTR delTexFunc;\nextern\tTEXSUBIMAGEPTR TexSubImage2DFunc;\n#endif\n\nextern\tint texture_extension_number;\nextern\tint\t\ttexture_mode;\n\nextern\tfloat\tgldepthmin, gldepthmax;\n\nvoid GL_Upload32 (unsigned *data, int width, int height,  bool mipmap, bool alpha);\nvoid GL_Upload8 (byte *data, int width, int height,  bool mipmap, bool alpha);\nint GL_LoadTexture (const char *identifier, int width, int height, byte *data, bool mipmap, bool alpha);\nint GL_LoadTexture32 (const char *identifier, int width, int height, byte *data, bool mipmap, bool alpha, bool fullbright);\n\ntypedef struct\n{\n\tfloat\tx, y, z;\n\tfloat\ts, t;\n\tfloat\tr, g, b;\n} glvert_t;\n\nextern glvert_t glv;\n\nextern\tint glx, gly, glwidth, glheight;\n\n#ifdef _WIN32\nextern\tPROC glArrayElementEXT;\nextern\tPROC glColorPointerEXT;\nextern\tPROC glTexturePointerEXT;\nextern\tPROC glVertexPointerEXT;\n#endif\n\n// r_local.h -- private refresh defs\n\n#define ALIAS_BASE_SIZE_RATIO\t\t(1.0 / 11.0)\n\t\t\t\t\t// normalizing factor so player model works out to about\n\t\t\t\t\t//  1 pixel per triangle\n#define\tMAX_LBM_HEIGHT\t\t480\n\n#define TILE_SIZE\t\t128\t\t// size of textures generated by R_GenTiledSurf\n\n#define SKYSHIFT\t\t7\n#define\tSKYSIZE\t\t\t(1 << SKYSHIFT)\n#define SKYMASK\t\t\t(SKYSIZE - 1)\n\n#define BACKFACE_EPSILON\t0.01\n\n\nvoid R_TimeRefresh_f (void);\nvoid R_ReadPointFile_f (void);\ntexture_t *R_TextureAnimation (texture_t *base);\n\ntypedef struct surfcache_s\n{\n\tstruct surfcache_s\t*next;\n\tstruct surfcache_s \t**owner;\t\t// NULL is an empty chunk of memory\n\tint\t\t\t\t\tlightadj[MAXLIGHTMAPS]; // checked for strobe flush\n\tint\t\t\t\t\tdlight;\n\tint\t\t\t\t\tsize;\t\t// including header\n\tunsigned\t\t\twidth;\n\tunsigned\t\t\theight;\t\t// DEBUG only needed for debug\n\tfloat\t\t\t\tmipscale;\n\tstruct texture_s\t*texture;\t// checked for animating textures\n\tbyte\t\t\t\tdata[4];\t// width*height elements\n} surfcache_t;\n\n\ntypedef struct\n{\n\tpixel_t\t\t*surfdat;\t// destination for generated surface\n\tint\t\t\trowbytes;\t// destination logical width in bytes\n\tmsurface_t\t*surf;\t\t// description for surface to generate\n\tfixed8_t\tlightadj[MAXLIGHTMAPS];\n\t\t\t\t\t\t\t// adjust for lightmap levels for dynamic lighting\n\ttexture_t\t*texture;\t// corrected for animating textures\n\tint\t\t\tsurfmip;\t// mipmapped ratio of surface texels / world pixels\n\tint\t\t\tsurfwidth;\t// in mipmapped texels\n\tint\t\t\tsurfheight;\t// in mipmapped texels\n} drawsurf_t;\n\n\ntypedef enum {\n\tpt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2\n} ptype_t;\n\n// !!! if this is changed, it must be changed in d_ifacea.h too !!!\ntypedef struct particle_s\n{\n// driver-usable fields\n\tvec3_t\t\torg;\n\tfloat\t\tcolor;\n// drivers never touch the following fields\n\tstruct particle_s\t*next;\n\tvec3_t\t\tvel;\n\tfloat\t\tramp;\n\tfloat\t\tdie;\n\tptype_t\t\ttype;\n} particle_t;\n\n\n//====================================================\n\n\nextern\tentity_t\tr_worldentity;\nextern\tbool\tr_cache_thrash;\t\t// compatability\nextern\tvec3_t\t\tmodelorg, r_entorigin;\nextern\tentity_t\t*currententity;\nextern\tint\t\t\tr_visframecount;\t// ??? what difs?\nextern\tint\t\t\tr_framecount;\nextern\tmplane_t\tfrustum[4];\nextern\tint\t\tc_brush_polys, c_alias_polys;\n\n\n//\n// view origin\n//\nextern\tvec3_t\tvup;\nextern\tvec3_t\tvpn;\nextern\tvec3_t\tvright;\nextern\tvec3_t\tr_origin;\n\n//\n// screen size info\n//\nextern\trefdef_t\tr_refdef;\nextern\tmleaf_t\t\t*r_viewleaf, *r_oldviewleaf;\nextern\ttexture_t\t*r_notexture_mip;\nextern\tint\t\td_lightstylevalue[256];\t// 8.8 fraction of base light value\n\nextern\tbool\tenvmap;\nextern\tint\tcurrenttexture;\nextern\tint\tcnttextures[2];\nextern\tint\tparticletexture;\nextern\tint\tplayertextures;\n\nextern\tint\tskytexturenum;\t\t// index in cl.loadmodel, not gl texture object\n\nextern\tcvar_t\tr_norefresh;\nextern\tcvar_t\tr_drawentities;\nextern\tcvar_t\tr_drawworld;\nextern\tcvar_t\tr_drawviewmodel;\nextern\tcvar_t\tr_speeds;\nextern\tcvar_t\tr_waterwarp;\nextern\tcvar_t\tr_fullbright;\nextern\tcvar_t\tr_lightmap;\nextern\tcvar_t\tr_shadows;\nextern\tcvar_t\tr_mirroralpha;\nextern\tcvar_t\tr_wateralpha;\nextern\tcvar_t\tr_dynamic;\nextern\tcvar_t\tr_novis;\n\nextern\tcvar_t\tgl_clear;\nextern\tcvar_t\tgl_cull;\nextern\tcvar_t\tgl_poly;\nextern\tcvar_t\tgl_texsort;\nextern\tcvar_t\tgl_smoothmodels;\nextern\tcvar_t\tgl_affinemodels;\nextern\tcvar_t\tgl_polyblend;\nextern\tcvar_t\tgl_keeptjunctions;\nextern\tcvar_t\tgl_reporttjunctions;\nextern\tcvar_t\tgl_flashblend;\nextern\tcvar_t\tgl_nocolors;\nextern\tcvar_t\tgl_doubleeyes;\nextern\tcvar_t\tgl_xflip;\nextern\tcvar_t\tgl_overbright;\n\nextern\tint\t\tgl_lightmap_format;\nextern\tint\t\tgl_solid_format;\nextern\tint\t\tgl_alpha_format;\n\nextern\tcvar_t\tgl_max_size;\nextern\tcvar_t\tgl_playermip;\n\nextern\tint\t\t\tmirrortexturenum;\t// quake texturenum, not gltexturenum\nextern\tbool\tmirror;\nextern\tmplane_t\t*mirror_plane;\n\nextern\tfloat\tr_world_matrix[16];\n\nextern\tconst char *gl_vendor;\nextern\tconst char *gl_renderer;\nextern\tconst char *gl_version;\nextern\tconst char *gl_extensions;\n\n// Stereo\nextern  cvar_t  st_separation;\nextern  cvar_t  st_zeropdist;\nextern  cvar_t  st_fustbal;\n//end stereo\n\nvoid R_TranslatePlayerSkin (int playernum);\nvoid GL_Bind (int texnum);\n\n#ifndef _WIN32\n#define APIENTRY /* */\n#endif\n\n// fenix@io.com: model interpolation\nextern  cvar_t  r_interpolate_model_animation;\nextern  cvar_t  r_interpolate_model_transform;\n\n#define ISTRANSPARENT(ent)   ((ent)->alpha > 0.0f && (ent)->alpha < 1.0f)\n"
  },
  {
    "path": "source/glquake2.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// disable data conversion warnings\n\n#pragma warning(disable : 4244)     // MIPS\n#pragma warning(disable : 4136)     // X86\n#pragma warning(disable : 4051)     // ALPHA\n  \n#include <windows.h>\n\n#include <vitaGL.h>\n\nvoid GL_BeginRendering (int *x, int *y, int *width, int *height);\nvoid GL_EndRendering (void);\n\n\n// Function prototypes for the Texture Object Extension routines\ntypedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *,\n                    const GLboolean *);\ntypedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint);\ntypedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *);\ntypedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *);\ntypedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint);\ntypedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *,\n                    const GLclampf *);\ntypedef void (APIENTRY *TEXSUBIMAGEPTR)(int, int, int, int, int, int, int, int, void *);\n\nextern\tBINDTEXFUNCPTR bindTexFunc;\nextern\tDELTEXFUNCPTR delTexFunc;\nextern\tTEXSUBIMAGEPTR TexSubImage2DFunc;\n\nextern\tint texture_extension_number;\nextern\tint\t\ttexture_mode;\n\nextern\tfloat\tgldepthmin, gldepthmax;\n\nvoid GL_Upload32 (unsigned *data, int width, int height,  bool mipmap, bool alpha, bool modulate);\nvoid GL_Upload8 (byte *data, int width, int height,  bool mipmap, bool alpha, bool modulate);\nint GL_LoadTexture (const char *identifier, int width, int height, byte *data, int mipmap, int alpha, int modulate);\n\ntypedef struct\n{\n\tfloat\tx, y, z;\n\tfloat\ts, t;\n\tfloat\tr, g, b;\n} glvert_t;\n\nextern glvert_t glv;\n\nextern\tint glx, gly, glwidth, glheight;\n\nextern\tPROC glArrayElementEXT;\nextern\tPROC glColorPointerEXT;\nextern\tPROC glTexturePointerEXT;\nextern\tPROC glVertexPointerEXT;\n\n\n// r_local.h -- private refresh defs\n\n#define MAXALIASVERTS\t\t2000\t// TODO: tune this\n\n#define ALIAS_BASE_SIZE_RATIO\t\t(1.0 / 11.0)\n\t\t\t\t\t// normalizing factor so player model works out to about\n\t\t\t\t\t//  1 pixel per triangle\n#define\tMAX_LBM_HEIGHT\t\t480\n\n#define TILE_SIZE\t\t128\t\t// size of textures generated by R_GenTiledSurf\n\n#define SKYSHIFT\t\t7\n#define\tSKYSIZE\t\t\t(1 << SKYSHIFT)\n#define SKYMASK\t\t\t(SKYSIZE - 1)\n\n#define BACKFACE_EPSILON\t0.01\n\n\nvoid R_TimeRefresh_f (void);\nvoid R_ReadPointFile_f (void);\ntexture_t *R_TextureAnimation (texture_t *base);\n\ntypedef struct surfcache_s\n{\n\tstruct surfcache_s\t*next;\n\tstruct surfcache_s \t**owner;\t\t// NULL is an empty chunk of memory\n\tint\t\t\t\t\tlightadj[MAXLIGHTMAPS]; // checked for strobe flush\n\tint\t\t\t\t\tdlight;\n\tint\t\t\t\t\tsize;\t\t// including header\n\tunsigned\t\t\twidth;\n\tunsigned\t\t\theight;\t\t// DEBUG only needed for debug\n\tfloat\t\t\t\tmipscale;\n\tstruct texture_s\t*texture;\t// checked for animating textures\n\tbyte\t\t\t\tdata[4];\t// width*height elements\n} surfcache_t;\n\n\ntypedef struct\n{\n\tpixel_t\t\t*surfdat;\t// destination for generated surface\n\tint\t\t\trowbytes;\t// destination logical width in bytes\n\tmsurface_t\t*surf;\t\t// description for surface to generate\n\tfixed8_t\tlightadj[MAXLIGHTMAPS];\n\t\t\t\t\t\t\t// adjust for lightmap levels for dynamic lighting\n\ttexture_t\t*texture;\t// corrected for animating textures\n\tint\t\t\tsurfmip;\t// mipmapped ratio of surface texels / world pixels\n\tint\t\t\tsurfwidth;\t// in mipmapped texels\n\tint\t\t\tsurfheight;\t// in mipmapped texels\n} drawsurf_t;\n\n\ntypedef enum {\n\tpt_static, pt_grav, pt_slowgrav, pt_fire, pt_explode, pt_explode2, pt_blob, pt_blob2\n} ptype_t;\n\n// !!! if this is changed, it must be changed in d_ifacea.h too !!!\ntypedef struct particle_s\n{\n// driver-usable fields\n\tvec3_t\t\torg;\n\tfloat\t\tcolor;\n// drivers never touch the following fields\n\tstruct particle_s\t*next;\n\tvec3_t\t\tvel;\n\tfloat\t\tramp;\n\tfloat\t\tdie;\n\tptype_t\t\ttype;\n} particle_t;\n\n\n//====================================================\n\n\nextern\tentity_t\tr_worldentity;\nextern\tbool\tr_cache_thrash;\t\t// compatability\nextern\tvec3_t\t\tmodelorg, r_entorigin;\nextern\tentity_t\t*currententity;\nextern\tint\t\t\tr_visframecount;\t// ??? what difs?\nextern\tint\t\t\tr_framecount;\nextern\tmplane_t\tfrustum[4];\nextern\tint\t\tc_brush_polys, c_alias_polys;\n\n\n//\n// view origin\n//\nextern\tvec3_t\tvup;\nextern\tvec3_t\tvpn;\nextern\tvec3_t\tvright;\nextern\tvec3_t\tr_origin;\n\n//\n// screen size info\n//\nextern\trefdef_t\tr_refdef;\nextern\tmleaf_t\t\t*r_viewleaf, *r_oldviewleaf;\nextern\ttexture_t\t*r_notexture_mip;\nextern\tint\t\td_lightstylevalue[256];\t// 8.8 fraction of base light value\n\nextern\tbool\tenvmap;\nextern\tint\tcurrenttexture;\nextern\tint\tparticletexture;\nextern\tint\tplayertextures;\n\nextern\tint\tskytexturenum;\t\t// index in cl.loadmodel, not gl texture object\n\nextern\tcvar_t\tr_drawentities;\nextern\tcvar_t\tr_drawworld;\nextern\tcvar_t\tr_drawviewmodel;\nextern\tcvar_t\tr_speeds;\nextern\tcvar_t\tr_waterwarp;\nextern\tcvar_t\tr_fullbright;\nextern\tcvar_t\tr_lightmap;\nextern\tcvar_t\tr_shadows;\nextern\tcvar_t\tr_dynamic;\n\nextern\tcvar_t\tgl_clear;\nextern\tcvar_t\tgl_cull;\nextern\tcvar_t\tgl_poly;\nextern\tcvar_t\tgl_texsort;\nextern\tcvar_t\tgl_smoothmodels;\nextern\tcvar_t\tgl_affinemodels;\nextern\tcvar_t\tgl_fogblend;\nextern\tcvar_t\tgl_polyblend;\nextern\tcvar_t\tgl_keeptjunctions;\nextern\tcvar_t\tgl_reporttjunctions;\n\nextern\tint\t\tgl_lightmap_format;\nextern\tint\t\tgl_solid_format;\nextern\tint\t\tgl_alpha_format;\n\nvoid R_TranslatePlayerSkin (int playernum);\nvoid GL_Bind (int texnum);\n"
  },
  {
    "path": "source/host.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// host.c -- coordinates spawning and killing of local servers\n\n#include \"quakedef.h\"\n#include \"r_local.h\"\n\n/*\n\nA server can always be started, even if the system started out as a client\nto a remote system.\n\nA client can NOT be started if the system started as a dedicated server.\n\nMemory is cleared / released when a server or client begins, not when they end.\n\n*/\n\nCVAR(developer, 1, CVAR_DEBUG)\nCVAR(temp1, 0, CVAR_NONE)\t// Ch0wW: Honestly never saw that CVAR being used, maybe for MOD support?\n\nCVAR(host_framerate, 0, CVAR_NONE)\nCVAR(host_speeds, 0, CVAR_NONE)\nCVAR(host_timescale, 0, CVAR_NONE)\nCVAR(sys_ticrate, 0.05, CVAR_NONE)\nCVAR(serverprofile, 0, CVAR_NONE)\n\nCVAR(skill, 1, CVAR_NONE)\nCVAR(deathmatch, 0, CVAR_SERVERINFO)\nCVAR(coop, 0, CVAR_SERVERINFO)\nCVAR(fraglimit, 0, CVAR_SERVERINFO)\nCVAR(timelimit, 0, CVAR_SERVERINFO)\nCVAR(teamplay, 0, CVAR_SERVERINFO)\nCVAR(samelevel, 0, CVAR_SERVERINFO)\nCVAR(noexit, 0, CVAR_SERVERINFO)\n\nCVAR(pausable, 1, CVAR_SERVERINFO)\n\n//----------------------------------------------\n\nquakeparms_t host_parms;\n\nbool\thost_initialized;\t\t// true if into command execution\n\ndouble\t\thost_frametime;\ndouble\t\thost_time;\ndouble\t\trealtime;\t\t\t\t// without any filtering or bounding\ndouble\t\toldrealtime;\t\t\t// last frame run\nint\t\t\thost_framecount;\n\nint\t\t\thost_hunklevel;\n\nint\t\t\tminimum_memory;\nint\t\t\tfps_count;\n\nclient_t\t*host_client;\t\t\t// current client\n\njmp_buf \thost_abortserver;\n\nbyte\t\t*host_basepal;\nbyte\t\t*host_colormap;\n\nextern void CL_RunParticles (void);\n\n/*\n================\nHost_EndGame\n================\n*/\nvoid Host_EndGame (char *message, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring = Sys_BigStackAlloc(1024, \"Host_EndGame\");\n\n\tva_start (argptr,message);\n\tvsprintf (string,message,argptr);\n\tva_end (argptr);\n\tCon_DPrintf (\"Host_EndGame: %s\\n\",string);\n\n\tif (sv.active)\n\t\tHost_ShutdownServer (false);\n\n\tif (cls.state == ca_dedicated)\n\t\tSys_Error (\"Host_EndGame: %s\\n\",string);\t// dedicated servers exit\n\n\tSys_BigStackFree(1024, \"Host_EndGame\");\n\n\tif (cls.demonum != -1)\n\t{\n\t\tCL_StopPlayback();\n\t\tCL_NextDemo();\n\t}\n\telse\n\t\tCL_Disconnect ();\n\n\tlongjmp (host_abortserver, 1);\n}\n\n/*\n================\nHost_Error\n\nThis shuts down both the client and server\n================\n*/\nvoid Host_Error (char *error, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring;\n\tstatic\tbool inerror = false;\n\n\tif (inerror)\n\t\tSys_Error (\"Host_Error: recursively entered\");\n\tinerror = true;\n\n\tSCR_EndLoadingPlaque ();\t\t// reenable screen updates\n\n\tstring = Sys_BigStackAlloc(1024, \"Host_Error\");\n\n\tva_start (argptr,error);\n\tvsprintf (string,error,argptr);\n\tva_end (argptr);\n\tCon_Printf (\"Host_Error: %s\\n\",string);\n\n\tif (sv.active)\n\t\tHost_ShutdownServer (false);\n\n\tif (cls.state == ca_dedicated)\n\t\tSys_Error (\"Host_Error: %s\\n\",string);\t// dedicated servers exit\n\n\tSys_BigStackFree(1024, \"Host_Error\");\n\n\tCL_Disconnect ();\n\tcls.demonum = -1;\n\n\tinerror = false;\n\n\tlongjmp (host_abortserver, 1);\n}\n\n/*\n================\nHost_FindMaxClients -- ToDo: Clean this up\n================\n*/\nvoid\tHost_FindMaxClients (void)\n{\n\tint\t\ti;\n\n\tsvs.maxclients = 1;\n\n\ti = COM_CheckParm (\"-dedicated\");\n\tif (i)\n\t{\n\t\tcls.state = ca_dedicated;\n\t\tif (i != (com_argc - 1))\n\t\t{\n\t\t\tsvs.maxclients = atoi (com_argv[i+1]);\n\t\t}\n\t\telse\n\t\t\tsvs.maxclients = 8;\n\t}\n\telse\n\t\tcls.state = ca_disconnected;\n\n\ti = COM_CheckParm (\"-listen\");\n\tif (i)\n\t{\n\t\tif (cls.state == ca_dedicated)\n\t\t\tSys_Error (\"Only one of -dedicated or -listen can be specified\");\n\t\tif (i != (com_argc - 1))\n\t\t\tsvs.maxclients = atoi (com_argv[i+1]);\n\t\telse\n\t\t\tsvs.maxclients = 8;\n\t}\n\tif (svs.maxclients < 1)\n\t\tsvs.maxclients = 8;\n\telse if (svs.maxclients > MAX_SCOREBOARD)\n\t\tsvs.maxclients = MAX_SCOREBOARD;\n\n\tsvs.maxclientslimit = svs.maxclients;\n\tif (svs.maxclientslimit < 4)\n\t\tsvs.maxclientslimit = 4;\n\tsvs.clients = (client_t*)Hunk_AllocName(svs.maxclientslimit * sizeof(client_t), \"clients\");\n\n\tCvar_SetValue (\"deathmatch\", svs.maxclients > 1 ? 1.0 : 0.0);\n}\n\n\n/*\n=======================\nHost_InitLocal\n======================\n*/\nvoid Host_InitLocal (void)\n{\n\tHost_InitCommands ();\n\n\tCvar_RegisterVariable (&host_framerate);\n\tCvar_RegisterVariable (&host_speeds);\n\tCvar_RegisterVariable (&host_timescale);\n\n\tCvar_RegisterVariable (&sys_ticrate);\n\tCvar_RegisterVariable (&serverprofile);\n\n\tCvar_RegisterVariable (&fraglimit);\n\tCvar_RegisterVariable (&timelimit);\n\tCvar_RegisterVariable (&teamplay);\n\tCvar_RegisterVariable (&samelevel);\n\tCvar_RegisterVariable (&noexit);\n\tCvar_RegisterVariable (&skill);\n\tCvar_RegisterVariable (&developer);\n\tCvar_RegisterVariable (&deathmatch);\n\tCvar_RegisterVariable (&coop);\n\n\tCvar_RegisterVariable (&pausable);\n\n\tCvar_RegisterVariable (&temp1);\n\n\tHost_FindMaxClients ();\n\n\thost_time = 1.0;\t\t// so a think at time 0 won't get called\n}\n\n\n/*\n===============\nHost_WriteConfiguration\n\nWrites key bindings and archived cvars to config.cfg\n===============\n*/\nvoid Host_WriteConfiguration (char *name)\n{\n\tFILE\t*f;\n\n// dedicated servers initialize the host but don't parse and set the\n// config.cfg cvars\n\tif (host_initialized)\n\t{\n\t\tf = fopen (va(\"%s/%s\",com_gamedir, name), \"w\");\n\t\tif (!f)\n\t\t{\n\t\t\tSys_Error (\"Couldn't write config.cfg.\\n\");\n\t\t\treturn;\n\t\t}\n\n\t\tfprintf(f, \"//=====================================\\n\");\n\t\tfprintf(f, \"//Generated by %s, do not modify!\\n\", ENGINE_NAME);\n\t\tfprintf(f, \"//=====================================\\n\\n\");\n\t\tKey_WriteBindings (f);\n\t\tCvar_WriteVariables (f);\n\n\t\tfclose (f);\n\t}\n}\n\n\n/*\n=================\nSV_ClientPrintf\n\nSends text across to be displayed\nFIXME: make this just a stuffed echo?\n=================\n*/\nvoid SV_ClientPrintf (const char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring = Sys_BigStackAlloc(1024, \"SV_ClientPrintf\");\n\n\tva_start (argptr,fmt);\n\tvsprintf (string, fmt,argptr);\n\tva_end (argptr);\n\n\tMSG_WriteByte (&host_client->message, svc_print);\n\tMSG_WriteString (&host_client->message, string);\n\n\tSys_BigStackFree(1024, \"SV_ClientPrintf\");\n}\n\n/*\n=================\nSV_BroadcastPrintf\n\nSends text to all active clients\n=================\n*/\nvoid SV_BroadcastPrintf (char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring = Sys_BigStackAlloc(1024, \"SV_BroadcastPrintf\");\n\tint\t\t\ti;\n\n\tva_start (argptr,fmt);\n\tvsprintf (string, fmt,argptr);\n\tva_end (argptr);\n\n\tfor (i = 0; i < svs.maxclients; i++)\n\t{\n\t\tif (svs.clients[i].active && svs.clients[i].spawned)\n\t\t{\n\t\t\tMSG_WriteByte(&svs.clients[i].message, svc_print);\n\t\t\tMSG_WriteString(&svs.clients[i].message, string);\n\t\t}\n\t}\n\n\tSys_BigStackFree(1024, \"SV_BroadcastPrintf\");\t\n}\n\n/*\n=================\nHost_ClientCommands\n\nSend text over to the client to be executed\n=================\n*/\nvoid Host_ClientCommands (char *fmt, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring = Sys_BigStackAlloc(1024, \"Host_ClientCommands\");\n\n\tva_start (argptr,fmt);\n\tvsprintf (string, fmt,argptr);\n\tva_end (argptr);\n\n\tMSG_WriteByte (&host_client->message, svc_stufftext);\n\tMSG_WriteString (&host_client->message, string);\n\n\tSys_BigStackFree(1024, \"Host_ClientCommands\");\n}\n\n/*\n=====================\nSV_DropClient\n\nCalled when the player is getting totally kicked off the host\nif (crash = true), don't bother sending signofs\n=====================\n*/\nvoid SV_DropClient (bool crash)\n{\n\tint\t\tsaveSelf;\n\tint\t\ti;\n\tclient_t *client;\n\n\tif (!host_client->active)\n\t\treturn;\n\n\tif (!crash)\n\t{\n\t\t// send any final messages (don't check for errors)\n\t\tif (NET_CanSendMessage (host_client->netconnection))\n\t\t{\n\t\t\tMSG_WriteByte (&host_client->message, svc_disconnect);\n\t\t\tNET_SendMessage (host_client->netconnection, &host_client->message);\n\t\t}\n\n\t\tif (host_client->edict && host_client->spawned)\n\t\t{\n\t\t// call the prog function for removing a client\n\t\t// this will set the body to a dead frame, among other things\n\t\t\tsaveSelf = pr_global_struct->self;\n\t\t\tpr_global_struct->self = EDICT_TO_PROG(host_client->edict);\n\t\t\tPR_ExecuteProgram (pr_global_struct->ClientDisconnect);\n\t\t\tpr_global_struct->self = saveSelf;\n\t\t}\n\n\t\tSys_Printf (\"Client %s removed\\n\",host_client->name);\n\t}\n\n\t/*if (host_client->netconnection->proquake_connection == MOD_QSMACK)\n\t\tqsmackActive = false;*/\n\n// break the net connection\n\tNET_Close (host_client->netconnection);\n\thost_client->netconnection = NULL;\n\n// free the client (the body stays around)\n\thost_client->active = false;\n\thost_client->name[0] = 0;\n\thost_client->old_frags = -999999;\n\tnet_activeconnections--;\n\n// send notification to all clients\n\tfor (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)\n\t{\n\t\tif (!client->active)\n\t\t\tcontinue;\n\t\tMSG_WriteByte (&client->message, svc_updatename);\n\t\tMSG_WriteByte (&client->message, host_client - svs.clients);\n\t\tMSG_WriteString (&client->message, \"\");\n\t\tMSG_WriteByte (&client->message, svc_updatefrags);\n\t\tMSG_WriteByte (&client->message, host_client - svs.clients);\n\t\tMSG_WriteShort (&client->message, 0);\n\t\tMSG_WriteByte (&client->message, svc_updatecolors);\n\t\tMSG_WriteByte (&client->message, host_client - svs.clients);\n\t\tMSG_WriteByte (&client->message, 0);\n\t}\n}\n\n/*\n==================\nHost_ShutdownServer\n\nThis only happens at the end of a game, not between levels\n==================\n*/\nvoid Host_ShutdownServer(bool crash)\n{\n\tint\t\ti;\n\tint\t\tcount;\n\tsizebuf_t\tbuf;\n\tchar\t\tmessage[4];\n\tdouble\tstart;\n\n\tif (!sv.active)\n\t\treturn;\n\n\tsv.active = false;\n\n// stop all client sounds immediately\n\tif (cls.state == ca_connected)\n\t\tCL_Disconnect ();\n\n// flush any pending messages - like the score!!!\n\tstart = Sys_FloatTime();\n\tdo\n\t{\n\t\tcount = 0;\n\t\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t\t{\n\t\t\tif (host_client->active && host_client->message.cursize)\n\t\t\t{\n\t\t\t\tif (NET_CanSendMessage (host_client->netconnection))\n\t\t\t\t{\n\t\t\t\t\tNET_SendMessage(host_client->netconnection, &host_client->message);\n\t\t\t\t\tSZ_Clear (&host_client->message);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNET_GetMessage(host_client->netconnection);\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif ((Sys_FloatTime() - start) > 3.0)\n\t\t\tbreak;\n\t}\n\twhile (count);\n\n// make sure all the clients know we're disconnecting\n\tbuf.data = message;\n\tbuf.maxsize = 4;\n\tbuf.cursize = 0;\n\tMSG_WriteByte(&buf, svc_disconnect);\n\tcount = NET_SendToAll(&buf, 5);\n\tif (count)\n\t\tCon_Printf(\"Host_ShutdownServer: NET_SendToAll failed for %u clients\\n\", count);\n\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t\tif (host_client->active)\n\t\t\tSV_DropClient(crash);\n\n//\n// clear structures\n//\n\tmemset (&sv, 0, sizeof(sv));\n\tmemset (svs.clients, 0, svs.maxclientslimit*sizeof(client_t));\n}\n\n\n/*\n================\nHost_ClearMemory\n\nThis clears all the memory used by both the client and server, but does\nnot reinitialize anything.\n================\n*/\nvoid Host_ClearMemory (void)\n{\n\tCon_DPrintf (\"Clearing memory\\n\");\n\tD_FlushCaches ();\n\tMod_ClearAll ();\n\tif (host_hunklevel)\n\t\tHunk_FreeToLowMark (host_hunklevel);\n\n\tcls.signon = 0;\n\tmemset (&sv, 0, sizeof(sv));\n\tmemset (&cl, 0, sizeof(cl));\n}\n\n\n//============================================================================\n\n\n/*\n===================\nHost_FilterTime\n\nReturns false if the time is too short to run a frame\n===================\n*/\nextern bool benchmark;\nbool Host_FilterTime (float time)\n{\n\trealtime += time;\n\tif ( ( (!cls.timedemo || !benchmark) || (cls.timedemo && benchmark) ) && realtime - oldrealtime < 1.0/72.0)\n\t\treturn false;\t\t// framerate is too high\n\n\thost_frametime = realtime - oldrealtime;\n\toldrealtime = realtime;\n\n\t//johnfitz -- host_timescale is more intuitive than host_framerate\n\tif (host_timescale.value > 0)\n\t\thost_frametime *= host_timescale.value;\n\t//johnfitz\n\telse if (host_framerate.value > 0)\n\t\thost_frametime = host_framerate.value;\n\telse\n\t{\t// don't allow really long or short frames\n\t\tif (host_frametime > 0.1)\n\t\t\thost_frametime = 0.1;\n\t\tif (host_frametime < 0.001)\n\t\t\thost_frametime = 0.001;\n\t}\n\n\treturn true;\n}\n\n\n/*\n===================\nHost_GetConsoleCommands\n\nAdd them exactly as if they had been typed at the console\n===================\n*/\nvoid Host_GetConsoleCommands (void)\n{\n\tchar\t*cmd;\n\n\twhile (1)\n\t{\n\t\tcmd = Sys_ConsoleInput ();\n\t\tif (!cmd)\n\t\t\tbreak;\n\t\tCbuf_AddText (cmd);\n\t}\n}\n\n\n/*\n==================\nHost_ServerFrame\n\n==================\n*/\n#ifdef FPS_20\n\nvoid _Host_ServerFrame (void)\n{\n// run the world state\n\tpr_global_struct->frametime = host_frametime;\n\n// read client messages\n\tSV_RunClients ();\n\n// move things around and think\n// always pause in single player if in console or menus\n\tif (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )\n\t\tSV_Physics ();\n}\n\nvoid Host_ServerFrame (void)\n{\n\tfloat\tsave_host_frametime;\n\tfloat\ttemp_host_frametime;\n\n// run the world state\n\tpr_global_struct->frametime = host_frametime;\n\n// set the time and clear the general datagram\n\tSV_ClearDatagram ();\n\n// check for new clients\n\tSV_CheckForNewClients ();\n\n\ttemp_host_frametime = save_host_frametime = host_frametime;\n\twhile(temp_host_frametime > (1.0/72.0))\n\t{\n\t\tif (temp_host_frametime > 0.05)\n\t\t\thost_frametime = 0.05;\n\t\telse\n\t\t\thost_frametime = temp_host_frametime;\n\t\ttemp_host_frametime -= host_frametime;\n\t\t_Host_ServerFrame ();\n\t}\n\thost_frametime = save_host_frametime;\n\n// send all messages to the clients\n\tSV_SendClientMessages ();\n}\n\n#else\n\nvoid Host_ServerFrame (void)\n{\n\n\tstatic double port_time = 0;\n\n\tif (port_time > sv.time + 1 || port_time < sv.time - 60)\n\t{\n\t\tport_time = sv.time;\n\t\tCmd_ExecuteString(va(\"port %d\\n\", net_hostport), src_command);\n\t}\n\n// run the world state\n\tpr_global_struct->frametime = host_frametime;\n\n// set the time and clear the general datagram\n\tSV_ClearDatagram ();\n\n// check for new clients\n\tSV_CheckForNewClients ();\n\n// read client messages\n\tSV_RunClients ();\n\n// move things around and think\n// always pause in single player if in console or menus\n\tif (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )\n\t\tSV_Physics ();\n\n// send all messages to the clients\n\tSV_SendClientMessages ();\n}\n\n#endif\n\n\n/*\n==================\nHost_Frame\n\nRuns all active servers\n==================\n*/\nvoid _Host_Frame (float time)\n{\n\tstatic double\t\ttime1 = 0;\n\tstatic double\t\ttime2 = 0;\n\tstatic double\t\ttime3 = 0;\n\tint\t\t\tpass1, pass2, pass3;\n\n\tif (setjmp (host_abortserver) )\n\t\treturn;\t\t\t// something bad happened, or the server disconnected\n\n// keep the random time dependent\n\trand ();\n\n// decide the simulation time\n\tif (!Host_FilterTime (time))\n\t\treturn;\t\t\t// don't run too fast, or packets will flood out\n\n// get new key events\n\tSys_SendKeyEvents ();\n\n// allow mice or other external controllers to add commands\n\tIN_Commands ();\n\n// process console commands\n\tCbuf_Execute ();\n\tNET_Poll();\n\n// if running the server locally, make intentions now\n\tif (sv.active){\n\t\tCL_SendCmd ();\n\t}\n\n//-------------------\n//\n// server operations\n//\n//-------------------\n\n// check for commands typed to the host\n\tHost_GetConsoleCommands ();\n\n\tif (sv.active){\n\t\tHost_ServerFrame ();\n\t}\n\n//-------------------\n//\n// client operations\n//\n//-------------------\n\n// if running the server remotely, send intentions now after\n// the incoming messages have been read\n\tif (!sv.active){\n\t\tCL_SendCmd ();\n\t}\n\n\thost_time += host_frametime;\n\n// fetch results from server\n\tif (cls.state == ca_connected)\n\t{\n\t\tCL_ReadFromServer ();\n\t}\n\n// update video\n\tif (host_speeds.value)\n\t\ttime1 = Sys_FloatTime ();\n\n\tSCR_UpdateScreen ();\n\n\tCL_RunParticles (); //johnfitz -- seperated from rendering\n\t\n\tif (host_speeds.value)\n\t\ttime2 = Sys_FloatTime ();\n\n// update audio\n\tif (cls.signon == SIGNONS)\n\t{\n\t\tS_Update (r_origin, vpn, vright, vup);\n\t\tCL_DecayLights ();\n\t}\n\telse\n\t\tS_Update (vec3_origin, vec3_origin, vec3_origin, vec3_origin);\n\n\tCDAudio_Update();\n\n\tif (host_speeds.value)\n\t{\n\t\tpass1 = (time1 - time3)*1000;\n\t\ttime3 = Sys_FloatTime ();\n\t\tpass2 = (time2 - time1)*1000;\n\t\tpass3 = (time3 - time2)*1000;\n\t\tCon_Printf (\"%3i tot %3i server %3i gfx %3i snd\\n\",\n\t\t\t\t\tpass1+pass2+pass3, pass1, pass2, pass3);\n\t}\n\n\thost_framecount++;\n\tfps_count++;\n}\n\nvoid Host_Frame (float time)\n{\n\tdouble\ttime1, time2;\n\tstatic double\ttimetotal;\n\tstatic int\t\ttimecount;\n\tint\t\ti, c, m;\n\n\tif (!serverprofile.value)\n\t{\n\t\t_Host_Frame (time);\n\t\treturn;\n\t}\n\n\ttime1 = Sys_FloatTime ();\n\t_Host_Frame (time);\n\ttime2 = Sys_FloatTime ();\n\n\ttimetotal += time2 - time1;\n\ttimecount++;\n\n\tif (timecount < 1000)\n\t\treturn;\n\n\tm = timetotal*1000/timecount;\n\ttimecount = 0;\n\ttimetotal = 0;\n\tc = 0;\n\tfor (i=0 ; i<svs.maxclients ; i++)\n\t{\n\t\tif (svs.clients[i].active)\n\t\t\tc++;\n\t}\n\n\tCon_Printf (\"serverprofile: %2i clients %2i msec\\n\",  c,  m);\n}\n\n//============================================================================\n\n\nextern int vcrFile;\n#define\tVCR_SIGNATURE\t0x56435231\n// \"VCR1\"\n\nvoid Host_InitVCR (quakeparms_t *parms)\n{\n\tint\t\ti, len, n;\n\tchar\t*p;\n\n\tif (COM_CheckParm(\"-playback\"))\n\t{\n\t\tif (com_argc != 2)\n\t\t\tSys_Error(\"No other parameters allowed with -playback\\n\");\n\n\t\tSys_FileOpenRead(\"quake.vcr\", &vcrFile);\n\t\tif (vcrFile == -1)\n\t\t\tSys_Error(\"playback file not found\\n\");\n\n\t\tSys_FileRead (vcrFile, &i, sizeof(int));\n\t\tif (i != VCR_SIGNATURE)\n\t\t\tSys_Error(\"Invalid signature in vcr file\\n\");\n\n\t\tSys_FileRead (vcrFile, &com_argc, sizeof(int));\n\t\tcom_argv = malloc(com_argc * sizeof(char *));\n\t\tcom_argv[0] = parms->argv[0];\n\t\tfor (i = 0; i < com_argc; i++)\n\t\t{\n\t\t\tSys_FileRead (vcrFile, &len, sizeof(int));\n\t\t\tp = malloc(len);\n\t\t\tSys_FileRead (vcrFile, p, len);\n\t\t\tcom_argv[i+1] = p;\n\t\t}\n\t\tcom_argc++; /* add one for arg[0] */\n\t\tparms->argc = com_argc;\n\t\tparms->argv = com_argv;\n\t}\n\n\tif ( (n = COM_CheckParm(\"-record\")) != 0)\n\t{\n\t\tvcrFile = Sys_FileOpenWrite(\"quake.vcr\");\n\n\t\ti = VCR_SIGNATURE;\n\t\tSys_FileWrite(vcrFile, &i, sizeof(int));\n\t\ti = com_argc - 1;\n\t\tSys_FileWrite(vcrFile, &i, sizeof(int));\n\t\tfor (i = 1; i < com_argc; i++)\n\t\t{\n\t\t\tif (i == n)\n\t\t\t{\n\t\t\t\tlen = 10;\n\t\t\t\tSys_FileWrite(vcrFile, &len, sizeof(int));\n\t\t\t\tSys_FileWrite(vcrFile, \"-playback\", len);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tlen = strlen(com_argv[i]) + 1;\n\t\t\tSys_FileWrite(vcrFile, &len, sizeof(int));\n\t\t\tSys_FileWrite(vcrFile, com_argv[i], len);\n\t\t}\n\t}\n\n}\n\n/*\n====================\nHost_Init\n====================\n*/\nvoid Host_Init (quakeparms_t *parms)\n{\n\n\tif (standard_quake)\n\t\tminimum_memory = MINIMUM_MEMORY;\n\telse\n\t\tminimum_memory = MINIMUM_MEMORY_LEVELPAK;\n\n\tif (COM_CheckParm (\"-minmemory\"))\n\t\tparms->memsize = minimum_memory;\n\n\thost_parms = *parms;\n\n\tif (parms->memsize < minimum_memory)\n\t\tSys_Error (\"Only %4.1f megs of memory available, can't execute game\", parms->memsize / (float)0x100000);\n\n\tcom_argc = parms->argc;\n\tcom_argv = parms->argv;\n\tMemory_Init (parms->membase, parms->memsize);\n\tCbuf_Init ();\n\tCmd_Init ();\n\tV_Init ();\n\tChase_Init ();\n\tHost_InitVCR (parms);\n\tCOM_Init (parms->basedir);\n\tHost_InitLocal ();\n\n\tW_LoadWadFile (\"gfx.wad\");\n\tKey_Init ();\n\n\tCon_Init ();\n\tM_Init ();\n\tPR_Init ();\n\tMod_Init ();\n\tNET_Init ();\n\tSV_Init ();\n\n\tHost_Version_f();\n\tCon_Printf (\"%4.1f megabyte heap\\n\",parms->memsize/ (1024*1024.0));\n\n\tR_InitTextures ();\t\t// needed even for dedicated servers\n\n\tif (cls.state != ca_dedicated)\n\t{\n\t\thost_basepal = (byte *)COM_LoadHunkFile (\"gfx/palette.lmp\", NULL);\n\t\tif (!host_basepal)\n\t\t\tSys_Error (\"Couldn't load gfx/palette.lmp\");\n\t\thost_colormap = (byte *)COM_LoadHunkFile (\"gfx/colormap.lmp\", NULL);\n\t\tif (!host_colormap)\n\t\t\tSys_Error (\"Couldn't load gfx/colormap.lmp\");\n\n#ifndef _WIN32 // on non win32, mouse comes before video for security reasons\n\t\tIN_Init ();\n#endif\n\t\tVID_Init (host_basepal);\n\n\t\tDraw_Init ();\n\t\tSCR_Init ();\n\t\tR_Init ();\n#ifndef\t_WIN32\n\t// on Win32, sound initialization has to come before video initialization, so we\n\t// can put up a popup if the sound hardware is in use\n\t\tS_Init ();\n#else\n\n#ifdef\tGLQUAKE\n\t// FIXME: doesn't use the new one-window approach yet\n\t\tS_Init ();\n#endif\n\n#endif\t// _WIN32\n\t\tCDAudio_Init ();\n\t\tSbar_Init ();\n\t\tCL_Init ();\n#ifdef _WIN32 // on non win32, mouse comes before video for security reasons\n\t\tIN_Init ();\n#endif\n\t}\n\n\tCbuf_InsertText (\"exec quake.rc\\n\");\n\n\tHunk_AllocName (0, \"-HOST_HUNKLEVEL-\");\n\thost_hunklevel = Hunk_LowMark ();\n\n\thost_initialized = true;\n\n\tSys_Printf (\"======== %s Initialized=========\\n\", ENGINE_NAME);\n}\n\n\n/*\n===============\nHost_Shutdown\n\nFIXME: this is a callback from Sys_Quit and Sys_Error.  It would be better\nto run quit through here before the final handoff to the sys code.\n===============\n*/\nvoid Host_Shutdown(void)\n{\n\tstatic bool isdown = false;\n\n\tif (isdown)\n\t{\n\t\tprintf (\"recursive shutdown\\n\");\n\t\treturn;\n\t}\n\tisdown = true;\n\n// keep Con_Printf from trying to update the screen\n\tscr_disabled_for_loading = true;\n\n\tHost_WriteConfiguration (\"config.cfg\");\n\n\tCDAudio_Shutdown ();\n\tNET_Shutdown ();\n\tS_Shutdown();\n\tIN_Shutdown ();\n\n\tif (cls.state != ca_dedicated)\n\t{\n\t\tVID_Shutdown();\n\t}\n}\n"
  },
  {
    "path": "source/host_cmd.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n\nextern cvar_t pausable;\nextern int com_nummissionpacks; //johnfitz\nextern void Host_WriteConfiguration (char *name);\nextern void COM_ForceExtension(char *path, char *extension);\n\nint\tcurrent_skill;\n\nvoid Mod_Print (void);\n\n/*\n==================\nHost_Quit_f\n==================\n*/\n\nextern void M_Menu_Quit_f (void);\n\nvoid Host_Quit_f (void)\n{\n\tif (key_dest != key_console && cls.state != ca_dedicated)\n\t{\n\t\tM_Menu_Quit_f ();\n\t\treturn;\n\t}\n\tCL_Disconnect ();\n\tHost_ShutdownServer(false);\n\n\tSys_Quit ();\n}\n\n//==============================================================================\n//johnfitz -- dynamic gamedir stuff\n//==============================================================================\n\nextern bool com_modified;\nextern searchpath_t *com_searchpaths;\npack_t *COM_LoadPackFile (char *packfile);\n\n// Kill all the search packs until the game path is found. Kill it, then return\n// the next path to it.\nvoid KillGameDir(searchpath_t *search)\n{\n\tsearchpath_t *search_killer;\n\twhile (search)\n\t{\n\t\tif (*search->filename)\n\t\t{\n\t\t\tcom_searchpaths = search->next;\n\t\t\tZ_Free(search);\n\t\t\treturn; //once you hit the dir, youve already freed the paks\n\t\t}\n\t\tSys_FileClose (search->pack->handle); //johnfitz\n\t\tsearch_killer = search->next;\n\t\tZ_Free(search->pack->files);\n\t\tZ_Free(search->pack);\n\t\tZ_Free(search);\n\t\tsearch = search_killer;\n\t}\n}\n\n// Return the number of games in memory\nint NumGames(searchpath_t *search)\n{\n\tint found = 0;\n\twhile (search)\n\t{\n\t\tif (*search->filename)\n\t\t\tfound++;\n\t\tsearch = search->next;\n\t}\n\treturn found;\n}\n\nvoid ExtraMaps_NewGame (void);\n\n/*\n===============\nHost_WriteConfig_f\nWrites key bindings and ONLY archived cvars to a custom config file\n===============\n*/\nvoid Host_WriteConfig_f (void)\n{\n\tchar\tname[MAX_OSPATH];\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"Usage: writeconfig <filename>\\n\");\n\t\treturn;\n\t}\n\n\tstrncpyz (name, Cmd_Argv(1), sizeof(name));\n\tCOM_ForceExtension (name, \".cfg\");\n\n\tCon_Printf (\"Writing %s\\n\", name);\n\n\tHost_WriteConfiguration (name);\n}\n\n/*\n==================\nHost_Game_f\n==================\n*/\nextern char mp_path[32];\nextern char* mod_path;\nvoid Host_Game_f (void)\n{\n\tint i;\n\tsearchpath_t *search = com_searchpaths;\n\tpack_t *pak;\n\tchar   pakfile[MAX_OSPATH]; //FIXME: it's confusing to use this string for two different things\n\n\tif (Cmd_Argc() > 1)\n\t{\n\n\t\tif (!registered.value) //disable command for shareware quake\n\t\t\tCon_Printf(\"Shareware version detected, issues may be encountered\\n\");\n\n\t\tif (strstr(Cmd_Argv(1), \"..\"))\n\t\t{\n\t\t\tCon_Printf (\"Relative pathnames are not allowed.\\n\");\n\t\t\treturn;\n\t\t}\n\t\t\n\t\tstrcpy (pakfile, va(\"%s/%s\", host_parms.basedir, Cmd_Argv(1)));\n\t\tif (!strcasecmp(pakfile, com_gamedir)) //no change\n\t\t{\n\t\t\tCon_Printf(\"\\\"game\\\" is already \\\"%s\\\"\\n\", COM_SkipPath(com_gamedir));\n\t\t\treturn;\n\t\t}\n\t\tsprintf(mp_path, Cmd_Argv(1));\n\t\tmod_path = mp_path;\n\t\tcom_modified = true;\n\n\t\t//Kill the server\n\t\tCL_Disconnect ();\n\t\tHost_ShutdownServer(true);\n\n\t\t//Write config file\n\t\tHost_WriteConfiguration (\"config.cfg\");\n\n\t\t//Kill the extra game if it is loaded\n\t\tif (NumGames(com_searchpaths) > 1 + com_nummissionpacks)\n\t\t\tKillGameDir(com_searchpaths);\n\n\t\tstrcpy (com_gamedir, pakfile);\n\n\t\tif (strcasecmp(Cmd_Argv(1), GAMENAME_DIR)) //game is not id1\n\t\t{\n\t\t\tsearch = Z_Malloc(sizeof(searchpath_t));\n\t\t\tstrcpy (search->filename, pakfile);\n\t\t\tsearch->next = com_searchpaths;\n\t\t\tcom_searchpaths = search;\n\n\t\t\t//Load the paks if any are found:\n\t\t\tfor (i = 0; ; i++)\n\t\t\t{\n\t\t\t\tsprintf (pakfile, \"%s/pak%i.pak\", com_gamedir, i);\n\t\t\t\tpak = COM_LoadPackFile (pakfile);\n\t\t\t\tif (!pak)\n\t\t\t\tbreak;\n\t\t\t\tsearch = Z_Malloc(sizeof(searchpath_t));\n\t\t\t\tsearch->pack = pak;\n\t\t\t\tsearch->next = com_searchpaths;\n\t\t\t\tcom_searchpaths = search;\n\t\t\t}\n\t\t}\n\n\t\t//clear out and reload appropriate data\n\t\tCache_Flush ();\n\t\tMod_ResetAll();\n\t\tExtraMaps_NewGame ();\n\t\t//Cbuf_InsertText (\"exec quake.rc\\n\");\n\n\t\tCon_Printf(\"\\\"game\\\" changed to \\\"%s\\\"\\n\", COM_SkipPath(com_gamedir));\n\t}\n\telse //Diplay the current gamedir\n\t\tCon_Printf(\"\\\"game\\\" is \\\"%s\\\"\\n\", COM_SkipPath(com_gamedir));\n}\n\n//==============================================================================\n//johnfitz -- extramaps management\n//==============================================================================\n\ntypedef struct extralevel_s\n{\n\tchar\t\t\t\tname[32];\n\tstruct extralevel_s\t*next;\n} extralevel_t;\n\nextralevel_t\t*extralevels;\n\nvoid ExtraMaps_Add (char *name)\n{\n\textralevel_t\t*level,*cursor,*prev;\n\n\t//ingore duplicate\n\tfor (level = extralevels; level; level = level->next)\n\t\tif (!strcmp (name, level->name))\n\t\t\treturn;\n\n\tlevel = Z_Malloc(sizeof(extralevel_t));\n\tstrcpy (level->name, name);\n\n\t//insert each entry in alphabetical order\n    if (extralevels == NULL || strcasecmp(level->name, extralevels->name) < 0) //insert at front\n\t{\n        level->next = extralevels;\n        extralevels = level;\n    }\n    else //insert later\n\t{\n        prev = extralevels;\n        cursor = extralevels->next;\n        while (cursor && (strcasecmp(level->name, cursor->name) > 0))\n\t\t{\n            prev = cursor;\n            cursor = cursor->next;\n        }\n        level->next = prev->next;\n        prev->next = level;\n    }\n}\n\nvoid ExtraMaps_Init (void) //TODO: move win32 specific stuff to sys_win.c\n{\n}\n\nvoid ExtraMaps_Clear (void)\n{\n\textralevel_t *blah;\n\n\twhile (extralevels)\n\t{\n\t\tblah = extralevels->next;\n\t\tZ_Free(extralevels);\n\t\textralevels = blah;\n\t}\n}\n\nvoid ExtraMaps_NewGame (void)\n{\n\tExtraMaps_Clear ();\n\tExtraMaps_Init ();\n}\n\n/*\n==================\nHost_Maps_f\n==================\n*/\nvoid Host_Maps_f (void)\n{\n\tint i;\n\textralevel_t\t*level;\n\n\tfor (level=extralevels, i=0; level; level=level->next, i++)\n\t\tCon_SafePrintf (\"   %s\\n\", level->name);\n\n\tif (i)\n\t\tCon_SafePrintf (\"%i map(s)\\n\", i);\n\telse\n\t\tCon_SafePrintf (\"no maps found\\n\");\n}\n\n//==============================================================================\n//johnfitz -- modlist management\n//==============================================================================\n\ntypedef struct mod_s\n{\n\tchar\t\t\tname[MAX_OSPATH];\n\tstruct mod_s\t*next;\n} mod_t;\n\nmod_t\t*modlist;\n\nvoid Modlist_Add (char *name)\n{\n\tmod_t\t*mod,*cursor,*prev;\n\n\t//ingore duplicate\n\tfor (mod = modlist; mod; mod = mod->next)\n\t\tif (!strcmp (name, mod->name))\n\t\t\treturn;\n\n\tmod = Z_Malloc(sizeof(mod_t));\n\tstrcpy (mod->name, name);\n\n\t//insert each entry in alphabetical order\n    if (modlist == NULL || strcasecmp(mod->name, modlist->name) < 0) //insert at front\n\t{\n        mod->next = modlist;\n        modlist = mod;\n    }\n    else //insert later\n\t{\n        prev = modlist;\n        cursor = modlist->next;\n        while (cursor && (strcasecmp(mod->name, cursor->name) > 0))\n\t\t{\n            prev = cursor;\n            cursor = cursor->next;\n        }\n        mod->next = prev->next;\n        prev->next = mod;\n    }\n}\n\nvoid Modlist_Init (void) //TODO: move win32 specific stuff to sys_win.c\n{\n#ifdef _WIN32\n\tWIN32_FIND_DATA\tFindFileData, FindChildData;\n\tHANDLE\t\t\tFind, FindProgs, FindPak;\n\tchar\t\t\tfilestring[MAX_OSPATH], childstring[MAX_OSPATH];\n\tint\t\t\t\ttemp;\n\n\tsprintf (filestring,\"%s/*\", host_parms.basedir);\n\tFind = FindFirstFile(filestring, &FindFileData);\n\tif (Find == INVALID_HANDLE_VALUE)\n\t{\n\t\tFindClose (Find);\n\t\treturn;\n\t}\n\n\tdo\n\t{\n\t\tsprintf (childstring,\"%s/%s/progs.dat\", host_parms.basedir, FindFileData.cFileName);\n\t\tFindProgs = FindFirstFile(childstring, &FindChildData);\n\n\t\tsprintf (childstring,\"%s/%s/*.pak\", host_parms.basedir, FindFileData.cFileName);\n\t\tFindPak = FindFirstFile(childstring, &FindChildData);\n\n\t\tif (FindProgs != INVALID_HANDLE_VALUE || FindPak != INVALID_HANDLE_VALUE)\n\t\t\tModlist_Add (FindFileData.cFileName);\n\n\t\tFindClose (FindProgs);\n\t\tFindClose (FindPak);\n\t} while (FindNextFile(Find, &FindFileData));\n\n\tFindClose (Find);\n#endif\n}\n\n/*\n==================\nHost_Mods_f -- johnfitz\n\nlist all potential mod directories (contain either a pak file or a progs.dat)\n==================\n*/\nvoid Host_Mods_f (void)\n{\n\tint i;\n\tmod_t\t*mod;\n\n\tfor (mod = modlist, i=0; mod; mod = mod->next, i++)\n\t\tCon_SafePrintf (\"   %s\\n\", mod->name);\n\n\tif (i)\n\t\tCon_SafePrintf (\"%i mod(s)\\n\", i);\n\telse\n\t\tCon_SafePrintf (\"no mods found\\n\");\n}\n\n//==============================================================================\n\n/*\n=============\nHost_Mapname_f -- johnfitz\n=============\n*/\nvoid Host_Mapname_f (void)\n{\n\tchar name[MAX_QPATH];\n\n\tif (sv.active)\n\t{\n\t\tCOM_StripExtension (sv.worldmodel->name + 5, name);\n\t\tCon_Printf (\"\\\"mapname\\\" is \\\"%s\\\"\\n\", name);\n\t\treturn;\n\t}\n\n\tif (cls.state == ca_connected)\n\t{\n\t\tCOM_StripExtension (cl.worldmodel->name + 5, name);\n\t\tCon_Printf (\"\\\"mapname\\\" is \\\"%s\\\"\\n\", name);\n\t\treturn;\n\t}\n\n\tCon_Printf (\"no map loaded\\n\");\n}\n\n/*\n==================\nHost_Status_f\n==================\n*/\nvoid Host_Status_f (void)\n{\n\tclient_t\t*client;\n\tint\t\t\tseconds;\n\tint\t\t\tminutes;\n\tint\t\t\thours = 0;\n\tint\t\t\tj;\n\tvoid\t\t(*print) (const char *fmt, ...);\n\n\tif (cmd_source == src_command)\n\t{\n\t\tif (!sv.active)\n\t\t{\n\t\t\tCmd_ForwardToServer ();\n\t\t\treturn;\n\t\t}\n\t\tprint = Con_Printf;\n\t}\n\telse\n\t\tprint = SV_ClientPrintf;\n\n\tprint (\"host:    %s\\n\", Cvar_VariableString (\"hostname\"));\n\tprint (\"version: %4.2f\\n\", VERSION);\n\tif (tcpipAvailable)\n\t\tprint (\"tcp/ip:  %s\\n\", my_tcpip_address);\n\tprint (\"map:     %s\\n\", sv.name);\n\tprint (\"players: %i active (%i max)\\n\\n\", net_activeconnections, svs.maxclients);\n\tfor (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)\n\t{\n\t\tif (!client->active)\n\t\t\tcontinue;\n\t\tseconds = (int)(net_time - client->netconnection->connecttime);\n\t\tminutes = seconds / 60;\n\t\tif (minutes)\n\t\t{\n\t\t\tseconds -= (minutes * 60);\n\t\t\thours = minutes / 60;\n\t\t\tif (hours)\n\t\t\t\tminutes -= (hours * 60);\n\t\t}\n\t\telse\n\t\t\thours = 0;\n\t\tprint (\"#%-2u %-16.16s  %3i  %2i:%02i:%02i\\n\", j+1, client->name, (int)client->edict->v.frags, hours, minutes, seconds);\n\t\tprint (\"   %s\\n\", client->netconnection->address);\n\t}\n}\n\n\n/*\n==================\nHost_God_f\n\nSets client to godmode\n==================\n*/\nvoid Host_God_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tsv_player->v.flags = (int)sv_player->v.flags ^ FL_GODMODE;\n\tif (!((int)sv_player->v.flags & FL_GODMODE) )\n\t\tSV_ClientPrintf (\"godmode OFF\\n\");\n\telse\n\t\tSV_ClientPrintf (\"godmode ON\\n\");\n}\n\nvoid Host_Notarget_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tsv_player->v.flags = (int)sv_player->v.flags ^ FL_NOTARGET;\n\tif (!((int)sv_player->v.flags & FL_NOTARGET) )\n\t\tSV_ClientPrintf (\"notarget OFF\\n\");\n\telse\n\t\tSV_ClientPrintf (\"notarget ON\\n\");\n}\n\nbool noclip_anglehack;\n\nvoid Host_Noclip_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tif (sv_player->v.movetype != MOVETYPE_NOCLIP)\n\t{\n\t\tnoclip_anglehack = true;\n\t\tsv_player->v.movetype = MOVETYPE_NOCLIP;\n\t\tSV_ClientPrintf (\"noclip ON\\n\");\n\t}\n\telse\n\t{\n\t\tnoclip_anglehack = false;\n\t\tsv_player->v.movetype = MOVETYPE_WALK;\n\t\tSV_ClientPrintf (\"noclip OFF\\n\");\n\t}\n}\n\n/*\n==================\nHost_Fly_f\n\nSets client to flymode\n==================\n*/\nvoid Host_Fly_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tif (sv_player->v.movetype != MOVETYPE_FLY)\n\t{\n\t\tsv_player->v.movetype = MOVETYPE_FLY;\n\t\tSV_ClientPrintf (\"flymode ON\\n\");\n\t}\n\telse\n\t{\n\t\tsv_player->v.movetype = MOVETYPE_WALK;\n\t\tSV_ClientPrintf (\"flymode OFF\\n\");\n\t}\n}\n\n\n/*\n==================\nHost_Ping_f\n\n==================\n*/\nvoid Host_Ping_f (void)\n{\n\tint\t\ti, j;\n\tfloat\ttotal;\n\tclient_t\t*client;\n\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tSV_ClientPrintf (\"Client ping times:\\n\");\n\tfor (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)\n\t{\n\t\tif (!client->active)\n\t\t\tcontinue;\n\t\ttotal = 0;\n\t\tfor (j=0 ; j<NUM_PING_TIMES ; j++)\n\t\t\ttotal+=client->ping_times[j];\n\t\ttotal /= NUM_PING_TIMES;\n\t\tSV_ClientPrintf (\"%4i %s\\n\", (int)(total*1000), client->name);\n\t}\n}\n\n/*\n===============================================================================\n\nSERVER TRANSITIONS\n\n===============================================================================\n*/\n\n\n/*\n======================\nHost_Map_f\n\nhandle a\nmap <servername>\ncommand from the console.  Active clients are kicked off.\n======================\n*/\nvoid Host_Map_f (void)\n{\n\tint\t\ti;\n\tchar\tname[MAX_QPATH];\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tcls.demonum = -1;\t\t// stop demo loop in case this fails\n\n\tCL_Disconnect ();\n\tHost_ShutdownServer(false);\n\n\tkey_dest = key_game;\t\t\t// remove console or menu\n\tSCR_BeginLoadingPlaque ();\n\n\tcls.mapstring[0] = 0;\n\tfor (i=0 ; i<Cmd_Argc() ; i++)\n\t{\n\t\tstrcat (cls.mapstring, Cmd_Argv(i));\n\t\tstrcat (cls.mapstring, \" \");\n\t}\n\tstrcat (cls.mapstring, \"\\n\");\n\n\tsvs.serverflags = 0;\t\t\t// haven't completed an episode yet\n\tstrcpy (name, Cmd_Argv(1));\n\tSV_SpawnServer (name);\n\n\tif (!sv.active)\n\t\treturn;\n\n\tif (cls.state != ca_dedicated)\n\t{\n\t\tstrcpy (cls.spawnparms, \"\");\n\n\t\tfor (i=2 ; i<Cmd_Argc() ; i++)\n\t\t{\n\t\t\tstrcat (cls.spawnparms, Cmd_Argv(i));\n\t\t\tstrcat (cls.spawnparms, \" \");\n\t\t}\n\n\t\tCmd_ExecuteString (\"connect local\", src_command);\n\t}\n}\n\n/*\n==================\nHost_Changelevel_f\n\nGoes to a new map, taking all clients along\n==================\n*/\nvoid Host_Changelevel_f (void)\n{\n\tchar\tlevel[MAX_QPATH];\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"changelevel <levelname> : continue game on a new level\\n\");\n\t\treturn;\n\t}\n\tif (!sv.active || cls.demoplayback)\n\t{\n\t\tCon_Printf (\"Only the server may changelevel\\n\");\n\t\treturn;\n\t}\n\tSV_SaveSpawnparms ();\n\tstrcpy (level, Cmd_Argv(1));\n\tSV_SpawnServer (level);\n}\n\n/*\n==================\nHost_Restart_f\n\nRestarts the current server for a dead player\n==================\n*/\nvoid Host_Restart_f (void)\n{\n\tchar\tmapname[MAX_QPATH];\n\n\tif (cls.demoplayback || !sv.active)\n\t\treturn;\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\tstrcpy (mapname, sv.name);\t// must copy out, because it gets cleared\n\t\t\t\t\t\t\t\t// in sv_spawnserver\n\tSV_SpawnServer (mapname);\n}\n\n/*\n==================\nHost_Reconnect_f\n\nThis command causes the client to wait for the signon messages again.\nThis is sent just before a server changes levels\n==================\n*/\nvoid Host_Reconnect_f (void)\n{\n\tSCR_BeginLoadingPlaque ();\n\tcls.signon = 0;\t\t// need new connection messages\n}\n\nextern char server_name[MAX_QPATH];\t// JPG 3.50\n\n/*\n=====================\nHost_Connect_f\n\nUser command to connect to server\n=====================\n*/\nvoid Host_Connect_f (void)\n{\n\tchar\tname[MAX_QPATH];\n\n\tcls.demonum = -1;\t\t// stop demo loop in case this fails\n\tif (cls.demoplayback)\n\t{\n\t\tCL_StopPlayback ();\n\t\tCL_Disconnect ();\n\t}\n\tstrcpy (name, Cmd_Argv(1));\n\tCL_EstablishConnection (name);\n\tHost_Reconnect_f ();\n\t\n\tstrcpy(server_name, name);\t// JPG 3.50\n}\n\n\n/*\n===============================================================================\n\nLOAD / SAVE GAME\n\n===============================================================================\n*/\n\n#define\tSAVEGAME_VERSION\t5\n\n/*\n===============\nHost_SavegameComment\n\nWrites a SAVEGAME_COMMENT_LENGTH character comment describing the current\n===============\n*/\nvoid Host_SavegameComment (char *text)\n{\n\tint\t\ti;\n\tchar\tkills[20];\n\n\tfor (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)\n\t\ttext[i] = ' ';\n\tmemcpy (text, cl.levelname, strlen(cl.levelname));\n\tsprintf (kills,\"kills:%3i/%3i\", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);\n\tmemcpy (text+22, kills, strlen(kills));\n// convert space to _ to make stdio happy\n\tfor (i=0 ; i<SAVEGAME_COMMENT_LENGTH ; i++)\n\t\tif (text[i] == ' ')\n\t\t\ttext[i] = '_';\n\ttext[SAVEGAME_COMMENT_LENGTH] = '\\0';\n}\n\n\n/*\n===============\nHost_Savegame_f\n===============\n*/\nvoid Host_Savegame_f (void)\n{\n\tchar\tname[256];\n\tFILE\t*f;\n\tint\t\ti;\n\tchar\tcomment[SAVEGAME_COMMENT_LENGTH+1];\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (!sv.active)\n\t{\n\t\tCon_Printf (\"Not playing a local game.\\n\");\n\t\treturn;\n\t}\n\n\tif (cl.intermission)\n\t{\n\t\tCon_Printf (\"Can't save in intermission.\\n\");\n\t\treturn;\n\t}\n\n\tif (svs.maxclients != 1)\n\t{\n\t\tCon_Printf (\"Can't save multiplayer games.\\n\");\n\t\treturn;\n\t}\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"save <savename> : save a game\\n\");\n\t\treturn;\n\t}\n\n\tif (strstr(Cmd_Argv(1), \"..\"))\n\t{\n\t\tCon_Printf (\"Relative pathnames are not allowed.\\n\");\n\t\treturn;\n\t}\n\n\tfor (i=0 ; i<svs.maxclients ; i++)\n\t{\n\t\tif (svs.clients[i].active && (svs.clients[i].edict->v.health <= 0) )\n\t\t{\n\t\t\tCon_Printf (\"Can't savegame with a dead player\\n\");\n\t\t\treturn;\n\t\t}\n\t}\n\n\tsprintf (name, \"%s/%s\", com_gamedir, Cmd_Argv(1));\n\tCOM_DefaultExtension (name, \".sav\");\n\n\tCon_Printf (\"Saving game to %s...\\n\", name);\n\tf = fopen (name, \"w\");\n\tif (!f)\n\t{\n\t\tCon_Printf (\"ERROR: couldn't open.\\n\");\n\t\treturn;\n\t}\n\n\tfprintf (f, \"%i\\n\", SAVEGAME_VERSION);\n\tHost_SavegameComment (comment);\n\tfprintf (f, \"%s\\n\", comment);\n\tfor (i=0 ; i<NUM_SPAWN_PARMS ; i++)\n\t\tfprintf (f, \"%f\\n\", svs.clients->spawn_parms[i]);\n\tfprintf (f, \"%d\\n\", current_skill);\n\tfprintf (f, \"%s\\n\", sv.name);\n\tfprintf (f, \"%f\\n\",sv.time);\n\n// write the light styles\n\n\tfor (i=0 ; i<MAX_LIGHTSTYLES ; i++)\n\t{\n\t\tif (sv.lightstyles[i])\n\t\t\tfprintf (f, \"%s\\n\", sv.lightstyles[i]);\n\t\telse\n\t\t\tfprintf (f,\"m\\n\");\n\t}\n\n\n\tED_WriteGlobals (f);\n\tfor (i=0 ; i<sv.num_edicts ; i++)\n\t{\n\t\tED_Write (f, EDICT_NUM(i));\n\t\tfflush (f);\n\t}\n\tfclose (f);\n\tCon_Printf (\"done.\\n\");\n}\n\n\n/*\n===============\nHost_Loadgame_f\n===============\n*/\nvoid Host_Loadgame_f (void)\n{\n\tprintf(\"Load Game\");\n\tchar\tname[MAX_OSPATH];\n\tFILE\t*f;\n\tchar\tmapname[MAX_QPATH];\n\tfloat\ttime, tfloat;\n\tchar*\tstr;\n\tchar*\tstart;\n\tint\t\ti, r;\n\tedict_t\t*ent;\n\tint\t\tentnum;\n\tint\t\tversion;\n\tfloat\tspawn_parms[NUM_SPAWN_PARMS];\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif (Cmd_Argc() != 2)\n\t{\n\t\tCon_Printf (\"load <savename> : load a game\\n\");\n\t\treturn;\n\t}\n\n\tcls.demonum = -1;\t\t// stop demo loop in case this fails\n\n\tsprintf (name, \"%s/%s\", com_gamedir, Cmd_Argv(1));\n\tCOM_DefaultExtension (name, \".sav\");\n\n// we can't call SCR_BeginLoadingPlaque, because too much stack space has\n// been used.  The menu calls it before stuffing loadgame command\n//\tSCR_BeginLoadingPlaque ();\n\n\tCon_Printf (\"Loading game from %s...\\n\", name);\n\tf = fopen (name, \"r\");\n\tif (!f)\n\t{\n\t\tCon_Printf (\"ERROR: couldn't open.\\n\");\n\t\treturn;\n\t}\n\n\tfscanf (f, \"%i\\n\", &version);\n\tif (version != SAVEGAME_VERSION)\n\t{\n\t\tfclose (f);\n\t\tCon_Printf (\"Savegame is version %i, not %i\\n\", version, SAVEGAME_VERSION);\n\t\treturn;\n\t}\n\n\tstr = Sys_BigStackAlloc(32768, \"Host_Loadgame_f\");\n\tfscanf (f, \"%s\\n\", str);\n\tfor (i=0 ; i<NUM_SPAWN_PARMS ; i++)\n\t\tfscanf (f, \"%f\\n\", &spawn_parms[i]);\n// this silliness is so we can load 1.06 save files, which have float skill values\n\tfscanf (f, \"%f\\n\", &tfloat);\n\tcurrent_skill = (int)(tfloat + 0.1);\n\tCvar_SetValue (\"skill\", (float)current_skill);\n\tCvar_SetValue (\"deathmatch\", 0);\n\tCvar_SetValue (\"coop\", 0);\n\tCvar_SetValue (\"teamplay\", 0);\n\n\tfscanf (f, \"%s\\n\",mapname);\n\tfscanf (f, \"%f\\n\",&time);\n\n\tCL_Disconnect_f ();\n\n\tSV_SpawnServer (mapname);\n\n\tif (!sv.active)\n\t{\n\t\tCon_Printf (\"Couldn't load map\\n\");\n\t\tSys_BigStackFree(32768, \"Host_Loadgame_f\");\n\t\treturn;\n\t}\n\tsv.paused = true;\t\t// pause until all clients connect\n\tsv.loadgame = true;\n\n// load the light styles\n\n\tfor (i=0 ; i<MAX_LIGHTSTYLES ; i++)\n\t{\n\t\tfscanf (f, \"%s\\n\", str);\n\t\tsv.lightstyles[i] = Hunk_Alloc (strlen(str)+1);\n\t\tstrcpy (sv.lightstyles[i], str);\n\t}\n\n// load the edicts out of the savegame file\n\tentnum = -1;\t\t// -1 is the globals\n\twhile (!feof(f))\n\t{\n\t\tfor (i=0 ; i < 32768 - 1 ; i++)\n\t\t{\n\t\t\tr = fgetc (f);\n\t\t\tif (r == EOF || !r)\n\t\t\t\tbreak;\n\t\t\tstr[i] = r;\n\t\t\tif (r == '}')\n\t\t\t{\n\t\t\t\ti++;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (i == 32768 - 1)\n\t\t\tSys_Error (\"Loadgame buffer overflow\");\n\t\tstr[i] = 0;\n\t\tstart = str;\n\t\tstart = COM_Parse(str);\n\t\tif (!com_token[0])\n\t\t\tbreak;\t\t// end of file\n\t\tif (strcmp(com_token,\"{\"))\n\t\t\tSys_Error (\"First token isn't a brace\");\n\n\t\tif (entnum == -1)\n\t\t{\t// parse the global vars\n\t\t\tED_ParseGlobals (start);\n\t\t}\n\t\telse\n\t\t{\t// parse an edict\n\n\t\t\tent = EDICT_NUM(entnum);\n\t\t\tmemset (&ent->v, 0, progs->entityfields * 4);\n\t\t\tent->free = false;\n\t\t\tED_ParseEdict (start, ent);\n\n\t\t// link it into the bsp tree\n\t\t\tif (!ent->free)\n\t\t\t\tSV_LinkEdict (ent, false);\n\t\t}\n\n\t\tentnum++;\n\t}\n\n\tsv.num_edicts = entnum;\n\tsv.time = time;\n\n\tfclose (f);\n\n\tfor (i=0 ; i<NUM_SPAWN_PARMS ; i++)\n\t\tsvs.clients->spawn_parms[i] = spawn_parms[i];\n\n\tif (cls.state != ca_dedicated)\n\t{\n\t\tCL_EstablishConnection (\"local\");\n\t\tHost_Reconnect_f ();\n\t}\n\n\tSys_BigStackFree(32768, \"Host_Loadgame_f\");\n}\n\n//============================================================================\n\n/*\n======================\nHost_Name_f\n======================\n*/\nvoid Host_Name_f (void)\n{\n\tint a;\n\tchar\t*newName;\n\n\tif (Cmd_Argc () == 1)\n\t{\n\t\tCon_Printf (\"\\\"name\\\" is \\\"%s\\\"\\n\", cl_name.string);\n\t\treturn;\n\t}\n\tif (Cmd_Argc () == 2)\n\t\tnewName = Cmd_Argv(1);\n\telse\n\t\tnewName = Cmd_Args();\n\tnewName[15] = 0;\n\n\t// JPG 3.02 - remove bad characters\n\tfor (a = 0 ; newName[a] ; a++)\n\t{\n\t\tif (newName[a] == 10)\n\t\t\tnewName[a] = ' ';\n\t\telse if (newName[a] == 13)\n\t\t\tnewName[a] += 128;\n\t}\n\n\tif (cmd_source == src_command)\n\t{\n\t\tif (strcmp(cl_name.string, newName) == 0)\n\t\t\treturn;\n\t\tCvar_Set (\"_cl_name\", newName);\n\t\tif (cls.state == ca_connected)\n\t\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (host_client->name[0] && strcmp(host_client->name, \"unconnected\") )\n\t\tif (strcmp(host_client->name, newName) != 0)\n\t\t\tCon_Printf (\"%s renamed to %s\\n\", host_client->name, newName);\n\tstrcpy (host_client->name, newName);\n\thost_client->edict->v.netname = host_client->name - pr_strings;\n\n// send notification to all clients\n\n\tMSG_WriteByte (&sv.reliable_datagram, svc_updatename);\n\tMSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);\n\tMSG_WriteString (&sv.reliable_datagram, host_client->name);\n}\n\n\nvoid Host_Version_f (void)\n{\n\tCon_Printf (\"%s - Version %4.2f (GIT: %s)\\n\", ENGINE_NAME, VERSION, GIT_VERSION);\n\tCon_Printf (\"Compiled: \"__TIME__\" \"__DATE__\"\\n\");\n\tCon_Printf (\"ProQuake protocol: %4.2f. \\n\", VERSION_PROQUAKE);\n}\n\n#ifdef IDGODS\nvoid Host_Please_f (void)\n{\n\tclient_t *cl;\n\tint\t\t\tj;\n\n\tif (cmd_source != src_command)\n\t\treturn;\n\n\tif ((Cmd_Argc () == 3) && strcmp(Cmd_Argv(1), \"#\") == 0)\n\t{\n\t\tj = atof(Cmd_Argv(2)) - 1;\n\t\tif (j < 0 || j >= svs.maxclients)\n\t\t\treturn;\n\t\tif (!svs.clients[j].active)\n\t\t\treturn;\n\t\tcl = &svs.clients[j];\n\t\tif (cl->privileged)\n\t\t{\n\t\t\tcl->privileged = false;\n\t\t\tcl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);\n\t\t\tcl->edict->v.movetype = MOVETYPE_WALK;\n\t\t\tnoclip_anglehack = false;\n\t\t}\n\t\telse\n\t\t\tcl->privileged = true;\n\t}\n\n\tif (Cmd_Argc () != 2)\n\t\treturn;\n\n\tfor (j=0, cl = svs.clients ; j<svs.maxclients ; j++, cl++)\n\t{\n\t\tif (!cl->active)\n\t\t\tcontinue;\n\t\tif (strcasecmp(cl->name, Cmd_Argv(1)) == 0)\n\t\t{\n\t\t\tif (cl->privileged)\n\t\t\t{\n\t\t\t\tcl->privileged = false;\n\t\t\t\tcl->edict->v.flags = (int)cl->edict->v.flags & ~(FL_GODMODE|FL_NOTARGET);\n\t\t\t\tcl->edict->v.movetype = MOVETYPE_WALK;\n\t\t\t\tnoclip_anglehack = false;\n\t\t\t}\n\t\t\telse\n\t\t\t\tcl->privileged = true;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n#endif\n\n\nvoid Host_Say(bool teamonly)\n{\n\tclient_t *client;\n\tclient_t *save;\n\tint\t\tj;\n\tchar\t*p;\n\tunsigned char\ttext[64];\n\tbool\tfromServer = false;\n\n\tif (cmd_source == src_command)\n\t{\n\t\tif (cls.state == ca_dedicated)\n\t\t{\n\t\t\tfromServer = true;\n\t\t\tteamonly = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tCmd_ForwardToServer ();\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (Cmd_Argc () < 2)\n\t\treturn;\n\n\tsave = host_client;\n\n\tp = Cmd_Args();\n// remove quotes if present\n\tif (*p == '\"')\n\t{\n\t\tp++;\n\t\tp[strlen(p)-1] = 0;\n\t}\n\n// turn on color set 1\n\tif (!fromServer)\n\t\tsprintf (text, \"%c%s: \", 1, save->name);\n\telse\n\t\tsprintf (text, \"%c<%s> \", 1, hostname.string);\n\n\tj = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator\n\tif (strlen(p) > j)\n\t\tp[j] = 0;\n\n\tstrcat (text, p);\n\tstrcat (text, \"\\n\");\n\n\tfor (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)\n\t{\n\t\tif (!client || !client->active || !client->spawned)\n\t\t\tcontinue;\n\t\tif (teamplay.value && teamonly && client->edict->v.team != save->edict->v.team)\n\t\t\tcontinue;\n\t\thost_client = client;\n\t\tSV_ClientPrintf(\"%s\", text);\n\t}\n\thost_client = save;\n\n\tSys_Printf(\"%s\", &text[1]);\n}\n\n\nvoid Host_Say_f(void)\n{\n\tHost_Say(false);\n}\n\n\nvoid Host_Say_Team_f(void)\n{\n\tHost_Say(true);\n}\n\n\nvoid Host_Tell_f(void)\n{\n\tclient_t *client;\n\tclient_t *save;\n\tint\t\tj;\n\tchar\t*p;\n\tchar\ttext[64];\n\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (Cmd_Argc () < 3)\n\t\treturn;\n\n\tstrcpy(text, host_client->name);\n\tstrcat(text, \": \");\n\n\tp = Cmd_Args();\n\n// remove quotes if present\n\tif (*p == '\"')\n\t{\n\t\tp++;\n\t\tp[strlen(p)-1] = 0;\n\t}\n\n// check length & truncate if necessary\n\tj = sizeof(text) - 2 - strlen(text);  // -2 for /n and null terminator\n\tif (strlen(p) > j)\n\t\tp[j] = 0;\n\n\tstrcat (text, p);\n\tstrcat (text, \"\\n\");\n\n\tsave = host_client;\n\tfor (j = 0, client = svs.clients; j < svs.maxclients; j++, client++)\n\t{\n\t\tif (!client->active || !client->spawned)\n\t\t\tcontinue;\n\t\tif (strcasecmp(client->name, Cmd_Argv(1)))\n\t\t\tcontinue;\n\t\thost_client = client;\n\t\tSV_ClientPrintf(\"%s\", text);\n\t\tbreak;\n\t}\n\thost_client = save;\n}\n\n\n/*\n==================\nHost_Color_f\n==================\n*/\nvoid Host_Color_f(void)\n{\n\tint\t\ttop, bottom;\n\tint\t\tplayercolor;\n\n\tif (Cmd_Argc() == 1)\n\t{\n\t\tCon_Printf (\"\\\"color\\\" is \\\"%i %i\\\"\\n\", ((int)cl_color.value) >> 4, ((int)cl_color.value) & 0x0f);\n\t\tCon_Printf (\"color <0-13> [0-13]\\n\");\n\t\treturn;\n\t}\n\n\tif (Cmd_Argc() == 2)\n\t\ttop = bottom = atoi(Cmd_Argv(1));\n\telse\n\t{\n\t\ttop = atoi(Cmd_Argv(1));\n\t\tbottom = atoi(Cmd_Argv(2));\n\t}\n\n\ttop &= 15;\n\tif (top > 13)\n\t\ttop = 13;\n\tbottom &= 15;\n\tif (bottom > 13)\n\t\tbottom = 13;\n\n\tplayercolor = top*16 + bottom;\n\n\tif (cmd_source == src_command)\n\t{\n\t\tCvar_SetValue (\"_cl_color\", playercolor);\n\t\tif (cls.state == ca_connected)\n\t\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\thost_client->colors = playercolor;\n\thost_client->edict->v.team = bottom + 1;\n\n// send notification to all clients\n\tMSG_WriteByte (&sv.reliable_datagram, svc_updatecolors);\n\tMSG_WriteByte (&sv.reliable_datagram, host_client - svs.clients);\n\tMSG_WriteByte (&sv.reliable_datagram, host_client->colors);\n}\n\n/*\n==================\nHost_Kill_f\n==================\n*/\nvoid Host_Kill_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (sv_player->v.health <= 0)\n\t{\n\t\tSV_ClientPrintf (\"Can't suicide -- already dead!\\n\");\n\t\treturn;\n\t}\n\n\tpr_global_struct->time = sv.time;\n\tpr_global_struct->self = EDICT_TO_PROG(sv_player);\n\tPR_ExecuteProgram (pr_global_struct->ClientKill);\n}\n\n\n/*\n==================\nHost_Pause_f\n==================\n*/\nvoid Host_Pause_f (void)\n{\n\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\tif (!pausable.value)\n\t\tSV_ClientPrintf (\"Pause not allowed.\\n\");\n\telse\n\t{\n\t\tsv.paused ^= 1;\n\n\t\tif (svs.maxclients > 1)\n\t\t\tSV_BroadcastPrintf (\"%s %s the game\\n\", pr_strings + sv_player->v.netname, sv.paused ? \"paused\":\"unpaused\");\n\n\t// send notification to all clients\n\t\tMSG_WriteByte (&sv.reliable_datagram, svc_setpause);\n\t\tMSG_WriteByte (&sv.reliable_datagram, sv.paused);\n\t}\n}\n\n//===========================================================================\n\n\n/*\n==================\nHost_PreSpawn_f\n==================\n*/\nvoid Host_PreSpawn_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCon_Printf (\"prespawn is not valid from the console\\n\");\n\t\treturn;\n\t}\n\n\tif (host_client->spawned)\n\t{\n\t\tCon_Printf (\"prespawn not valid -- already spawned\\n\");\n\t\treturn;\n\t}\n\n\tSZ_Write (&host_client->message, sv.signon.data, sv.signon.cursize);\n\tMSG_WriteByte (&host_client->message, svc_signonnum);\n\tMSG_WriteByte (&host_client->message, 2);\n\thost_client->sendsignon = true;\n}\n\n/*\n==================\nHost_Spawn_f\n==================\n*/\nvoid Host_Spawn_f (void)\n{\n\tint\t\ti;\n\tclient_t\t*client;\n\tedict_t\t*ent;\n\tfloat *sendangle;\n\t\n\tif (cmd_source == src_command)\n\t{\n\t\tCon_Printf (\"spawn is not valid from the console\\n\");\n\t\treturn;\n\t}\n\n\tif (host_client->spawned)\n\t{\n\t\tCon_Printf (\"Spawn not valid -- already spawned\\n\");\n\t\treturn;\n\t}\n\n// run the entrance script\n\tif (sv.loadgame)\n\t{\t// loaded games are fully inited already\n\t\t// if this is the last client to be connected, unpause\n\t\tsv.paused = false;\n\t}\n\telse\n\t{\n\t\t// set up the edict\n\t\tent = host_client->edict;\n\n\t\tmemset (&ent->v, 0, progs->entityfields * 4);\n\t\tent->v.colormap = NUM_FOR_EDICT(ent);\n\t\tent->v.team = (host_client->colors & 15) + 1;\n\t\tent->v.netname = host_client->name - pr_strings;\n\n\t\t// copy spawn parms out of the client_t\n\n\t\tfor (i=0 ; i< NUM_SPAWN_PARMS ; i++)\n\t\t\t(&pr_global_struct->parm1)[i] = host_client->spawn_parms[i];\n\n\t\t// call the spawn function\n\n\t\tpr_global_struct->time = sv.time;\n\t\tpr_global_struct->self = EDICT_TO_PROG(sv_player);\n\t\tPR_ExecuteProgram (pr_global_struct->ClientConnect);\n\n\t\tif ((Sys_FloatTime() - host_client->netconnection->connecttime) <= sv.time)\n\t\t\tSys_Printf (\"%s entered the game\\n\", host_client->name);\n\n\t\tPR_ExecuteProgram (pr_global_struct->PutClientInServer);\n\t}\n\n\n// send all current names, colors, and frag counts\n\tSZ_Clear (&host_client->message);\n\n// send time of update\n\tMSG_WriteByte (&host_client->message, svc_time);\n\tMSG_WriteFloat (&host_client->message, sv.time);\n\n\tfor (i=0, client = svs.clients ; i<svs.maxclients ; i++, client++)\n\t{\n\t\tMSG_WriteByte (&host_client->message, svc_updatename);\n\t\tMSG_WriteByte (&host_client->message, i);\n\t\tMSG_WriteString (&host_client->message, client->name);\n\t\tMSG_WriteByte (&host_client->message, svc_updatefrags);\n\t\tMSG_WriteByte (&host_client->message, i);\n\t\tMSG_WriteShort (&host_client->message, client->old_frags);\n\t\tMSG_WriteByte (&host_client->message, svc_updatecolors);\n\t\tMSG_WriteByte (&host_client->message, i);\n\t\tMSG_WriteByte (&host_client->message, client->colors);\n\t}\n\n// send all current light styles\n\tfor (i=0 ; i<MAX_LIGHTSTYLES ; i++)\n\t{\n\t\tMSG_WriteByte (&host_client->message, svc_lightstyle);\n\t\tMSG_WriteByte (&host_client->message, (char)i);\n\t\tMSG_WriteString (&host_client->message, sv.lightstyles[i]);\n\t}\n\n//\n// send some stats\n//\n\tMSG_WriteByte (&host_client->message, svc_updatestat);\n\tMSG_WriteByte (&host_client->message, STAT_TOTALSECRETS);\n\tMSG_WriteLong (&host_client->message, pr_global_struct->total_secrets);\n\n\tMSG_WriteByte (&host_client->message, svc_updatestat);\n\tMSG_WriteByte (&host_client->message, STAT_TOTALMONSTERS);\n\tMSG_WriteLong (&host_client->message, pr_global_struct->total_monsters);\n\n\tMSG_WriteByte (&host_client->message, svc_updatestat);\n\tMSG_WriteByte (&host_client->message, STAT_SECRETS);\n\tMSG_WriteLong (&host_client->message, pr_global_struct->found_secrets);\n\n\tMSG_WriteByte (&host_client->message, svc_updatestat);\n\tMSG_WriteByte (&host_client->message, STAT_MONSTERS);\n\tMSG_WriteLong (&host_client->message, pr_global_struct->killed_monsters);\n\n\n//\n// send a fixangle\n// Never send a roll angle, because savegames can catch the server\n// in a state where it is expecting the client to correct the angle\n// and it won't happen if the game was just loaded, so you wind up\n// with a permanent head tilt\n\tent = EDICT_NUM( 1 + (host_client - svs.clients) );\n\tMSG_WriteByte (&host_client->message, svc_setangle);\n\tsendangle = sv.loadgame ? ent->v.v_angle : ent->v.angles;\n\tfor (i=0 ; i < 2 ; i++)\n\t\tMSG_WriteAngle (&host_client->message, sendangle[i]);\n\tMSG_WriteAngle (&host_client->message, 0 );\n\n\tSV_WriteClientdataToMessage (sv_player, &host_client->message);\n\n\tMSG_WriteByte (&host_client->message, svc_signonnum);\n\tMSG_WriteByte (&host_client->message, 3);\n\thost_client->sendsignon = true;\n}\n\n/*\n==================\nHost_Begin_f\n==================\n*/\nvoid Host_Begin_f (void)\n{\n\tif (cmd_source == src_command)\n\t{\n\t\tCon_Printf (\"begin is not valid from the console\\n\");\n\t\treturn;\n\t}\n\n\thost_client->spawned = true;\n}\n\n//===========================================================================\n\n\n/*\n==================\nHost_Kick_f\n\nKicks a user off of the server\n==================\n*/\nvoid Host_Kick_f (void)\n{\n\tchar\t\t*who;\n\tchar\t\t*message = NULL;\n\tclient_t\t*save;\n\tint\t\t\ti;\n\tbool\tbyNumber = false;\n\n\tif (cmd_source == src_command)\n\t{\n\t\tif (!sv.active)\n\t\t{\n\t\t\tCmd_ForwardToServer ();\n\t\t\treturn;\n\t\t}\n\t}\n\telse if (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tsave = host_client;\n\n\tif (Cmd_Argc() > 2 && strcmp(Cmd_Argv(1), \"#\") == 0)\n\t{\n\t\ti = atof(Cmd_Argv(2)) - 1;\n\t\tif (i < 0 || i >= svs.maxclients)\n\t\t\treturn;\n\t\tif (!svs.clients[i].active)\n\t\t\treturn;\n\t\thost_client = &svs.clients[i];\n\t\tbyNumber = true;\n\t}\n\telse\n\t{\n\t\tfor (i = 0, host_client = svs.clients; i < svs.maxclients; i++, host_client++)\n\t\t{\n\t\t\tif (!host_client->active)\n\t\t\t\tcontinue;\n\t\t\tif (strcasecmp(host_client->name, Cmd_Argv(1)) == 0)\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\tif (i < svs.maxclients)\n\t{\n\t\tif (cmd_source == src_command)\n\t\t\tif (cls.state == ca_dedicated)\n\t\t\t\twho = \"Console\";\n\t\t\telse\n\t\t\t\twho = cl_name.string;\n\t\telse\n\t\t\twho = save->name;\n\n\t\t// can't kick yourself!\n\t\tif (host_client == save)\n\t\t\treturn;\n\n\t\tif (Cmd_Argc() > 2)\n\t\t{\n\t\t\tmessage = COM_Parse(Cmd_Args());\n\t\t\tif (byNumber)\n\t\t\t{\n\t\t\t\tmessage++;\t\t\t\t\t\t\t// skip the #\n\t\t\t\twhile (*message == ' ')\t\t\t\t// skip white space\n\t\t\t\t\tmessage++;\n\t\t\t\tmessage += strlen(Cmd_Argv(2));\t// skip the number\n\t\t\t}\n\t\t\twhile (*message && *message == ' ')\n\t\t\t\tmessage++;\n\t\t}\n\t\tif (message)\n\t\t\tSV_ClientPrintf (\"Kicked by %s: %s\\n\", who, message);\n\t\telse\n\t\t\tSV_ClientPrintf (\"Kicked by %s\\n\", who);\n\t\tSV_DropClient (false);\n\t}\n\n\thost_client = save;\n}\n\n/*\n===============================================================================\n\nDEBUGGING TOOLS\n\n===============================================================================\n*/\n\n/*\n==================\nHost_Give_f\n==================\n*/\nvoid Host_Give_f (void)\n{\n\tchar\t*t;\n\tint\t\tv, w;\n\teval_t\t*val;\n\n\tif (cmd_source == src_command)\n\t{\n\t\tCmd_ForwardToServer ();\n\t\treturn;\n\t}\n\n\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\treturn;\n\n\tt = Cmd_Argv(1);\n\tv = atoi (Cmd_Argv(2));\n\n\tswitch (t[0])\n\t{\n   case '0':\n   case '1':\n   case '2':\n   case '3':\n   case '4':\n   case '5':\n   case '6':\n   case '7':\n   case '8':\n   case '9':\n      // MED 01/04/97 added hipnotic give stuff\n      if (hipnotic)\n      {\n         if (t[0] == '6')\n         {\n            if (t[1] == 'a')\n               sv_player->v.items = (int)sv_player->v.items | HIT_PROXIMITY_GUN;\n            else\n               sv_player->v.items = (int)sv_player->v.items | IT_GRENADE_LAUNCHER;\n         }\n         else if (t[0] == '9')\n            sv_player->v.items = (int)sv_player->v.items | HIT_LASER_CANNON;\n         else if (t[0] == '0')\n            sv_player->v.items = (int)sv_player->v.items | HIT_MJOLNIR;\n         else if (t[0] >= '2')\n            sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));\n      }\n      else\n      {\n         if (t[0] >= '2')\n            sv_player->v.items = (int)sv_player->v.items | (IT_SHOTGUN << (t[0] - '2'));\n      }\n\t\tbreak;\n\n    case 's':\n\t\tif (rogue)\n\t\t{\n\t        val = GetEdictFieldValue(sv_player, \"ammo_shells1\");\n\t\t    if (val)\n\t\t\t    val->_float = v;\n\t\t}\n\n        sv_player->v.ammo_shells = v;\n        break;\n    case 'n':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_nails1\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon <= IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_nails = v;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsv_player->v.ammo_nails = v;\n\t\t}\n        break;\n    case 'l':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_lava_nails\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon > IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_nails = v;\n\t\t\t}\n\t\t}\n        break;\n    case 'r':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_rockets1\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon <= IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_rockets = v;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsv_player->v.ammo_rockets = v;\n\t\t}\n        break;\n    case 'm':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_multi_rockets\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon > IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_rockets = v;\n\t\t\t}\n\t\t}\n        break;\n    case 'h':\n        sv_player->v.health = v;\n        break;\n    case 'c':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_cells1\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon <= IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_cells = v;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsv_player->v.ammo_cells = v;\n\t\t}\n        break;\n    case 'p':\n\t\tif (rogue)\n\t\t{\n\t\t\tval = GetEdictFieldValue(sv_player, \"ammo_plasma\");\n\t\t\tif (val)\n\t\t\t{\n\t\t\t\tval->_float = v;\n\t\t\t\tif (sv_player->v.weapon > IT_LIGHTNING)\n\t\t\t\t\tsv_player->v.ammo_cells = v;\n\t\t\t}\n\t\t}\n        break;\n    }\n}\n\nedict_t\t*FindViewthing (void)\n{\n\tint\t\ti;\n\tedict_t\t*e;\n\n\tfor (i=0 ; i<sv.num_edicts ; i++)\n\t{\n\t\te = EDICT_NUM(i);\n\t\tif ( !strcmp (pr_strings + e->v.classname, \"viewthing\") )\n\t\t\treturn e;\n\t}\n\tCon_Printf (\"No viewthing on map\\n\");\n\treturn NULL;\n}\n\n/*\n==================\nHost_Viewmodel_f\n==================\n*/\nvoid Host_Viewmodel_f (void)\n{\n\tedict_t\t*e;\n\tmodel_t\t*m;\n\n\te = FindViewthing ();\n\tif (!e)\n\t\treturn;\n\n\tm = Mod_ForName (Cmd_Argv(1), false);\n\tif (!m)\n\t{\n\t\tCon_Printf (\"Can't load %s\\n\", Cmd_Argv(1));\n\t\treturn;\n\t}\n\n\te->v.frame = 0;\n\tcl.model_precache[(int)e->v.modelindex] = m;\n}\n\n/*\n==================\nHost_Viewframe_f\n==================\n*/\nvoid Host_Viewframe_f (void)\n{\n\tedict_t\t*e;\n\tint\t\tf;\n\tmodel_t\t*m;\n\n\te = FindViewthing ();\n\tif (!e)\n\t\treturn;\n\tm = cl.model_precache[(int)e->v.modelindex];\n\n\tf = atoi(Cmd_Argv(1));\n\tif (f >= m->numframes)\n\t\tf = m->numframes-1;\n\n\te->v.frame = f;\n}\n\n\nvoid PrintFrameName (model_t *m, int frame)\n{\n\taliashdr_t \t\t\t*hdr;\n\tmaliasframedesc_t\t*pframedesc;\n\n\thdr = (aliashdr_t *)Mod_Extradata (m);\n\tif (!hdr)\n\t\treturn;\n\tpframedesc = &hdr->frames[frame];\n\n\tCon_Printf (\"frame %i: %s\\n\", frame, pframedesc->name);\n}\n\n/*\n==================\nHost_Viewnext_f\n==================\n*/\nvoid Host_Viewnext_f (void)\n{\n\tedict_t\t*e;\n\tmodel_t\t*m;\n\n\te = FindViewthing ();\n\tif (!e)\n\t\treturn;\n\tm = cl.model_precache[(int)e->v.modelindex];\n\n\te->v.frame = e->v.frame + 1;\n\tif (e->v.frame >= m->numframes)\n\t\te->v.frame = m->numframes - 1;\n\n\tPrintFrameName (m, e->v.frame);\n}\n\n/*\n==================\nHost_Viewprev_f\n==================\n*/\nvoid Host_Viewprev_f (void)\n{\n\tedict_t\t*e;\n\tmodel_t\t*m;\n\n\te = FindViewthing ();\n\tif (!e)\n\t\treturn;\n\n\tm = cl.model_precache[(int)e->v.modelindex];\n\n\te->v.frame = e->v.frame - 1;\n\tif (e->v.frame < 0)\n\t\te->v.frame = 0;\n\n\tPrintFrameName (m, e->v.frame);\n}\n\n/*\n===============================================================================\n\nDEMO LOOP CONTROL\n\n===============================================================================\n*/\n\n\n/*\n==================\nHost_Startdemos_f\n==================\n*/\nvoid Host_Startdemos_f (void)\n{\n\tint\t\ti, c;\n\n\tif (cls.state == ca_dedicated)\n\t{\n\t\tif (!sv.active)\n\t\t\tCbuf_AddText (\"map start\\n\");\n\t\treturn;\n\t}\n\n\tc = Cmd_Argc() - 1;\n\tif (c > MAX_DEMOS)\n\t{\n\t\tCon_Printf (\"Max %i demos in demoloop\\n\", MAX_DEMOS);\n\t\tc = MAX_DEMOS;\n\t}\n\tCon_Printf (\"%i demo(s) in loop\\n\", c);\n\n\tfor (i=1 ; i<c+1 ; i++)\n\t\tstrncpy (cls.demos[i-1], Cmd_Argv(i), sizeof(cls.demos[0])-1);\n\n\tif (!sv.active && cls.demonum != -1 && !cls.demoplayback)\n\t{\n\t\tcls.demonum = 0;\n\t\tCL_NextDemo ();\n\t}\n\telse\n\t\tcls.demonum = -1;\n}\n\n\n/*\n==================\nHost_Demos_f\n\nReturn to looping demos\n==================\n*/\nvoid Host_Demos_f (void)\n{\n\tif (cls.state == ca_dedicated)\n\t\treturn;\n\tif (cls.demonum == -1)\n\t\tcls.demonum = 1;\n\tCL_Disconnect_f ();\n\tCL_NextDemo ();\n}\n\n/*\n==================\nHost_Stopdemo_f\n\nReturn to looping demos\n==================\n*/\nvoid Host_Stopdemo_f (void)\n{\n\tif (cls.state == ca_dedicated)\n\t\treturn;\n\tif (!cls.demoplayback)\n\t\treturn;\n\tCL_StopPlayback ();\n\tCL_Disconnect ();\n}\n\n//=============================================================================\n\n/*\n==================\nHost_InitCommands\n==================\n*/\nvoid Host_InitCommands (void)\n{\n\tCmd_AddCommand (\"game\", Host_Game_f); //johnfitz\n\t\n\tCmd_AddCommand (\"status\", Host_Status_f);\n\tCmd_AddCommand (\"quit\", Host_Quit_f);\n\tCmd_AddCommand (\"god\", Host_God_f);\n\tCmd_AddCommand (\"notarget\", Host_Notarget_f);\n\tCmd_AddCommand (\"fly\", Host_Fly_f);\n\tCmd_AddCommand (\"map\", Host_Map_f);\n\tCmd_AddCommand (\"restart\", Host_Restart_f);\n\tCmd_AddCommand (\"changelevel\", Host_Changelevel_f);\n\tCmd_AddCommand (\"connect\", Host_Connect_f);\n\tCmd_AddCommand (\"reconnect\", Host_Reconnect_f);\n\tCmd_AddCommand (\"name\", Host_Name_f);\n\tCmd_AddCommand (\"noclip\", Host_Noclip_f);\n\tCmd_AddCommand (\"version\", Host_Version_f);\n\t\n\tCmd_AddCommand (\"say\", Host_Say_f);\n\tCmd_AddCommand (\"say_team\", Host_Say_Team_f);\n\tCmd_AddCommand (\"tell\", Host_Tell_f);\n\tCmd_AddCommand (\"color\", Host_Color_f);\n\tCmd_AddCommand (\"kill\", Host_Kill_f);\n\tCmd_AddCommand (\"pause\", Host_Pause_f);\n\tCmd_AddCommand (\"spawn\", Host_Spawn_f);\n\tCmd_AddCommand (\"begin\", Host_Begin_f);\n\tCmd_AddCommand (\"prespawn\", Host_PreSpawn_f);\n\tCmd_AddCommand (\"kick\", Host_Kick_f);\n\tCmd_AddCommand (\"ping\", Host_Ping_f);\n\tCmd_AddCommand (\"load\", Host_Loadgame_f);\n\tCmd_AddCommand (\"save\", Host_Savegame_f);\n\tCmd_AddCommand (\"give\", Host_Give_f);\n\n\tCmd_AddCommand (\"startdemos\", Host_Startdemos_f);\n\tCmd_AddCommand (\"demos\", Host_Demos_f);\n\tCmd_AddCommand (\"stopdemo\", Host_Stopdemo_f);\n\n\tCmd_AddCommand (\"viewmodel\", Host_Viewmodel_f);\n\tCmd_AddCommand (\"viewframe\", Host_Viewframe_f);\n\tCmd_AddCommand (\"viewnext\", Host_Viewnext_f);\n\tCmd_AddCommand (\"viewprev\", Host_Viewprev_f);\n\t\n\tCmd_AddCommand (\"saveconfig\", Host_WriteConfig_f);\t// dp cfg compat\n\tCmd_AddCommand (\"writeconfig\", Host_WriteConfig_f);\t// by joe\n\n\tCmd_AddCommand (\"mcache\", Mod_Print);\n}\n"
  },
  {
    "path": "source/image.c",
    "content": "/*\nCopyright (C) 1996-2001 Id Software, Inc.\nCopyright (C) 2002-2009 John Fitzgibbons and others\nCopyright (C) 2010-2014 QuakeSpasm developers\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//image.c -- image loading\n\n#include \"quakedef.h\"\n\nstatic char loadfilename[MAX_OSPATH]; //file scope so that error messages can use it\n\ntypedef struct stdio_buffer_s {\n\tFILE *f;\n\tunsigned char buffer[1024];\n\tint size;\n\tint pos;\n} stdio_buffer_t;\n\nstatic stdio_buffer_t *Buf_Alloc(FILE *f)\n{\n\tstdio_buffer_t *buf = (stdio_buffer_t *) calloc(1, sizeof(stdio_buffer_t));\n\tbuf->f = f;\n\treturn buf;\n}\n\nstatic void Buf_Free(stdio_buffer_t *buf)\n{\n\tfree(buf);\n}\n\nstatic inline int Buf_GetC(stdio_buffer_t *buf)\n{\n\tif (buf->pos >= buf->size)\n\t{\n\t\tbuf->size = fread(buf->buffer, 1, sizeof(buf->buffer), buf->f);\n\t\tbuf->pos = 0;\n\t\t\n\t\tif (buf->size == 0)\n\t\t\treturn EOF;\n\t}\n\n\treturn buf->buffer[buf->pos++];\n}\n\n/*\n============\nImage_LoadImage\n\nreturns a pointer to hunk allocated RGBA data\n\nTODO: search order: tga png jpg pcx lmp\n============\n*/\nbyte *Image_LoadImage (const char *name, int *width, int *height)\n{\n\tFILE\t*f;\n\n\tsnprintf (loadfilename, sizeof(loadfilename), \"%s.tga\", name);\n\tCOM_FOpenFile (loadfilename, &f, NULL);\n\tif (f)\n\t\treturn Image_LoadTGA (f, width, height);\n\n\tsnprintf (loadfilename, sizeof(loadfilename), \"%s.pcx\", name);\n\tCOM_FOpenFile (loadfilename, &f, NULL);\n\tif (f)\n\t\treturn Image_LoadPCX (f, width, height);\n\n\treturn NULL;\n}\n\n//==============================================================================\n//\n//  TGA\n//\n//==============================================================================\n\ntypedef struct targaheader_s {\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_t;\n\n#define TARGAHEADERSIZE 18 //size on disk\n\ntargaheader_t targa_header;\n\nint fgetLittleShort (FILE *f)\n{\n\tbyte\tb1, b2;\n\n\tb1 = fgetc(f);\n\tb2 = fgetc(f);\n\n\treturn (short)(b1 + b2*256);\n}\n\nint fgetLittleLong (FILE *f)\n{\n\tbyte\tb1, b2, b3, b4;\n\n\tb1 = fgetc(f);\n\tb2 = fgetc(f);\n\tb3 = fgetc(f);\n\tb4 = fgetc(f);\n\n\treturn b1 + (b2<<8) + (b3<<16) + (b4<<24);\n}\n\n/*\n=============\nImage_LoadTGA\n=============\n*/\nbyte *Image_LoadTGA (FILE *fin, int *width, int *height)\n{\n\tint\t\t\t\tcolumns, rows, numPixels;\n\tbyte\t\t\t*pixbuf;\n\tint\t\t\t\trow, column;\n\tbyte\t\t\t*targa_rgba;\n\tint\t\t\t\trealrow; //johnfitz -- fix for upside-down targas\n\tbool\t\tupside_down; //johnfitz -- fix for upside-down targas\n\tstdio_buffer_t\t*buf;\n\n\ttarga_header.id_length = fgetc(fin);\n\ttarga_header.colormap_type = fgetc(fin);\n\ttarga_header.image_type = fgetc(fin);\n\n\ttarga_header.colormap_index = fgetLittleShort(fin);\n\ttarga_header.colormap_length = fgetLittleShort(fin);\n\ttarga_header.colormap_size = fgetc(fin);\n\ttarga_header.x_origin = fgetLittleShort(fin);\n\ttarga_header.y_origin = fgetLittleShort(fin);\n\ttarga_header.width = fgetLittleShort(fin);\n\ttarga_header.height = fgetLittleShort(fin);\n\ttarga_header.pixel_size = fgetc(fin);\n\ttarga_header.attributes = fgetc(fin);\n\n\tif (targa_header.image_type!=2 && targa_header.image_type!=10)\n\t\tSys_Error (\"Image_LoadTGA: %s is not a type 2 or type 10 targa\\n\", loadfilename);\n\n\tif (targa_header.colormap_type !=0 || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24))\n\t\tSys_Error (\"Image_LoadTGA: %s is not a 24bit or 32bit targa\\n\", loadfilename);\n\n\tcolumns = targa_header.width;\n\trows = targa_header.height;\n\tnumPixels = columns * rows;\n\tupside_down = !(targa_header.attributes & 0x20); //johnfitz -- fix for upside-down targas\n\n\ttarga_rgba = (byte *) malloc (numPixels*4);\n\n\tif (targa_header.id_length != 0)\n\t\tfseek(fin, targa_header.id_length, SEEK_CUR);  // skip TARGA image comment\n\n\tbuf = Buf_Alloc(fin);\n\n\tif (targa_header.image_type==2) // Uncompressed, RGB images\n\t{\n\t\tfor(row=rows-1; row>=0; row--)\n\t\t{\n\t\t\t//johnfitz -- fix for upside-down targas\n\t\t\trealrow = upside_down ? row : rows - 1 - row;\n\t\t\tpixbuf = targa_rgba + realrow*columns*4;\n\t\t\t//johnfitz\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\tcase 24:\n\t\t\t\t\tblue = Buf_GetC(buf);\n\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\tred = Buf_GetC(buf);\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_GetC(buf);\n\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\tred = Buf_GetC(buf);\n\t\t\t\t\talphabyte = Buf_GetC(buf);\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\t}\n\t\t\t}\n\t\t}\n\t}\n\telse if (targa_header.image_type==10) // Runlength encoded RGB images\n\t{\n\t\tunsigned char red,green,blue,alphabyte,packetHeader,packetSize,j;\n\t\tfor(row=rows-1; row>=0; row--)\n\t\t{\n\t\t\t//johnfitz -- fix for upside-down targas\n\t\t\trealrow = upside_down ? row : rows - 1 - row;\n\t\t\tpixbuf = targa_rgba + realrow*columns*4;\n\t\t\t//johnfitz\n\t\t\tfor(column=0; column<columns; )\n\t\t\t{\n\t\t\t\tpacketHeader=Buf_GetC(buf);\n\t\t\t\tpacketSize = 1 + (packetHeader & 0x7f);\n\t\t\t\tif (packetHeader & 0x80) // run-length packet\n\t\t\t\t{\n\t\t\t\t\tswitch (targa_header.pixel_size)\n\t\t\t\t\t{\n\t\t\t\t\tcase 24:\n\t\t\t\t\t\tblue = Buf_GetC(buf);\n\t\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\t\tred = Buf_GetC(buf);\n\t\t\t\t\t\talphabyte = 255;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 32:\n\t\t\t\t\t\tblue = Buf_GetC(buf);\n\t\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\t\tred = Buf_GetC(buf);\n\t\t\t\t\t\talphabyte = Buf_GetC(buf);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdefault: /* avoid compiler warnings */\n\t\t\t\t\t\tblue = red = green = alphabyte = 0;\n\t\t\t\t\t}\n\n\t\t\t\t\tfor(j=0;j<packetSize;j++)\n\t\t\t\t\t{\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{\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\t//johnfitz -- fix for upside-down targas\n\t\t\t\t\t\t\trealrow = upside_down ? row : rows - 1 - row;\n\t\t\t\t\t\t\tpixbuf = targa_rgba + realrow*columns*4;\n\t\t\t\t\t\t\t//johnfitz\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{\n\t\t\t\t\tfor(j=0;j<packetSize;j++)\n\t\t\t\t\t{\n\t\t\t\t\t\tswitch (targa_header.pixel_size)\n\t\t\t\t\t\t{\n\t\t\t\t\t\tcase 24:\n\t\t\t\t\t\t\tblue = Buf_GetC(buf);\n\t\t\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\t\t\tred = Buf_GetC(buf);\n\t\t\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t\t\t*pixbuf++ = 255;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase 32:\n\t\t\t\t\t\t\tblue = Buf_GetC(buf);\n\t\t\t\t\t\t\tgreen = Buf_GetC(buf);\n\t\t\t\t\t\t\tred = Buf_GetC(buf);\n\t\t\t\t\t\t\talphabyte = Buf_GetC(buf);\n\t\t\t\t\t\t\t*pixbuf++ = red;\n\t\t\t\t\t\t\t*pixbuf++ = green;\n\t\t\t\t\t\t\t*pixbuf++ = blue;\n\t\t\t\t\t\t\t*pixbuf++ = alphabyte;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tdefault: /* avoid compiler warnings */\n\t\t\t\t\t\t\tblue = red = green = alphabyte = 0;\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{\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\t//johnfitz -- fix for upside-down targas\n\t\t\t\t\t\t\trealrow = upside_down ? row : rows - 1 - row;\n\t\t\t\t\t\t\tpixbuf = targa_rgba + realrow*columns*4;\n\t\t\t\t\t\t\t//johnfitz\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\tbreakOut:;\n\t\t}\n\t}\n\n\tBuf_Free(buf);\n\tfclose(fin);\n\n\t*width = (int)(targa_header.width);\n\t*height = (int)(targa_header.height);\n\treturn targa_rgba;\n}\n\n//==============================================================================\n//\n//  PCX\n//\n//==============================================================================\n\ntypedef struct\n{\n    char\t\t\tsignature;\n    char\t\t\tversion;\n    char\t\t\tencoding;\n    char\t\t\tbits_per_pixel;\n    unsigned short\txmin,ymin,xmax,ymax;\n    unsigned short\thdpi,vdpi;\n    byte\t\t\tcolortable[48];\n    char\t\t\treserved;\n    char\t\t\tcolor_planes;\n    unsigned short\tbytes_per_line;\n    unsigned short\tpalette_type;\n    char\t\t\tfiller[58];\n} pcxheader_t;\n\n/*\n============\nImage_LoadPCX\n============\n*/\nbyte *Image_LoadPCX (FILE *f, int *width, int *height)\n{\n\tpcxheader_t\tpcx;\n\tint\t\t\tx, y, w, h, readbyte, runlength, start;\n\tbyte\t\t*p, *data;\n\tbyte\t\tpalette[768];\n\tstdio_buffer_t  *buf;\n\n\tstart = ftell (f); //save start of file (since we might be inside a pak file, SEEK_SET might not be the start of the pcx)\n\n\tfread(&pcx, sizeof(pcx), 1, f);\n\tpcx.xmin = (unsigned short)LittleShort (pcx.xmin);\n\tpcx.ymin = (unsigned short)LittleShort (pcx.ymin);\n\tpcx.xmax = (unsigned short)LittleShort (pcx.xmax);\n\tpcx.ymax = (unsigned short)LittleShort (pcx.ymax);\n\tpcx.bytes_per_line = (unsigned short)LittleShort (pcx.bytes_per_line);\n\n\tif (pcx.signature != 0x0A)\n\t\tSys_Error (\"'%s' is not a valid PCX file\", loadfilename);\n\n\tif (pcx.version != 5)\n\t\tSys_Error (\"'%s' is version %i, should be 5\", loadfilename, pcx.version);\n\n\tif (pcx.encoding != 1 || pcx.bits_per_pixel != 8 || pcx.color_planes != 1)\n\t\tSys_Error (\"'%s' has wrong encoding or bit depth\", loadfilename);\n\n\tw = pcx.xmax - pcx.xmin + 1;\n\th = pcx.ymax - pcx.ymin + 1;\n\n\tdata = (byte *) malloc((w*h+1)*4); //+1 to allow reading padding byte on last line\n\n\t//load palette\n\tfseek (f, start + com_filesize - 768, SEEK_SET);\n\tfread (palette, 1, 768, f);\n\n\t//back to start of image data\n\tfseek (f, start + sizeof(pcx), SEEK_SET);\n\n\tbuf = Buf_Alloc(f);\n\n\tfor (y=0; y<h; y++)\n\t{\n\t\tp = data + y * w * 4;\n\n\t\tfor (x=0; x<(pcx.bytes_per_line); ) //read the extra padding byte if necessary\n\t\t{\n\t\t\treadbyte = Buf_GetC(buf);\n\n\t\t\tif(readbyte >= 0xC0)\n\t\t\t{\n\t\t\t\trunlength = readbyte & 0x3F;\n\t\t\t\treadbyte = Buf_GetC(buf);\n\t\t\t}\n\t\t\telse\n\t\t\t\trunlength = 1;\n\n\t\t\twhile(runlength--)\n\t\t\t{\n\t\t\t\tp[0] = palette[readbyte*3];\n\t\t\t\tp[1] = palette[readbyte*3+1];\n\t\t\t\tp[2] = palette[readbyte*3+2];\n\t\t\t\tp[3] = 255;\n\t\t\t\tp += 4;\n\t\t\t\tx++;\n\t\t\t}\n\t\t}\n\t}\n\n\tBuf_Free(buf);\n\tfclose(f);\n\n\t*width = w;\n\t*height = h;\n\treturn data;\n}\n"
  },
  {
    "path": "source/image.h",
    "content": "/*\nCopyright (C) 1996-2001 Id Software, Inc.\nCopyright (C) 2002-2009 John Fitzgibbons and others\nCopyright (C) 2010-2014 QuakeSpasm developers\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#ifndef IMAGE_H\n#define IMAGE_H\n\n//image.h -- image reading / writing\n\n//be sure to free the hunk after using these loading functions\nbyte *Image_LoadTGA (FILE *f, int *width, int *height);\nbyte *Image_LoadPCX (FILE *f, int *width, int *height);\nbyte *Image_LoadImage (const char *name, int *width, int *height);\n\n#endif\t/* IMAGE_H */\n\n\n"
  },
  {
    "path": "source/in_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n#include <vitasdk.h>\n\nCVAR (m_filter,\t\t0, CVAR_ARCHIVE)\nCVAR (pstv_rumble,\t1, CVAR_ARCHIVE)\nCVAR (retrotouch,\t\t\t\t\t0, CVAR_ARCHIVE)\nCVAR (psvita_touchmode,\t\t\t\t0, CVAR_ARCHIVE)\t// 0: as a button / 1: as a joystick\nCVAR (psvita_front_sensitivity_x,\t1, CVAR_ARCHIVE)\nCVAR (psvita_front_sensitivity_y,\t0.5, CVAR_ARCHIVE)\nCVAR (psvita_back_sensitivity_x,\t1, CVAR_ARCHIVE)\nCVAR (psvita_back_sensitivity_y,\t0.5, CVAR_ARCHIVE)\nCVAR (motioncam,\t\t\t\t\t 0, CVAR_ARCHIVE)\nCVAR (motion_horizontal_sensitivity,\t 0, CVAR_ARCHIVE)\nCVAR (motion_vertical_sensitivity,\t 0, CVAR_ARCHIVE)\n\nextern cvar_t always_run, invert_camera;\nextern void Log (const char *format, ...);\n\n#define lerp(value, from_max, to_max) ((((value*10) * (to_max*10))/(from_max*10))/10)\n\nuint64_t rumble_tick = 0;\nSceCtrlData oldanalogs, analogs;\nSceMotionState motionstate;\n\nvoid IN_Init (void)\n{\n  Cvar_RegisterVariable (&m_filter);\n  Cvar_RegisterVariable (&retrotouch);\n  Cvar_RegisterVariable (&always_run);\n  Cvar_RegisterVariable (&invert_camera);\n  Cvar_RegisterVariable (&pstv_rumble);\n  Cvar_RegisterVariable(&psvita_touchmode);\n\n  Cvar_RegisterVariable (&motioncam);\n  Cvar_RegisterVariable (&motion_horizontal_sensitivity);\n  Cvar_RegisterVariable (&motion_vertical_sensitivity);\n\n  //Touchscreen sensitivity\n  Cvar_RegisterVariable(&psvita_front_sensitivity_x);\n  Cvar_RegisterVariable(&psvita_front_sensitivity_y);\n  Cvar_RegisterVariable(&psvita_back_sensitivity_x);\n  Cvar_RegisterVariable(&psvita_back_sensitivity_y);\n\n  sceMotionReset();\n  sceMotionStartSampling();\n}\n\nvoid IN_ResetInputs(void)\n{\n\t// Set default PSVITA controls\n\tCbuf_AddText(\"unbindall\\n\");\n\tCbuf_AddText(\"bind CROSS +jump\\n\"); // Cross\n\tCbuf_AddText(\"bind SQUARE +attack\\n\"); // Square\n\tCbuf_AddText(\"bind CIRCLE \\\"impulse 12\\\"\\n\"); // Circle\n\tCbuf_AddText(\"bind TRIANGLE \\\"impulse 10\\\"\\n\"); // Triangle\n\tCbuf_AddText(\"bind LTRIGGER +jump\\n\"); // Left Trigger\n\tCbuf_AddText(\"bind RTRIGGER +attack\\n\"); // Right Trigger\n\tCbuf_AddText(\"bind UPARROW +forward\\n\"); // Up\n\tCbuf_AddText(\"bind DOWNARROW +back\\n\"); // Down\n\tCbuf_AddText(\"bind LEFTARROW +moveleft\\n\"); // Left\n\tCbuf_AddText(\"bind RIGHTARROW +moveright\\n\"); // Right\n\tCbuf_AddText(\"bind TOUCH +showscores\\n\"); // Touchscreen\n\tCbuf_AddText(\"bind SELECT +showscores\\n\"); // Touchscreen\n\tCbuf_AddText(\"sensitivity 3.5\\n\"); // Right Analog Sensitivity\n}\n\nvoid IN_Shutdown (void)\n{\n}\n\nvoid IN_Commands (void)\n{\n}\n\nvoid IN_StartRumble (void)\n{\n\tif (!pstv_rumble.value) return;\n\tSceCtrlActuator handle;\n\thandle.small = 100;\n\thandle.large = 100;\n\tsceCtrlSetActuator(1, &handle);\n\trumble_tick = sceKernelGetProcessTimeWide();\n}\n\nvoid IN_StopRumble (void)\n{\n\tSceCtrlActuator handle;\n\thandle.small = 0;\n\thandle.large = 0;\n\tsceCtrlSetActuator(1, &handle);\n\trumble_tick = 0;\n}\n\nvoid IN_RescaleAnalog(int *x, int *y, int dead) {\n\t//radial and scaled deadzone\n\t//http://www.third-helix.com/2013/04/12/doing-thumbstick-dead-zones-right.html\n\n\tfloat analogX = (float) *x;\n\tfloat analogY = (float) *y;\n\tfloat deadZone = (float) dead;\n\tfloat maximum = 128.0f;\n\tfloat magnitude = sqrt(analogX * analogX + analogY * analogY);\n\tif (magnitude >= deadZone)\n\t{\n\t\tfloat scalingFactor = maximum / magnitude * (magnitude - deadZone) / (maximum - deadZone);\n\t\t*x = (int) (analogX * scalingFactor);\n\t\t*y = (int) (analogY * scalingFactor);\n\t} else {\n\t\t*x = 0;\n\t\t*y = 0;\n\t}\n}\n\nvoid IN_Move (usercmd_t *cmd)\n{\n\t// ANALOGS\n\tif ((in_speed.state & 1) || always_run.value){\n\t\tcl_forwardspeed.value = 400;\n\t\tcl_backspeed.value = 400;\n\t\tcl_sidespeed.value = 700;\n\t}else{\n\t\tcl_forwardspeed.value = 200;\n\t\tcl_backspeed.value = 200;\n\t\tcl_sidespeed.value = 300;\n\t}\n\n\tsceCtrlPeekBufferPositive(0, &analogs, 1);\n\tint left_x = analogs.lx - 127;\n\tint left_y = analogs.ly - 127;\n\tint right_x = analogs.rx - 127;\n\tint right_y = analogs.ry - 127;\n\n\t// Left analog support for player movement\n\tfloat x_mov = abs(left_x) < 30 ? 0 : (left_x * cl_sidespeed.value) * 0.01;\n\tfloat y_mov = abs(left_y) < 30 ? 0 : (left_y * (left_y > 0 ? cl_backspeed.value : cl_forwardspeed.value)) * 0.01;\n\tcmd->forwardmove -= y_mov;\n\tif (gl_xflip.value) cmd->sidemove -= x_mov;\n\telse cmd->sidemove += x_mov;\n\n\t// Right analog support for camera movement\n\tIN_RescaleAnalog(&right_x, &right_y, 30);\n\tfloat x_cam = (right_x * sensitivity.value) * 0.008;\n\tfloat y_cam = (right_y * sensitivity.value) * 0.008;\n\tif (gl_xflip.value) cl.viewangles[YAW] += x_cam;\n\telse cl.viewangles[YAW] -= x_cam;\n\tV_StopPitchDrift();\n\tif (invert_camera.value) cl.viewangles[PITCH] -= y_cam;\n\telse cl.viewangles[PITCH] += y_cam;\n\n\t// TOUCH SUPPORT\n\n\t// Retrotouch support for camera movement\n\tSceTouchData touch;\n\tif (retrotouch.value){\n\t\tsceTouchPeek(SCE_TOUCH_PORT_BACK, &touch, 1);\n\t\tif (touch.reportNum > 0) {\n\t\t\tint raw_x = lerp(touch.report[0].x, 1919, 960);\n\t\t\tint raw_y = lerp(touch.report[0].y, 1087, 544);\n\t\t\tint touch_x = raw_x - 480;\n\t\t\tint touch_y = raw_y - 272;\n\t\t\tx_cam = abs(touch_x) < 20 ? 0 : touch_x * psvita_back_sensitivity_x.value * 0.008;\n\t\t\ty_cam = abs(touch_y) < 20 ? 0 : touch_y * psvita_back_sensitivity_x.value * 0.008;\n\t\t\tcl.viewangles[YAW] -= x_cam;\n\t\t\tV_StopPitchDrift();\n\t\t\tif (invert_camera.value) cl.viewangles[PITCH] -= y_cam;\n\t\t\telse cl.viewangles[PITCH] += y_cam;\n\t\t}\n\t}\n\n\tif (psvita_touchmode.value == 1)\n\t{\n\t\tsceTouchPeek(SCE_TOUCH_PORT_FRONT, &touch, 1);\n\t\tif (touch.reportNum > 0) {\n\t\t\tint raw_x = lerp(touch.report[0].x, 1919, 960);\n\t\t\tint raw_y = lerp(touch.report[0].y, 1087, 544);\n\t\t\tint touch_x = raw_x - 480;\n\t\t\tint touch_y = raw_y - 272;\n\t\t\tx_cam = abs(touch_x) < 20 ? 0 : touch_x * psvita_front_sensitivity_x.value * 0.008;\n\t\t\ty_cam = abs(touch_y) < 20 ? 0 : touch_y * psvita_front_sensitivity_y.value * 0.008;\n\t\t\tcl.viewangles[YAW] -= x_cam;\n\t\t\tV_StopPitchDrift();\n\t\t\tif (invert_camera.value) cl.viewangles[PITCH] -= y_cam;\n\t\t\telse cl.viewangles[PITCH] += y_cam;\n\t\t}\n\t}\n\n  // gyro analog support for camera movement\n\n  if (motioncam.value){\n    sceMotionGetState(&motionstate);\n\n    // not sure why YAW or the horizontal x axis is the controlled by angularVelocity.y\n    // and the PITCH or the vertical y axis is controlled by angularVelocity.x but its what seems to work\n    float x_gyro_cam = motionstate.angularVelocity.y * motion_horizontal_sensitivity.value;\n    float y_gyro_cam = motionstate.angularVelocity.x * motion_vertical_sensitivity.value;\n\n    if (gl_xflip.value)\n      cl.viewangles[YAW] -= x_gyro_cam;\n    else\n      cl.viewangles[YAW] += x_gyro_cam;\n\n    V_StopPitchDrift();\n\n    if (invert_camera.value)\n      cl.viewangles[PITCH] += y_gyro_cam;\n    else\n      cl.viewangles[PITCH] -= y_gyro_cam;\n  }\n\n\tif (pq_fullpitch.value)\n\t\tcl.viewangles[PITCH] = COM_Clamp(cl.viewangles[PITCH], -90, 90);\n\telse\n\t\tcl.viewangles[PITCH] = COM_Clamp(cl.viewangles[PITCH], -70, 80);\n}\n"
  },
  {
    "path": "source/input.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// input.h -- external (non-keyboard) input devices\n\nvoid IN_Init (void);\n\nvoid IN_Shutdown (void);\n\nvoid IN_StartRumble (void);\n\nvoid IN_StopRumble (void);\n\nvoid IN_Commands (void);\n// oportunity for devices to stick commands on the script buffer\n\nvoid IN_Move (usercmd_t *cmd);\n// add additional movement on top of the keyboard move cmd\n\nvoid IN_ClearStates (void);\n// restores all button and position states to defaults\n\nvoid IN_ResetInputs (void);"
  },
  {
    "path": "source/keys.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include \"quakedef.h\"\n\n/*\n\nkey up events are sent even if in console mode\n\n*/\n\n\n#define\t\tMAXCMDLINE\t256\nchar\tkey_lines[32][MAXCMDLINE];\nint\t\tkey_linepos;\nint\t\tshift_down=false;\nint\t\tkey_lastpress;\n\nint\t\tedit_line=0;\nint\t\thistory_line=0;\n\nkeydest_t\tkey_dest;\n\nint\t\tkey_count;\t\t\t// incremented every key event\n\nchar\t*keybindings[256];\nbool\tconsolekeys[256];\t// if true, can't be rebound while in console\nbool\tmenubound[256];\t// if true, can't be rebound while in menu\nint\t\tkeyshift[256];\t\t// key to map to if shift held down in console\nint\t\tkey_repeats[256];\t// if > 1, it is autorepeating\nbool\tkeydown[256];\n\ntypedef struct\n{\n\tchar\t*name;\n\tint\t\tkeynum;\n} keyname_t;\n\nkeyname_t keynames[] =\n{\n\t{\"TAB\", K_TAB},\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{\"TOUCH\", K_TOUCH},\n\t{\"CTRL\", K_CTRL},\n\t{\"SHIFT\", K_SHIFT},\n\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\n\t{\"JOY1\", K_JOY1},\n\t{\"JOY2\", K_JOY2},\n\t{\"JOY3\", K_JOY3},\n\t{\"JOY4\", K_JOY4},\n\t\n\t// PSP / PSVITA Buttons\n\t{\"CROSS\", K_CROSS},\n\t{\"SQUARE\", K_SQUARE },\n\t{\"TRIANGLE\", K_TRIANGLE },\n\t{\"CIRCLE\", K_CIRCLE },\n\t{\"LTRIGGER\", K_LEFTTRIGGER },\n\t{\"RTRIGGER\", K_RIGHTTRIGGER },\n\t{\"START\", K_START }, // Start Button\n\t{\"SELECT\", K_SELECT }, // Select Button\n\n\t// OTHER Buttons\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\t{\"AUX17\", K_AUX17},\n\t{\"AUX18\", K_AUX18},\n\t{\"AUX19\", K_AUX19},\n\t{\"AUX20\", K_AUX20},\n\t{\"AUX21\", K_AUX21},\n\t{\"AUX22\", K_AUX22},\n\t{\"AUX23\", K_AUX23},\n\t{\"AUX24\", K_AUX24},\n\t{\"AUX25\", K_AUX25},\n\t{\"AUX26\", K_AUX26},\n\t{\"AUX27\", K_AUX27},\n\t{\"AUX28\", K_AUX28},\n\t{\"AUX29\", K_AUX29},\n\t{\"AUX30\", K_AUX30},\n\t{\"AUX31\", K_AUX31},\n\t{\"AUX32\", K_AUX32},\n\n\t{\"PAUSE\", K_PAUSE},\n\n\t{\"SEMICOLON\", ';'},\t// because a raw semicolon seperates commands\n\n\t{NULL,0}\n};\n\n/*\n==============================================================================\n\n\t\t\tLINE TYPING INTO THE CONSOLE\n\n==============================================================================\n*/\n\n\n\n\nvoid Key_SendText(char *Text)\n{\n\tCbuf_AddText(Text);\n\tCbuf_AddText(\"\\n\");\n\tCon_Printf(\"]%s\\n\", Text);\n\tedit_line = (edit_line + 1) & 31;\n\thistory_line = edit_line;\n\tkey_lines[edit_line][0] = ']';\n\tkey_linepos = 1;\n}\n\n/*\n====================\nKey_Console\n\nInteractive line editing and console scrollback\n====================\n*/\nvoid Key_Console (int key)\n{\n\tchar\t*cmd;\n\n\tif (key == K_CROSS)\n\t{\n\t\tKey_SendText(key_lines[edit_line] + 1);\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\tif (key == K_RIGHTARROW)\t// Was K_TAB\n\t{\t// command completion\n\t\tcmd = Cmd_CompleteCommand (key_lines[edit_line]+1);\n\t\tif (!cmd)\n\t\t\tcmd = Cvar_CompleteVariable (key_lines[edit_line]+1);\n\t\tif (cmd)\n\t\t{\n\t\t\tstrcpy (key_lines[edit_line]+1, cmd);\n\t\t\tkey_linepos = strlen(cmd)+1;\n\t\t\tkey_lines[edit_line][key_linepos] = ' ';\n\t\t\tkey_linepos++;\n\t\t\tkey_lines[edit_line][key_linepos] = 0;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tif (key == K_BACKSPACE || key == K_LEFTARROW)\n\t{\n\t\tif (key_linepos > 1)\n\t\t\tkey_linepos--;\n\t\treturn;\n\t}\n\n\tif (key == K_UPARROW)\n\t{\n\t\tdo\n\t\t{\n\t\t\thistory_line = (history_line - 1) & 31;\n\t\t} while (history_line != edit_line\n\t\t\t\t&& !key_lines[history_line][1]);\n\t\tif (history_line == edit_line)\n\t\t\thistory_line = (edit_line+1)&31;\n\t\tstrcpy(key_lines[edit_line], key_lines[history_line]);\n\t\tkey_linepos = strlen(key_lines[edit_line]);\n\t\treturn;\n\t}\n\n\tif (key == K_DOWNARROW)\n\t{\n\t\tif (history_line == edit_line) return;\n\t\tdo\n\t\t{\n\t\t\thistory_line = (history_line + 1) & 31;\n\t\t}\n\t\twhile (history_line != edit_line\n\t\t\t&& !key_lines[history_line][1]);\n\t\tif (history_line == edit_line)\n\t\t{\n\t\t\tkey_lines[edit_line][0] = ']';\n\t\t\tkey_linepos = 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrcpy(key_lines[edit_line], key_lines[history_line]);\n\t\t\tkey_linepos = strlen(key_lines[edit_line]);\n\t\t}\n\t\treturn;\n\t}\n\n\tif (key == K_LEFTTRIGGER) // Scrolling up the console\n\t{\n\t\tcon_backscroll += 2;\n\t\tif (con_backscroll > con_totallines - (vid.height>>3) - 1)\n\t\t\tcon_backscroll = con_totallines - (vid.height>>3) - 1;\n\t\treturn;\n\t}\n\n\tif (key == K_RIGHTTRIGGER) // Scrolling down the console\n\t{\n\t\tcon_backscroll -= 2;\n\t\tif (con_backscroll < 0)\n\t\t\tcon_backscroll = 0;\n\t\treturn;\n\t}\n\n\tif (key == K_HOME)\n\t{\n\t\tcon_backscroll = con_totallines - (vid.height>>3) - 1;\n\t\treturn;\n\t}\n\n\tif (key == K_START)\n\t{\n\t\tcon_backscroll = 0;\n\t\treturn;\n\t}\n\n\tif (key < 32 || key > 127)\n\t\treturn;\t// non printable\n\n\tif (key_linepos < MAXCMDLINE-1)\n\t{\n\t\tkey_lines[edit_line][key_linepos] = key;\n\t\tkey_linepos++;\n\t\tkey_lines[edit_line][key_linepos] = 0;\n\t}\n\n}\n\n//============================================================================\n\nchar chat_buffer[32];\nbool team_message = false;\n\nvoid Key_Message (int key)\n{\n\tstatic int chat_bufferlen = 0;\n\n\tif (key == K_CROSS)\n\t{\n\t\tif (team_message)\n\t\t\tCbuf_AddText (\"say_team \\\"\");\n\t\telse\n\t\t\tCbuf_AddText (\"say \\\"\");\n\t\tCbuf_AddText(chat_buffer);\n\t\tCbuf_AddText(\"\\\"\\n\");\n\n\t\tkey_dest = key_game;\n\t\tchat_bufferlen = 0;\n\t\tchat_buffer[0] = 0;\n\t\treturn;\n\t}\n\n\tif (key == K_START)\n\t{\n\t\tkey_dest = key_game;\n\t\tchat_bufferlen = 0;\n\t\tchat_buffer[0] = 0;\n\t\treturn;\n\t}\n\n\tif (key < 32 || key > 127)\n\t\treturn;\t// non printable\n\n\tif (key == K_LEFTARROW)\n\t{\n\t\tif (chat_bufferlen)\n\t\t{\n\t\t\tchat_bufferlen--;\n\t\t\tchat_buffer[chat_bufferlen] = 0;\n\t\t}\n\t\treturn;\n\t}\n\n\tif (chat_bufferlen == 31)\n\t\treturn; // all full\n\n\tchat_buffer[chat_bufferlen++] = key;\n\tchat_buffer[chat_bufferlen] = 0;\n}\n\n//============================================================================\n\n\n/*\n===================\nKey_StringToKeynum\n\nReturns a key number to be used to index keybindings[] by looking at\nthe given string.  Single ascii characters return themselves, while\nthe K_* names are matched up.\n===================\n*/\nint Key_StringToKeynum (char *str)\n{\n\tkeyname_t\t*kn;\n\n\tif (!str || !str[0])\n\t\treturn -1;\n\tif (!str[1])\n\t\treturn str[0];\n\n\tfor (kn=keynames ; kn->name ; kn++)\n\t{\n\t\tif (!strcasecmp(str,kn->name))\n\t\t\treturn kn->keynum;\n\t}\n\treturn -1;\n}\n\n/*\n===================\nKey_KeynumToString\n\nReturns a string (either a single ascii char, or a K_* name) for the\ngiven keynum.\nFIXME: handle quote special (general escape sequence?)\n===================\n*/\nchar *Key_KeynumToString (int keynum)\n{\n\tkeyname_t\t*kn;\n\tstatic\tchar\ttinystr[2];\n\n\tif (keynum == -1)\n\t\treturn \"<KEY NOT FOUND>\";\n\tif (keynum > 32 && keynum < 127)\n\t{\t// printable ascii\n\t\ttinystr[0] = keynum;\n\t\ttinystr[1] = 0;\n\t\treturn tinystr;\n\t}\n\n\tfor (kn=keynames ; kn->name ; kn++)\n\t\tif (keynum == kn->keynum)\n\t\t\treturn kn->name;\n\n\treturn \"<UNKNOWN KEYNUM>\";\n}\n\n\n/*\n===================\nKey_SetBinding\n===================\n*/\nvoid Key_SetBinding (int keynum, char *binding)\n{\n\tchar\t*new;\n\tint\t\tl;\n\n\tif (keynum == -1)\n\t\treturn;\n\n// free old bindings\n\tif (keybindings[keynum])\n\t{\n\t\tZ_Free (keybindings[keynum]);\n\t\tkeybindings[keynum] = NULL;\n\t}\n\n// allocate memory for new binding\n\tl = strlen (binding);\n\tnew = Z_Malloc (l+1);\n\tstrcpy (new, binding);\n\tnew[l] = 0;\n\tkeybindings[keynum] = new;\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\tCon_Printf (\"unbind <key> : remove commands from a key\\n\");\n\t\treturn;\n\t}\n\n\tb = Key_StringToKeynum (Cmd_Argv(1));\n\tif (b==-1)\n\t{\n\t\tCon_Printf (\"\\\"%s\\\" isn't a valid key\\n\", Cmd_Argv(1));\n\t\treturn;\n\t}\n\n\tKey_SetBinding (b, \"\");\n}\n\nvoid Key_Unbindall_f (void)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<256 ; i++)\n\t\tif (keybindings[i])\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\t*cmd;\n\n\tc = Cmd_Argc();\n\n\tif (c != 2 && c != 3)\n\t{\n\t\tCon_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\tCon_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 (keybindings[b])\n\t\t\tCon_Printf (\"\\\"%s\\\" = \\\"%s\\\"\\n\", Cmd_Argv(1), keybindings[b] );\n\t\telse\n\t\t\tCon_Printf (\"\\\"%s\\\" is not bound\\n\", Cmd_Argv(1) );\n\t\treturn;\n\t}\n\n\tcmd = Sys_BigStackAlloc(1024, \"Key_Bind_f\");\n\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\tif (i > 2)\n\t\t\tstrcat (cmd, \" \");\n\t\tstrcat (cmd, Cmd_Argv(i));\n\t}\n\n\tKey_SetBinding (b, cmd);\n\tSys_BigStackFree(1024, \"Key_Bind_f\");\n}\n\n/*\n============\nKey_WriteBindings\n\nWrites lines containing \"bind key value\"\n============\n*/\nvoid Key_WriteBindings (FILE *f)\n{\n\tint\t\ti;\n\n\tfprintf(f, \"// Key bindings\\n\");\n\tfor (i=0 ; i<256 ; i++)\n\t\tif (keybindings[i])\n\t\t\tif (*keybindings[i])\n\t\t\t\tfprintf (f, \"bind \\\"%s\\\" \\\"%s\\\"\\n\", Key_KeynumToString(i), keybindings[i]);\n}\n\n\n/*\n===================\nKey_Init\n===================\n*/\nvoid Key_Init (void)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<32 ; i++)\n\t{\n\t\tkey_lines[i][0] = ']';\n\t\tkey_lines[i][1] = 0;\n\t}\n\tkey_linepos = 1;\n\n\t//consolekeys[K_ENTER] = true;\n\tconsolekeys[K_TAB] = true;\n\tconsolekeys[K_UPARROW] = true;\n\tconsolekeys[K_DOWNARROW] = true;\n\tconsolekeys[K_LEFTARROW] = true;\n\tconsolekeys[K_RIGHTARROW] = true;\t// Now acts as TAB\n\n\t// Add PSVita buttons to stop interfering in MP\n\tconsolekeys[K_START] = true;\t// Toggles console\n\tconsolekeys[K_SELECT] = true;\n\tconsolekeys[K_LEFTTRIGGER] = true;\n\tconsolekeys[K_RIGHTTRIGGER] = true;\n\tconsolekeys[K_CROSS] = true;\n\tconsolekeys[K_TRIANGLE] = true;\n\tconsolekeys[K_SQUARE] = true;\n\tconsolekeys[K_CIRCLE] = true;\n\n\tmenubound[K_START] = true;\n\n//\n// register our functions\n//\n\tCmd_AddCommand (\"bind\",Key_Bind_f);\n\tCmd_AddCommand (\"unbind\",Key_Unbind_f);\n\tCmd_AddCommand (\"unbindall\",Key_Unbindall_f);\n}\n\n/*\n===================\nKey_Event\n\nCalled by the system between frames for both key up and key down events\nShould NOT be called during an interrupt!\n===================\n*/\nvoid Key_Event (int key, bool down)\n{\n\tchar\t*kb;\n\tchar*\tcmd;\n\n\tkeydown[key] = down;\n\n\tif (!down)\n\t\tkey_repeats[key] = 0;\n\n\tkey_lastpress = key;\n\tkey_count++;\n\tif (key_count <= 0)\n\t{\n\t\treturn;\t\t// just catching keys for Con_NotifyBox\n\t}\n\n// update auto-repeat status\n\tif (down)\n\t{\n\t\tkey_repeats[key]++;\n\t\tif (key != K_BACKSPACE && key != K_PAUSE && key_repeats[key] > 1)\n\t\t{\n\t\t\treturn;\t// ignore most autorepeats\n\t\t}\n\n\t\tif (key >= 200 && !keybindings[key] && key != K_START && key != K_SELECT )\n\t\t\tCon_Printf (\"%s is unbound, please set a button in the options.\\n\", Key_KeynumToString (key) );\n\t}\n\n\tif (key == K_SHIFT)\n\t\tshift_down = down;\n\n//\n// handle escape specialy, so the user can never unbind it\n//\n\tif (key == K_START || key == K_ENTER)\n\t{\n\t\tif (!down)\n\t\t\treturn;\n\t\tswitch (key_dest)\n\t\t{\n\t\tcase key_message:\n\t\t\tKey_Message (key);\n\t\t\tbreak;\n\t\tcase key_menu:\n\t\t\tM_Keydown (key);\n\t\t\tbreak;\n\t\tcase key_game:\n\t\tcase key_console:\n\t\t\tM_ToggleMenu_f ();\n\t\t\tbreak;\n\t\tcase key_benchmark:\n\t\t\tbreak;\n\t\tdefault:\n\t\t\tSys_Error (\"Bad key_dest\");\n\t\t}\n\t\treturn;\n\t}\n\n\tcmd = Sys_BigStackAlloc(1024, \"Key_Event\");\n\n//\n// key up events only generate commands if the game key binding is\n// a button command (leading + sign).  These will occur even in console mode,\n// to keep the character from continuing an action started before a console\n// switch.  Button commands include the kenum as a parameter, so multiple\n// downs can be matched with ups\n//\n\tif (!down)\n\t{\n\t\tkb = keybindings[key];\n\t\tif (kb && kb[0] == '+')\n\t\t{\n\t\t\tsprintf (cmd, \"-%s %i\\n\", kb+1, key);\n\t\t\tCbuf_AddText (cmd);\n\t\t}\n\t\tif (keyshift[key] != key)\n\t\t{\n\t\t\tkb = keybindings[keyshift[key]];\n\t\t\tif (kb && kb[0] == '+')\n\t\t\t{\n\t\t\t\tsprintf (cmd, \"-%s %i\\n\", kb+1, key);\n\t\t\t\tCbuf_AddText (cmd);\n\t\t\t}\n\t\t}\n\n\t\tSys_BigStackFree(1024, \"Key_Event\");\n\t\treturn;\n\t}\n\n//\n// during demo playback, most keys bring up the main menu\n//\n\tif (cls.demoplayback && down && consolekeys[key] && key_dest == key_game)\n\t{\n\t\tM_ToggleMenu_f ();\n\t\tSys_BigStackFree(1024, \"Key_Event\");\n\t\treturn;\n\t}\n\n//\n// if not a consolekey, send to the interpreter no matter what mode is\n//\n\tif ( (key_dest == key_menu && menubound[key])\n\t|| (key_dest == key_console && !consolekeys[key])\n\t|| (key_dest == key_game && ( !con_forcedup || !consolekeys[key] ) ) )\n\t{\n\t\tkb = keybindings[key];\n\t\tif (kb)\n\t\t{\n\t\t\tif (kb[0] == '+')\n\t\t\t{\t// button commands add keynum as a parm\n\t\t\t\tsprintf (cmd, \"%s %i\\n\", kb, key);\n\t\t\t\tCbuf_AddText (cmd);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCbuf_AddText (kb);\n\t\t\t\tCbuf_AddText (\"\\n\");\n\t\t\t}\n\t\t}\n\t\tSys_BigStackFree(1024, \"Key_Event\");\n\t\treturn;\n\t}\n\n\tif (!down)\n\t{\n\t\tSys_BigStackFree(1024, \"Key_Event\");\n\t\treturn;\t\t// other systems only care about key down events\n\t}\n\n\tif (shift_down)\n\t{\n\t\tkey = keyshift[key];\n\t}\n\n\tswitch (key_dest)\n\t{\n\tcase key_message:\n\t\tKey_Message (key);\n\t\tbreak;\n\tcase key_menu:\n\t\tM_Keydown (key);\n\t\tbreak;\n\n\tcase key_game:\n\tcase key_console:\n\t\tKey_Console (key);\n\t\tbreak;\n\tcase key_benchmark:\n\t\tCL_Disconnect();\n\t\tbreak;\n\tdefault:\n\t\tSys_Error (\"Bad key_dest\");\n\t}\n\n\tSys_BigStackFree(1024, \"Key_Event\");\n}\n\n\n/*\n===================\nKey_ClearStates\n===================\n*/\nvoid Key_ClearStates (void)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<256 ; i++)\n\t{\n\t\tkeydown[i] = false;\n\t\tkey_repeats[i] = 0;\n\t}\n}\n"
  },
  {
    "path": "source/keys.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n//\n// these are the key numbers that should be passed to Key_Event\n//\n#define\tK_TAB\t\t\t9\n#define\tK_ENTER\t\t\t13\n#define\tK_ESCAPE\t\t27\n#define\tK_SPACE\t\t\t32\n\n// normal keys should be passed as lowercased ascii\n\n#define\tK_BACKSPACE\t\t127\n#define\tK_UPARROW\t\t128\n#define\tK_DOWNARROW\t\t129\n#define\tK_LEFTARROW\t\t130\n#define\tK_RIGHTARROW\t131\n#define\tK_TOUCH\t\t\t132\n\n#define\tK_CTRL\t\t\t133\n#define\tK_SHIFT\t\t\t134\n#define\tK_F1\t\t\t135\n#define\tK_F2\t\t\t136\n#define\tK_F3\t\t\t137\n#define\tK_F4\t\t\t138\n#define\tK_F5\t\t\t139\n#define\tK_F6\t\t\t140\n#define\tK_F7\t\t\t141\n#define\tK_F8\t\t\t142\n#define\tK_F9\t\t\t143\n#define\tK_F10\t\t\t144\n#define\tK_F11\t\t\t145\n#define\tK_F12\t\t\t146\n#define\tK_INS\t\t\t147\n#define\tK_DEL\t\t\t148\n#define\tK_PGDN\t\t\t149\n#define\tK_PGUP\t\t\t150\n#define\tK_HOME\t\t\t151\n#define\tK_END\t\t\t152\n\n#define K_PAUSE\t\t\t255\n\n//\n// mouse buttons generate virtual keys\n//\n#define\tK_MOUSE1\t\t200\n#define\tK_MOUSE2\t\t201\n#define\tK_MOUSE3\t\t202\n\n//\n// joystick buttons\n//\n#define\tK_JOY1\t\t\t203\n#define\tK_JOY2\t\t\t204\n#define\tK_JOY3\t\t\t205\n#define\tK_JOY4\t\t\t206\n\n// PSP / PSVita Buttons\n#define\tK_CROSS\t\t\t207\n#define\tK_SQUARE\t\t208\n#define\tK_TRIANGLE\t\t209\n#define\tK_CIRCLE\t\t210\n#define\tK_LEFTTRIGGER\t211\n#define\tK_RIGHTTRIGGER\t212\n#define\tK_SELECT\t\t213\n#define\tK_START\t\t\t214\n\n//\n// aux keys are for multi-buttoned joysticks to generate so they can use\n// the normal binding process\n//\n\n#define\tK_AUX9\t\t\t215\n#define\tK_AUX10\t\t\t216\n#define\tK_AUX11\t\t\t217\n#define\tK_AUX12\t\t\t218\n#define\tK_AUX13\t\t\t219\n#define\tK_AUX14\t\t\t220\n#define\tK_AUX15\t\t\t221\n#define\tK_AUX16\t\t\t222\n#define\tK_AUX17\t\t\t223\n#define\tK_AUX18\t\t\t224\n#define\tK_AUX19\t\t\t225\n#define\tK_AUX20\t\t\t226\n#define\tK_AUX21\t\t\t227\n#define\tK_AUX22\t\t\t228\n#define\tK_AUX23\t\t\t229\n#define\tK_AUX24\t\t\t230\n#define\tK_AUX25\t\t\t231\n#define\tK_AUX26\t\t\t232\n#define\tK_AUX27\t\t\t233\n#define\tK_AUX28\t\t\t234\n#define\tK_AUX29\t\t\t235\n#define\tK_AUX30\t\t\t236\n#define\tK_AUX31\t\t\t237\n#define\tK_AUX32\t\t\t238\n\n// JACK: Intellimouse(c) Mouse Wheel Support\n\n#define K_MWHEELUP\t\t239\n#define K_MWHEELDOWN\t240\n\n\n\ntypedef enum {key_game, key_console, key_message, key_menu, key_benchmark} keydest_t;\n\nextern keydest_t\tkey_dest;\nextern char *keybindings[256];\nextern\tint\t\tkey_repeats[256];\nextern\tint\t\tkey_count;\t\t\t// incremented every key event\nextern\tint\t\tkey_lastpress;\n\nvoid Key_Event (int key, bool down);\nvoid Key_Init (void);\nvoid Key_WriteBindings (FILE *f);\nvoid Key_SetBinding (int keynum, char *binding);\nvoid Key_ClearStates (void);\nvoid Key_SendText(char *strText);"
  },
  {
    "path": "source/mathlib.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// mathlib.c -- math primitives\n\n#include <math.h>\n#include <math_neon.h>\n#include \"quakedef.h\"\n\nextern void Sys_Error(const char *error, ...);\n\nvec3_t vec3_origin = { 0,0,0 };\nint nanmask = 255 << 23;\n\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 = 1.0F / DotProduct(normal, normal);\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** 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\tfloat absrc = fabsf(src[i]);\n\t\tif (absrc < minelem)\n\t\t{\n\t\t\tpos = i;\n\t\t\tminelem = absrc;\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\nvoid RotatePointAroundVector(vec3_t dst, const vec3_t dir, const vec3_t point, float degrees)\n{\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\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\t\n\tfloat cs[2];\n\tsincosf_c(DEG2RAD(degrees), cs);\n\tzrot[0][0] = cs[1];\n\tzrot[0][1] = cs[0];\n\tzrot[1][0] = -cs[0];\n\tzrot[1][1] = cs[1];\n\n\tR_ConcatRotations(m, zrot, tmpmat);\n\tR_ConcatRotations(tmpmat, im, rot);\n\n\tfor (i = 0; i < 3; i++)\n\t{\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\n\nfloat\tanglemod(float a)\n{\n\ta = (360.0 / 65536) * ((int)(a*(65536 / 360.0)) & 65535);\n\treturn a;\n}\n\n/*\n==================\nBOPS_Error\n\nSplit out like this for ASM to call.\n==================\n*/\nvoid BOPS_Error(void)\n{\n\tSys_Error(\"BoxOnPlaneSide:  Bad signbits\");\n}\n\n\n#if\t!id386\n\n/*\n==================\nBoxOnPlaneSide\n\nReturns 1, 2, or 1 + 2\n==================\n*/\nint BoxOnPlaneSide(vec3_t emins, vec3_t emaxs, mplane_t *p)\n{\n\tfloat\tdist1, dist2;\n\tint\t\tsides;\n\n\t// 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\tBOPS_Error();\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#ifdef PARANOID\n\tif (sides == 0)\n\t\tSys_Error(\"BoxOnPlaneSide: sides==0\");\n#endif\n\n\treturn sides;\n}\n\n#endif\n\nvoid AngleVectors(vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)\n{\n\tfloat\t\tsr, sp, sy, cr, cp, cy;\n\t\n\tv4sf src = {\n\t\tangles[YAW] * (M_PI * 2 / 360),\n\t\tangles[PITCH] * (M_PI * 2 / 360),\n\t\tangles[ROLL] * (M_PI * 2 / 360),\n\t\t0\n\t};\n\t\n\tv4sf sins, coss;\n\t\n\tsincos_ps(src, &sins, &coss);\n\t\n\tsy = sins[0];\n\tcy = coss[0];\n\tsp = sins[1];\n\tcp = coss[1];\n\tsr = sins[2];\n\tcr = coss[2];\n\n\tforward[0] = cp*cy;\n\tforward[1] = cp*sy;\n\tforward[2] = -sp;\n\tright[0] = (-1 * sr*sp*cy + -1 * cr*-sy);\n\tright[1] = (-1 * sr*sp*sy + -1 * cr*cy);\n\tright[2] = -1 * sr*cp;\n\tup[0] = (cr*sp*cy + -sr*-sy);\n\tup[1] = (cr*sp*sy + -sr*cy);\n\tup[2] = cr*cp;\n}\n\nint VectorCompare(vec3_t v1, vec3_t v2)\n{\n\tint\t\ti;\n\n\tfor (i = 0; i<3; i++)\n\t\tif (v1[i] != v2[i])\n\t\t\treturn 0;\n\n\treturn 1;\n}\n\nvoid VectorMA(vec3_t veca, float scale, vec3_t vecb, vec3_t vecc)\n{\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(vec3_t v1, vec3_t v2)\n{\n\treturn v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];\n}\n\nvoid _VectorSubtract(vec3_t veca, vec3_t vecb, vec3_t out)\n{\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(vec3_t veca, vec3_t vecb, vec3_t out)\n{\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(vec3_t in, vec3_t out)\n{\n\tout[0] = in[0];\n\tout[1] = in[1];\n\tout[2] = in[2];\n}\n\nvoid CrossProduct(vec3_t v1, vec3_t v2, vec3_t cross)\n{\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\ndouble sqrt(double x);\n\nvec_t Length(vec3_t v)\n{\n\tint\t\ti;\n\tfloat\tlength;\n\n\tlength = 0;\n\tfor (i = 0; i< 3; i++)\n\t\tlength += v[i] * v[i];\n\tlength = sqrtf(length);\t\t// FIXME\n\n\treturn length;\n}\n\nfloat VectorLength(vec3_t v)\n{\n\tfloat\tlength;\n\n\tlength = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];\n\treturn sqrtf(length);\n}\n\n\nfloat VectorNormalize(vec3_t v)\n{\n\tfloat\tlength, ilength;\n\n\tlength = v[0] * v[0] + v[1] * v[1] + v[2] * v[2];\n\tlength = sqrt(length);\t\t// FIXME\n\n\tif (length)\n\t{\n\t\tilength = 1 / length;\n\t\tv[0] *= ilength;\n\t\tv[1] *= ilength;\n\t\tv[2] *= ilength;\n\t}\n\n\treturn length;\n}\n\nvoid VectorInverse(vec3_t v)\n{\n\tv[0] = -v[0];\n\tv[1] = -v[1];\n\tv[2] = -v[2];\n}\n\nvoid VectorScale(vec3_t in, vec_t scale, vec3_t out)\n{\n\tout[0] = in[0] * scale;\n\tout[1] = in[1] * scale;\n\tout[2] = in[2] * scale;\n}\n\n\nint Q_log2(int val)\n{\n\tint answer = 0;\n\twhile (val >>= 1)\n\t\tanswer++;\n\treturn answer;\n}\n\n\n/*\n================\nR_ConcatRotations\n================\n*/\nvoid R_ConcatRotations(float in1[3][3], float in2[3][3], float out[3][3])\n{\n\tout[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];\n\tout[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];\n\tout[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];\n\tout[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];\n\tout[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];\n\tout[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];\n\tout[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];\n\tout[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];\n\tout[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];\n}\n\n\n/*\n================\nR_ConcatTransforms\n================\n*/\nvoid R_ConcatTransforms(float in1[3][4], float in2[3][4], float out[3][4])\n{\n\tout[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + in1[0][2] * in2[2][0];\n\tout[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + in1[0][2] * in2[2][1];\n\tout[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + in1[0][2] * in2[2][2];\n\tout[0][3] = in1[0][0] * in2[0][3] + in1[0][1] * in2[1][3] + in1[0][2] * in2[2][3] + in1[0][3];\n\tout[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + in1[1][2] * in2[2][0];\n\tout[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + in1[1][2] * in2[2][1];\n\tout[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + in1[1][2] * in2[2][2];\n\tout[1][3] = in1[1][0] * in2[0][3] + in1[1][1] * in2[1][3] + in1[1][2] * in2[2][3] + in1[1][3];\n\tout[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + in1[2][2] * in2[2][0];\n\tout[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + in1[2][2] * in2[2][1];\n\tout[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + in1[2][2] * in2[2][2];\n\tout[2][3] = in1[2][0] * in2[0][3] + in1[2][1] * in2[1][3] + in1[2][2] * in2[2][3] + in1[2][3];\n}\n\n\n/*\n===================\nFloorDivMod\n\nReturns mathematically correct (floor-based) quotient and remainder for\nnumer and denom, both of which should contain no fractional part. The\nquotient must fit in 32 bits.\n====================\n*/\n\nvoid FloorDivMod(double numer, double denom, int *quotient,\n\tint *rem)\n{\n\tint\t\tq, r;\n\tdouble\tx;\n\n#ifndef PARANOID\n\tif (denom <= 0.0)\n\t\tSys_Error(\"FloorDivMod: bad denominator %d\\n\", denom);\n\n\t//\tif ((floor(numer) != numer) || (floor(denom) != denom))\n\t//\t\tSys_Error (\"FloorDivMod: non-integer numer or denom %f %f\\n\",\n\t//\t\t\t\tnumer, denom);\n#endif\n\n\tif (numer >= 0.0)\n\t{\n\n\t\tx = floor(numer / denom);\n\t\tq = (int)x;\n\t\tr = (int)floor(numer - (x * denom));\n\t}\n\telse\n\t{\n\t\t//\n\t\t// perform operations with positive values, and fix mod to make floor-based\n\t\t//\n\t\tx = floor(-numer / denom);\n\t\tq = -(int)x;\n\t\tr = (int)floor(-numer - (x * denom));\n\t\tif (r != 0)\n\t\t{\n\t\t\tq--;\n\t\t\tr = (int)denom - r;\n\t\t}\n\t}\n\n\t*quotient = q;\n\t*rem = r;\n}\n\n\n/*\n===================\nGreatestCommonDivisor\n====================\n*/\nint GreatestCommonDivisor(int i1, int i2)\n{\n\tif (i1 > i2)\n\t{\n\t\tif (i2 == 0)\n\t\t\treturn (i1);\n\t\treturn GreatestCommonDivisor(i2, i1 % i2);\n\t}\n\telse\n\t{\n\t\tif (i1 == 0)\n\t\t\treturn (i2);\n\t\treturn GreatestCommonDivisor(i1, i2 % i1);\n\t}\n}\n\n\n#if\t!id386\n\n// TODO: move to nonintel.c\n\n/*\n===================\nInvert24To16\n\nInverts an 8.24 value to a 16.16 value\n====================\n*/\n\nfixed16_t Invert24To16(fixed16_t val)\n{\n\tif (val < 256)\n\t\treturn (0xFFFFFFFF);\n\n\treturn (fixed16_t)\n\t\t(((double)0x10000 * (double)0x1000000 / (double)val) + 0.5);\n}\n\n#endif\n\nint ParseFloats(const signed char *s, float *f, int *f_size) {\n\tint i, argc;\n\n\tif (!s || !f || !f_size)\n\t\tSys_Error(\"ParseFloats() wrong params\");\n\n\tif (f_size[0] <= 0)\n\t\treturn (f_size[0] = 0); // array have no size, unusual but no crime\n\n\tCmd_TokenizeString(s);\n\targc = min(Cmd_Argc(), f_size[0]);\n\n\tfor (i = 0; i < argc; i++)\n\t\tf[i] = atof(Cmd_Argv(i));\n\n\tfor (; i < f_size[0]; i++)\n\t\tf[i] = 0; // zeroing unused elements\n\n\treturn (f_size[0] = argc);\n}\n"
  },
  {
    "path": "source/mathlib.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// mathlib.h\n\n#include <limits.h>\n\ntypedef float vec_t;\ntypedef vec_t vec3_t[3];\ntypedef vec_t vec5_t[5];\n\ntypedef\tint\tfixed4_t;\ntypedef\tint\tfixed8_t;\ntypedef\tint\tfixed16_t;\n#define FIXED16_MAX INT_MAX;\n\n#define DEG2RAD(a) ((a * M_PI) / 180.0f)\n\nstruct mplane_s;\n\nextern vec3_t vec3_origin;\n\n/// LordHavoc: this function never returns exactly MIN or exactly MAX, because\n/// of a QuakeC bug in id1 where the line\n/// self.nextthink = self.nexthink + random() * 0.5;\n/// can result in 0 (self.nextthink is 0 at this point in the code to begin\n/// with), causing \"stone monsters\" that never spawned properly, also MAX is\n/// avoided because some people use random() as an index into arrays or for\n/// loop conditions, where hitting exactly MAX may be a fatal error\n#define lhrandom(MIN,MAX) (((double)(rand() + 0.5) / ((double)RAND_MAX + 1)) * ((MAX)-(MIN)) + (MIN))\n\n#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2])\n#define VectorSubtract(a,b,out) {out[0]=a[0]-b[0];out[1]=a[1]-b[1];out[2]=a[2]-b[2];}\n#define VectorAdd(a,b,out) {out[0]=a[0]+b[0];out[1]=a[1]+b[1];out[2]=a[2]+b[2];}\n#define VectorCopy(a,out) {out[0]=a[0];out[1]=a[1];out[2]=a[2];}\n#define VectorClear(a) ((a)[0] = (a)[1] = (a)[2] = 0)\n#define VectorNegate(a, out) ((out)[0] = -(a)[0], (out)[1] = -(a)[1], (out)[2] = -(a)[2])\n#define VectorRandom(v) do{(v)[0] = lhrandom(-1, 1);(v)[1] = lhrandom(-1, 1);(v)[2] = lhrandom(-1, 1);}while(DotProduct(v, v) > 1)\n\t\nvoid VectorMA (vec3_t veca, float scale, vec3_t vecb, vec3_t vecc);\n\nvec_t _DotProduct (vec3_t v1, vec3_t v2);\nvoid _VectorSubtract (vec3_t veca, vec3_t vecb, vec3_t out);\nvoid _VectorAdd (vec3_t veca, vec3_t vecb, vec3_t out);\nvoid _VectorCopy (vec3_t in, vec3_t out);\n\nint VectorCompare (vec3_t v1, vec3_t v2);\nvec_t Length (vec3_t v);\nvoid CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross);\nfloat VectorNormalize (vec3_t v);\t\t// returns vector length\nvoid VectorInverse (vec3_t v);\nvoid VectorScale (vec3_t in, vec_t scale, vec3_t out);\nint Q_log2(int val);\n\nvoid R_ConcatRotations (float in1[3][3], float in2[3][3], float out[3][3]);\nvoid R_ConcatTransforms (float in1[3][4], float in2[3][4], float out[3][4]);\n\nvoid FloorDivMod (double numer, double denom, int *quotient,\n\t\tint *rem);\nfixed16_t Invert24To16(fixed16_t val);\nint GreatestCommonDivisor (int i1, int i2);\n\nvoid AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up);\nint BoxOnPlaneSide (vec3_t emins, vec3_t emaxs, struct mplane_s *plane);\nfloat\tanglemod(float a);\n\n\n\n#define BOX_ON_PLANE_SIDE(emins, emaxs, p)\t\\\n\t(((p)->type < 3)?\t\t\t\t\t\t\\\n\t(\t\t\t\t\t\t\t\t\t\t\\\n\t\t((p)->dist <= (emins)[(p)->type])?\t\\\n\t\t\t1\t\t\t\t\t\t\t\t\\\n\t\t:\t\t\t\t\t\t\t\t\t\\\n\t\t(\t\t\t\t\t\t\t\t\t\\\n\t\t\t((p)->dist >= (emaxs)[(p)->type])?\\\n\t\t\t\t2\t\t\t\t\t\t\t\\\n\t\t\t:\t\t\t\t\t\t\t\t\\\n\t\t\t\t3\t\t\t\t\t\t\t\\\n\t\t)\t\t\t\t\t\t\t\t\t\\\n\t)\t\t\t\t\t\t\t\t\t\t\\\n\t:\t\t\t\t\t\t\t\t\t\t\\\n\t\tBoxOnPlaneSide( (emins), (emaxs), (p)))\n\t\t\nint ParseFloats(const signed char *s, float *f, int *f_size);\n"
  },
  {
    "path": "source/menu.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\nCopyright (C) 2020 Asakura Reiko\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include <vitasdk.h>\n#include \"quakedef.h\"\n#include \"net_dgrm.h\"\n\nchar res_string[256];\nCVAR (vid_vsync, 1, CVAR_ARCHIVE)\nextern cvar_t\tfov;\nextern cvar_t\tcrosshair;\nextern cvar_t\tinvert_camera;\nextern cvar_t\tpstv_rumble;\nextern cvar_t\tretrotouch;\nextern cvar_t\tscr_sbaralpha;\nextern cvar_t\tmotioncam;\nextern cvar_t\tmotion_horizontal_sensitivity;\nextern cvar_t\tmotion_vertical_sensitivity;\nextern cvar_t\tgl_torchflares;\nextern cvar_t\tshow_fps;\nextern cvar_t\tgl_fog;\nextern cvar_t\tgl_outline;\nextern cvar_t\tr_viewmodeloffset;\nextern cvar_t\tst_separation;\nextern int scr_width;\nextern int scr_height;\nextern uint8_t is_uma0;\nint cfg_width;\nint cfg_height;\nextern cvar_t gl_bilinear;\nint m_state = m_none;\n\nextern ModsList* mods;\nextern int max_mod_idx;\n\nvoid (*vid_menudrawfn)(void);\nvoid (*vid_menukeyfn)(int key);\n\nvoid M_Menu_Main_f (void);\n\tvoid M_Menu_SinglePlayer_f (void);\n\t\tvoid M_Menu_Load_f (void);\n\t\tvoid M_Menu_Save_f (void);\n\tvoid M_Menu_MultiPlayer_f (void);\n\t\tvoid M_Menu_Setup_f (void);\n\t\tvoid M_Menu_Net_f (void);\n\t\t\tvoid M_Menu_OnlineServerList_f (void);\n\tvoid M_Menu_Options_f (void);\n\t\tvoid M_Menu_Keys_f (void);\n\t\tvoid M_Menu_Video_f (void);\n\tvoid M_Menu_Help_f (void);\n\tvoid M_Menu_Quit_f (void);\nvoid M_Menu_LanConfig_f (void);\nvoid M_Menu_GameOptions_f (void);\nvoid M_Menu_Search_f (void);\nvoid M_Menu_ServerList_f (void);\n\nvoid M_Main_Draw (void);\n\tvoid M_SinglePlayer_Draw (void);\n\t\tvoid M_Load_Draw (void);\n\t\tvoid M_Save_Draw (void);\n\tvoid M_MultiPlayer_Draw (void);\n\t\tvoid M_Setup_Draw (void);\n\t\tvoid M_Net_Draw (void);\n\t\t\tvoid M_OnlineServerList_Draw (void);\n\tvoid M_Options_Draw (void);\n\t\tvoid M_Keys_Draw (void);\n\t\tvoid M_Graphics_Draw (void);\n\t\tvoid M_Video_Draw (void);\n\t\tvoid M_Mods_Draw (void);\n\tvoid M_Help_Draw (void);\n\tvoid M_Quit_Draw (void);\nvoid M_LanConfig_Draw (void);\nvoid M_GameOptions_Draw (void);\nvoid M_Search_Draw (void);\nvoid M_ServerList_Draw (void);\n\nvoid M_Main_Key (int key);\n\tvoid M_SinglePlayer_Key (int key);\n\t\tvoid M_Load_Key (int key);\n\t\tvoid M_Save_Key (int key);\n\tvoid M_MultiPlayer_Key (int key);\n\t\tvoid M_Setup_Key (int key);\n\t\tvoid M_Net_Key (int key);\n\t\t\tvoid M_OnlineServerList_Key (int key);\n\tvoid M_Options_Key (int key);\n\t\tvoid M_Keys_Key (int key);\n\t\tvoid M_Graphics_Key (int key);\n\t\tvoid M_Video_Key (int key);\n\t\tvoid M_Mods_key (int key);\n\tvoid M_Help_Key (int key);\n\tvoid M_Quit_Key (int key);\nvoid M_LanConfig_Key (int key);\nvoid M_GameOptions_Key (int key);\nvoid M_Search_Key (int key);\nvoid M_ServerList_Key (int key);\n\nbool\tm_entersound;\t\t// play after drawing a frame, so caching\n\t\t\t\t\t\t\t\t// won't disrupt the sound\nbool\tm_recursiveDraw;\n\nint\t\t\tm_return_state;\nbool\tm_return_onerror;\nchar\t\tm_return_reason [32];\n\n#define StartingGame\t(m_multiplayer_cursor == 1)\n#define JoiningGame\t\t(m_multiplayer_cursor == 0)\n#define SerialConfig\t(m_net_cursor == 0)\n#define DirectConfig\t(m_net_cursor == 1)\n#define\tIPXConfig\t\t(m_net_cursor == 2)\n#define\tTCPIPConfig\t\t(m_net_cursor == 3)\n\nvoid M_ConfigureNetSubsystem(void);\n\nint antialiasing = 2;\nuint8_t netcheck_dialog_running = 0;\n\nvoid SetResolution(int w, int h){\n\tchar res_str[64];\n\tFILE *f = NULL;\n\tif (is_uma0) f = fopen(\"uma0:data/Quake/resolution.cfg\", \"wb\");\n\telse f = fopen(\"ux0:data/Quake/resolution.cfg\", \"wb\");\n\tsprintf(res_str, \"%dx%d\", w, h);\n\tfwrite(res_str, 1, strlen(res_str), f);\n\tfclose(f);\n\tcfg_width = w;\n\tcfg_height = h;\n}\n\nvoid SetAntiAliasing(int m){\n\tchar res_str[64];\n\tFILE *f = NULL;\n\tif (is_uma0) f = fopen(\"uma0:data/Quake/antialiasing.cfg\", \"wb\");\n\telse f = fopen(\"ux0:data/Quake/antialiasing.cfg\", \"wb\");\n\tsprintf(res_str, \"%d\", m);\n\tfwrite(res_str, 1, strlen(res_str), f);\n\tfclose(f);\n}\n\nvoid M_DrawColorBar (int x, int y, int highlight)\n{\n    int i;\n    int intense = highlight * 16 + (highlight < 8 ? 11 : 4);\n\n    for (i = 0; i < 14; i++)\n    {\n        // take the approximate midpoint colour (handle backward ranges)\n        int c = i * 16 + (i < 8 ? 8 : 7);\n\n        // braw baseline colour (offset downwards a little so that it fits correctly\n        Draw_Fill (x + i * 8, y + 4, 8, 8, c);\n    }\n\n    // draw the highlight rectangle\n    Draw_Fill (x - 1 + highlight * 8, y + 3, 10, 10, 15);\n\n    // redraw the highlighted color at brighter intensity\n    Draw_Fill (x + highlight * 8, y + 4, 8, 8, intense);\n}\n\n/*\n================\nM_DrawCharacter\n\nDraws one solid graphics character\n================\n*/\nvoid M_DrawCharacter (int cx, int line, int num)\n{\n\tBatch_Character ( cx, line, num);\n}\n\nvoid M_Print (int cx, int cy, char *str)\n{\n\tBatch_String(cx, cy, str, 128);\n}\n\nvoid M_PrintCentered (int cy, char *str)\n{\n\tint cx = 160 - strlen(str) * 4;\n\tBatch_String(cx, cy, str, 128);\n}\n\n\nvoid M_PrintWhite (int cx, int cy, char *str)\n{\n\tBatch_String(cx, cy, str, 0);\n}\n\nvoid M_DrawTransPic (int x, int y, qpic_t *pic)\n{\n\tDraw_TransPic (x, y, pic);\n}\n\nvoid M_DrawPic (int x, int y, qpic_t *pic)\n{\n\tDraw_Pic (x, y, pic);\n}\n\nbyte identityTable[256];\nbyte translationTable[256];\n\nvoid M_BuildTranslationTable(int top, int bottom)\n{\n\tint\t\tj;\n\tbyte\t*dest, *source;\n\n\tfor (j = 0; j < 256; j++)\n\t\tidentityTable[j] = j;\n\tdest = translationTable;\n\tsource = identityTable;\n\tmemcpy (dest, source, 256);\n\n\tif (top < 128)\t// the artists made some backwards ranges.  sigh.\n\t\tmemcpy (dest + TOP_RANGE, source + top, 16);\n\telse\n\t\tfor (j=0 ; j<16 ; j++)\n\t\t\tdest[TOP_RANGE+j] = source[top+15-j];\n\n\tif (bottom < 128)\n\t\tmemcpy (dest + BOTTOM_RANGE, source + bottom, 16);\n\telse\n\t\tfor (j=0 ; j<16 ; j++)\n\t\t\tdest[BOTTOM_RANGE+j] = source[bottom+15-j];\n}\n\n\nvoid M_DrawTransPicTranslate (int x, int y, qpic_t *pic)\n{\n\tDraw_TransPicTranslate (x, y, pic, translationTable);\n}\n\n\nvoid M_DrawTextBox (int x, int y, int width, int lines)\n{\n\tqpic_t\t*p;\n\tint\t\tcx, cy;\n\tint\t\tn;\n\n\t// draw left side\n\tcx = x;\n\tcy = y;\n\tp = Draw_CachePic (\"gfx/box_tl.lmp\");\n\tM_DrawTransPic (cx, cy, p);\n\tp = Draw_CachePic (\"gfx/box_ml.lmp\");\n\tfor (n = 0; n < lines; n++)\n\t{\n\t\tcy += 8;\n\t\tM_DrawTransPic (cx, cy, p);\n\t}\n\tp = Draw_CachePic (\"gfx/box_bl.lmp\");\n\tM_DrawTransPic (cx, cy+8, p);\n\n\t// draw middle\n\tcx += 8;\n\twhile (width > 0)\n\t{\n\t\tcy = y;\n\t\tp = Draw_CachePic (\"gfx/box_tm.lmp\");\n\t\tM_DrawTransPic (cx, cy, p);\n\t\tp = Draw_CachePic (\"gfx/box_mm.lmp\");\n\t\tfor (n = 0; n < lines; n++)\n\t\t{\n\t\t\tcy += 8;\n\t\t\tif (n == 1)\n\t\t\t\tp = Draw_CachePic (\"gfx/box_mm2.lmp\");\n\t\t\tM_DrawTransPic (cx, cy, p);\n\t\t}\n\t\tp = Draw_CachePic (\"gfx/box_bm.lmp\");\n\t\tM_DrawTransPic (cx, cy+8, p);\n\t\twidth -= 2;\n\t\tcx += 16;\n\t}\n\n\t// draw right side\n\tcy = y;\n\tp = Draw_CachePic (\"gfx/box_tr.lmp\");\n\tM_DrawTransPic (cx, cy, p);\n\tp = Draw_CachePic (\"gfx/box_mr.lmp\");\n\tfor (n = 0; n < lines; n++)\n\t{\n\t\tcy += 8;\n\t\tM_DrawTransPic (cx, cy, p);\n\t}\n\tp = Draw_CachePic (\"gfx/box_br.lmp\");\n\tM_DrawTransPic (cx, cy+8, p);\n}\n\n//=============================================================================\n\nint m_save_demonum;\n\n/*\n================\nM_ToggleMenu_f\n================\n*/\nvoid M_ToggleMenu_f (void)\n{\n\tm_entersound = true;\n\n\tif (key_dest == key_menu)\n\t{\n\t\tif (m_state != m_main)\n\t\t{\n\t\t\tM_Menu_Main_f ();\n\t\t\treturn;\n\t\t}\n\t\tkey_dest = key_game;\n\t\tm_state = m_none;\n\t\treturn;\n\t}\n\tif (key_dest == key_console)\n\t{\n\t\tCon_ToggleConsole_f ();\n\t}\n\telse\n\t{\n\t\tM_Menu_Main_f ();\n\t}\n}\n\n\n//=============================================================================\n/* MAIN MENU */\n\nint\tm_main_cursor;\n#define\tMAIN_ITEMS\t5\n\n\nvoid M_Menu_Main_f (void)\n{\n\tif (key_dest != key_menu)\n\t{\n\t\tm_save_demonum = cls.demonum;\n\t\tcls.demonum = -1;\n\t}\n\tkey_dest = key_menu;\n\tm_state = m_main;\n\tm_entersound = true;\n}\n\n\nvoid M_Main_Draw (void)\n{\n\tint\t\tf;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/ttl_main.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tM_DrawTransPic (72, 32, Draw_CachePic (\"gfx/mainmenu.lmp\") );\n\n\tf = (int)(host_time * 10)%6;\n\n\tM_DrawTransPic (54, 32 + m_main_cursor * 20,Draw_CachePic( va(\"gfx/menudot%i.lmp\", f+1 ) ) );\n\t\n\tM_PrintCentered (190, \" Thanks for the awesome support \");\n\tM_PrintCentered (198, \"         on Patreon to:         \");\n\tM_PrintCentered (206, \"     Tain Sueiras, polytoad     \");\n\tM_PrintCentered (214, \"  drd7of14, The Vita3K Project  \");\n\tDraw_Batched();\n}\n\n\nvoid M_Main_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tkey_dest = key_game;\n\t\tm_state = m_none;\n\t\tcls.demonum = m_save_demonum;\n\t\tif (cls.demonum != -1 && !cls.demoplayback && cls.state != ca_connected)\n\t\t\tCL_NextDemo ();\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (++m_main_cursor >= MAIN_ITEMS)\n\t\t\tm_main_cursor = 0;\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (--m_main_cursor < 0)\n\t\t\tm_main_cursor = MAIN_ITEMS - 1;\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_entersound = true;\n\n\t\tswitch (m_main_cursor)\n\t\t{\n\t\tcase 0:\n\t\t\tM_Menu_SinglePlayer_f ();\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tM_Menu_MultiPlayer_f ();\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tM_Menu_Options_f ();\n\t\t\tbreak;\n\n\t\tcase 3:\n\t\t\tM_Menu_Help_f ();\n\t\t\tbreak;\n\n\t\tcase 4:\n\t\t\tM_Menu_Quit_f ();\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n//=============================================================================\n/* SINGLE PLAYER MENU */\n\nint\tm_singleplayer_cursor;\n#define\tSINGLEPLAYER_ITEMS\t3\n\n\nvoid M_Menu_SinglePlayer_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_singleplayer;\n\tm_entersound = true;\n}\n\n\nvoid M_SinglePlayer_Draw (void)\n{\n\tint\t\tf;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/ttl_sgl.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tM_DrawTransPic (72, 32, Draw_CachePic (\"gfx/sp_menu.lmp\") );\n\n\tf = (int)(host_time * 10)%6;\n\n\tM_DrawTransPic (54, 32 + m_singleplayer_cursor * 20,Draw_CachePic( va(\"gfx/menudot%i.lmp\", f+1 ) ) );\n}\n\n\nvoid M_SinglePlayer_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Main_f ();\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (++m_singleplayer_cursor >= SINGLEPLAYER_ITEMS)\n\t\t\tm_singleplayer_cursor = 0;\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (--m_singleplayer_cursor < 0)\n\t\t\tm_singleplayer_cursor = SINGLEPLAYER_ITEMS - 1;\n\t\tbreak;\n\n\tcase K_CROSS: // Cross\n\tcase K_CIRCLE: // Circle\n\t\tm_entersound = true;\n\n\t\tswitch (m_singleplayer_cursor)\n\t\t{\n\t\tcase 0:\n\t\t\tkey_dest = key_game;\n\t\t\tCbuf_AddText (\"disconnect\\n\");\t// Ch0wW: Disconnect all the time to reset original NetQuake behaviour.\n\t\t\tCbuf_AddText (\"maxplayers 1\\n\");\n\t\t\tCbuf_AddText (\"map start\\n\");\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tM_Menu_Load_f ();\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tM_Menu_Save_f ();\n\t\t\tbreak;\n\t\t}\n\n\t}\n}\n\n//=============================================================================\n/* LOAD/SAVE MENU */\n\nint\t\tload_cursor;\t\t// 0 < load_cursor < MAX_SAVEGAMES\n\n#define\tMAX_SAVEGAMES\t\t12\nchar\tm_filenames[MAX_SAVEGAMES][SAVEGAME_COMMENT_LENGTH+1];\nint\t\tloadable[MAX_SAVEGAMES];\n\nvoid M_ScanSaves (void)\n{\n\tint\t\ti, j;\n\tchar\tname[MAX_OSPATH];\n\tFILE\t*f;\n\tint\t\tversion;\n\n\tfor (i=0 ; i<MAX_SAVEGAMES ; i++)\n\t{\n\t\tstrcpy (m_filenames[i], \"--- UNUSED SLOT ---\");\n\t\tloadable[i] = false;\n\t\tsprintf (name, \"%s/s%i.sav\", com_gamedir, i);\n\t\tf = fopen (name, \"r\");\n\t\tif (!f)\n\t\t\tcontinue;\n\t\tfscanf (f, \"%i\\n\", &version);\n\t\tfscanf (f, \"%79s\\n\", name);\n\t\tstrncpy (m_filenames[i], name, sizeof(m_filenames[i])-1);\n\n\t// change _ back to space\n\t\tfor (j=0 ; j<SAVEGAME_COMMENT_LENGTH ; j++)\n\t\t\tif (m_filenames[i][j] == '_')\n\t\t\t\tm_filenames[i][j] = ' ';\n\t\tloadable[i] = true;\n\t\tfclose (f);\n\t}\n}\n\nvoid M_Menu_Load_f (void)\n{\n\tm_entersound = true;\n\tm_state = m_load;\n\tkey_dest = key_menu;\n\tM_ScanSaves ();\n}\n\n\nvoid M_Menu_Save_f (void)\n{\n\tif (!sv.active)\n\t\treturn;\n\tif (cl.intermission)\n\t\treturn;\n\tif (svs.maxclients != 1)\n\t\treturn;\n\tm_entersound = true;\n\tm_state = m_save;\n\tkey_dest = key_menu;\n\tM_ScanSaves ();\n}\n\n\nvoid M_Load_Draw (void)\n{\n\tint\t\ti;\n\tqpic_t\t*p;\n\n\tp = Draw_CachePic (\"gfx/p_load.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tfor (i=0 ; i< MAX_SAVEGAMES; i++)\n\t\tM_Print (16, 32 + 8*i, m_filenames[i]);\n\n// line cursor\n\tM_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Save_Draw (void)\n{\n\tint\t\ti;\n\tqpic_t\t*p;\n\n\tp = Draw_CachePic (\"gfx/p_save.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tfor (i=0 ; i<MAX_SAVEGAMES ; i++)\n\t\tM_Print (16, 32 + 8*i, m_filenames[i]);\n\n// line cursor\n\tM_DrawCharacter (8, 32 + load_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Load_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_SinglePlayer_f ();\n\t\tbreak;\n\n\tcase K_CIRCLE: // Circle\n\tcase K_CROSS: // Cross\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tif (!loadable[load_cursor])\n\t\t\treturn;\n\t\tm_state = m_none;\n\t\tkey_dest = key_game;\n\n\t// Host_Loadgame_f can't bring up the loading plaque because too much\n\t// stack space has been used, so do it now\n\t\tSCR_BeginLoadingPlaque ();\n\n\t// issue the load command\n\t\tCbuf_AddText (va (\"load s%i\\n\", load_cursor) );\n\t\treturn;\n\n\tcase K_UPARROW:\n\tcase K_LEFTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tload_cursor--;\n\t\tif (load_cursor < 0)\n\t\t\tload_cursor = MAX_SAVEGAMES-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\tcase K_RIGHTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tload_cursor++;\n\t\tif (load_cursor >= MAX_SAVEGAMES)\n\t\t\tload_cursor = 0;\n\t\tbreak;\n\t}\n}\n\n\nvoid M_Save_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_SinglePlayer_f ();\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_state = m_none;\n\t\tkey_dest = key_game;\n\t\tCbuf_AddText (va(\"save s%i\\n\", load_cursor));\n\t\treturn;\n\n\tcase K_UPARROW:\n\tcase K_LEFTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tload_cursor--;\n\t\tif (load_cursor < 0)\n\t\t\tload_cursor = MAX_SAVEGAMES-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\tcase K_RIGHTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tload_cursor++;\n\t\tif (load_cursor >= MAX_SAVEGAMES)\n\t\t\tload_cursor = 0;\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* MULTIPLAYER MENU */\n\nint\tm_multiplayer_cursor;\n#define\tMULTIPLAYER_ITEMS\t3\n\n\nvoid M_Menu_MultiPlayer_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_multiplayer;\n\tm_entersound = true;\n}\n\n\nvoid M_MultiPlayer_Draw (void)\n{\n\tint\t\tf;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tM_DrawTransPic (72, 32, Draw_CachePic (\"gfx/mp_menu.lmp\") );\n\n\tf = (int)(host_time * 10)%6;\n\n\tM_DrawTransPic (54, 32 + m_multiplayer_cursor * 20,Draw_CachePic( va(\"gfx/menudot%i.lmp\", f+1 ) ) );\n\n\tif (tcpipAvailable)\n\t\treturn;\n\n\tDraw_String ((320/2) - ((27*8)/2), 148, \"No Communications Available\", 0);\n}\n\n\nvoid M_MultiPlayer_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Main_f ();\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (++m_multiplayer_cursor >= MULTIPLAYER_ITEMS)\n\t\t\tm_multiplayer_cursor = 0;\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (--m_multiplayer_cursor < 0)\n\t\t\tm_multiplayer_cursor = MULTIPLAYER_ITEMS - 1;\n\t\tbreak;\n\n\tcase K_CIRCLE: // Circle\n\tcase K_CROSS: // Cross\n\t\tm_entersound = true;\n\t\tswitch (m_multiplayer_cursor)\n\t\t{\n\t\tcase 0:\n\t\t\tif (tcpipAvailable)\n\t\t\t\tM_Menu_Net_f ();\n\t\t\tbreak;\n\n\t\tcase 1:\n\t\t\tif (tcpipAvailable)\n\t\t\t\tM_Menu_Net_f ();\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tM_Menu_Setup_f ();\n\t\t\tbreak;\n\t\t}\n\n\t}\n}\n\n//=============================================================================\n/* BENCHMARK MENU */\n\nvoid M_Menu_Benchmark_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_benchmark;\n\tm_entersound = true;\n}\n\nextern int max_fps;\nextern int min_fps;\nextern int average_fps;\nvoid M_Benchmark_Draw (void)\n{\n\tchar s[80],s1[80],s2[80];\n\tsprintf(s, \"    Max FPS: %3d\", max_fps);\n\tsprintf(s1, \"    Min FPS: %3d\", min_fps);\n\tsprintf(s2, \"Average FPS: %3d\", average_fps);\n\tM_Print(30, 20, \"Benchmark results\");\n\tM_Print (64, 40, s);\n\tM_Print (64, 48, s1);\n\tM_Print (64, 56, s2);\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Benchmark_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\tcase K_CIRCLE: // Circle\n\tcase K_CROSS: // Cross\n\t\tM_Menu_Options_f ();\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* SETUP MENU */\n\nint\t\tsetup_cursor = 4;\nint\t\tsetup_cursor_table[] = {40, 56, 80, 104, 140};\n\nchar\tsetup_hostname[16];\nchar\tsetup_myname[16];\nint\t\tsetup_oldtop;\nint\t\tsetup_oldbottom;\nint\t\tsetup_top;\nint\t\tsetup_bottom;\n\n#define\tNUM_SETUP_CMDS\t5\n\nvoid M_Menu_Setup_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_setup;\n\tm_entersound = true;\n\tstrcpy(setup_myname, cl_name.string);\n\tstrcpy(setup_hostname, hostname.string);\n\tsetup_top = setup_oldtop = ((int)cl_color.value) >> 4;\n\tsetup_bottom = setup_oldbottom = ((int)cl_color.value) & 15;\n}\n\n\nvoid M_Setup_Draw (void)\n{\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tM_DrawTextBox (160, 32, 16, 1);\n\tM_DrawTextBox (160, 48, 16, 1);\n    M_DrawColorBar (64, 88, setup_top);\n    M_DrawColorBar (64, 112, setup_bottom);\n\tM_DrawTextBox (64, 140-8, 14, 1);\n\tp = Draw_CachePic (\"gfx/bigbox.lmp\");\n\tM_DrawTransPic (176, 64, p);\n\tp = Draw_CachePic (\"gfx/menuplyr.lmp\");\n\tM_BuildTranslationTable(setup_top*16, setup_bottom*16);\n\tM_DrawTransPicTranslate (188, 72, p);\n\t\n\tM_Print (64, 40, \"Hostname\");\n\tM_Print (168, 40, setup_hostname);\n\tM_Print (64, 56, \"Your name\");\n\tM_Print (168, 56, setup_myname);\n\tM_Print (64, 80, \"Shirt color\");\n\tM_Print (64, 104, \"Pants color\");\n\tM_Print (72, 140, \"Accept Changes\");\n\t\n\tM_DrawCharacter (56, setup_cursor_table [setup_cursor], 12+((int)(realtime*4)&1));\n\n\tif (setup_cursor == 0)\n\t\tM_DrawCharacter (168 + 8*strlen(setup_hostname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));\n\n\tif (setup_cursor == 1)\n\t\tM_DrawCharacter (168 + 8*strlen(setup_myname), setup_cursor_table [setup_cursor], 10+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Setup_Key (int k)\n{\n\tint\t\t\tl;\n\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_MultiPlayer_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tsetup_cursor--;\n\t\tif (setup_cursor < 0)\n\t\t\tsetup_cursor = NUM_SETUP_CMDS-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tsetup_cursor++;\n\t\tif (setup_cursor >= NUM_SETUP_CMDS)\n\t\t\tsetup_cursor = 0;\n\t\tbreak;\n\n\tcase K_LEFTARROW:\n\t\tif (setup_cursor < 2)\n\t\t\treturn;\n\t\tS_LocalSound (\"misc/menu3.wav\");\n\t\tif (setup_cursor == 2)\n\t\t\tsetup_top = setup_top - 1;\n\t\tif (setup_cursor == 3)\n\t\t\tsetup_bottom = setup_bottom - 1;\n\t\tbreak;\n\tcase K_RIGHTARROW:\n\t\tif (setup_cursor < 2)\n\t\t\treturn;\nforward:\n\t\tS_LocalSound (\"misc/menu3.wav\");\n\t\tif (setup_cursor == 2)\n\t\t\tsetup_top = setup_top + 1;\n\t\tif (setup_cursor == 3)\n\t\t\tsetup_bottom = setup_bottom + 1;\n\t\tbreak;\n\n\tcase K_CIRCLE: // Circle\n\tcase K_CROSS: // Cross\n\t\tif (setup_cursor == 0 || setup_cursor == 1)\n\t\t\treturn;\n\n\t\tif (setup_cursor == 2 || setup_cursor == 3)\n\t\t\tgoto forward;\n\n\t\t// setup_cursor == 4 (OK)\n\t\tif (strcmp(cl_name.string, setup_myname) != 0)\n\t\t\tCbuf_AddText ( va (\"name \\\"%s\\\"\\n\", setup_myname) );\n\t\tif (strcmp(hostname.string, setup_hostname) != 0)\n\t\t\tCvar_Set(\"hostname\", setup_hostname);\n\t\tif (setup_top != setup_oldtop || setup_bottom != setup_oldbottom)\n\t\t\tCbuf_AddText( va (\"color %i %i\\n\", setup_top, setup_bottom) );\n\t\tm_entersound = true;\n\t\tM_Menu_MultiPlayer_f ();\n\t\tbreak;\n\n\tcase K_BACKSPACE:\n\t\tif (setup_cursor == 0)\n\t\t{\n\t\t\tif (strlen(setup_hostname))\n\t\t\t\tsetup_hostname[strlen(setup_hostname)-1] = 0;\n\t\t}\n\n\t\tif (setup_cursor == 1)\n\t\t{\n\t\t\tif (strlen(setup_myname))\n\t\t\t\tsetup_myname[strlen(setup_myname)-1] = 0;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tif (k < 32 || k > 127)\n\t\t\tbreak;\n\t\tif (setup_cursor == 0)\n\t\t{\n\t\t\tl = strlen(setup_hostname);\n\t\t\tif (l < 15)\n\t\t\t{\n\t\t\t\tsetup_hostname[l+1] = 0;\n\t\t\t\tsetup_hostname[l] = k;\n\t\t\t}\n\t\t}\n\t\tif (setup_cursor == 1)\n\t\t{\n\t\t\tl = strlen(setup_myname);\n\t\t\tif (l < 15)\n\t\t\t{\n\t\t\t\tsetup_myname[l+1] = 0;\n\t\t\t\tsetup_myname[l] = k;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (setup_top > 13)\n\t\tsetup_top = 0;\n\tif (setup_top < 0)\n\t\tsetup_top = 13;\n\tif (setup_bottom > 13)\n\t\tsetup_bottom = 0;\n\tif (setup_bottom < 0)\n\t\tsetup_bottom = 13;\n}\n\n//=============================================================================\n/* NET MENU */\n\nint\tm_net_cursor;\nint m_net_items;\nint m_net_saveHeight;\n\nchar *net_helpMessage [] =\n{\n/* .........1.........2.... */\n  \" Commonly used to play  \",\n  \" over the Internet, but \",\n  \" also used on a Local   \",\n  \" Area Network.          \"\n};\n\nvoid M_Menu_Net_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_net;\n\tm_entersound = true;\n\tm_net_items = 1;\n\n\tif (m_net_cursor >= m_net_items)\n\t\tm_net_cursor = 0;\n\tm_net_cursor--;\n\tM_Net_Key (K_DOWNARROW);\n}\n\n\nvoid M_Net_Draw (void)\n{\n\tint\t\tf;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tf = 32;\n\n\tif (tcpipAvailable)\n\t\tp = Draw_CachePic (\"gfx/netmen4.lmp\");\n\telse\n\t\tp = Draw_CachePic (\"gfx/dim_tcp.lmp\");\n\tM_DrawTransPic (72, f, p);\n\n\tf = (320-26*8)/2;\n\tM_DrawTextBox (f, 134, 24, 4);\n\tf += 8;\n\tDraw_String (f, 166, net_helpMessage[m_net_cursor*4+0], 128);\n\n\tf = (int)(host_time * 10)%6;\n\tM_DrawTransPic (54, 32 + m_net_cursor * 20,Draw_CachePic( va(\"gfx/menudot%i.lmp\", f+1 ) ) );\n}\n\n\nvoid M_Net_Key (int k)\n{\n\tM_Menu_LanConfig_f();\n}\n\n//=============================================================================\n/* MODS MENU */\n\nint\t\tmods_cursor;\n\nvoid M_Menu_Mods_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_mods;\n\tm_entersound = true;\n}\n\nModsList *cur = NULL;\n\nvoid M_Mods_Draw (void)\n{\n\tfloat\t\tr;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\n\tM_Print (60, 10, \"Select the mod to load\");\n\n\tModsList *ptr = mods;\n\tint j = 0;\n\twhile (ptr != NULL) {\n\t\tM_Print (60, 32 + j * 8, ptr->name);\n\t\tif (j == mods_cursor) cur = ptr;\n\t\tptr = ptr->next;\n\t\tj++;\n\t}\n\n\t// cursor\n\tM_DrawCharacter (50, 32 + mods_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Mods_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Options_f ();\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_entersound = true;\n\t\tchar cmd[128];\n\t\tsprintf(cmd, \"game %s\\n\", cur->name);\n\t\tCbuf_AddText (cmd);\n\t\tM_Menu_Main_f ();\n\t\treturn;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tmods_cursor--;\n\t\tif (mods_cursor < 0)\n\t\t\tmods_cursor = max_mod_idx;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tmods_cursor++;\n\t\tif (mods_cursor > max_mod_idx)\n\t\t\tmods_cursor = 0;\n\t\tbreak;\n\n\t}\n\n\tif (mods_cursor > max_mod_idx)\n\t{\n\t\tif (k == K_UPARROW)\n\t\t\tmods_cursor = max_mod_idx;\n\t\telse\n\t\t\tmods_cursor = 0;\n\t}\n\n}\n\n//=============================================================================\n/* GRAPHICS MENU */\n\n# define GRAPHICS_ITEMS 14\n\n#define\tSLIDER_RANGE 10\n\nint\tgraphics_cursor;\n\n#define N_RES 7\nstatic const int res[N_RES][2] = {\n\t{480, 272},\n\t{640, 368},\n\t{720, 408},\n\t{960, 544},\n\t{1280, 720},\n\t{1440, 1080},\n\t{1920, 1080},\n};\nint r_idx = -1;\n\nvoid M_Menu_Graphics_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_graphics;\n\tm_entersound = true;\n}\n\nvoid M_AdjustSliders2 (int dir)\n{\n\tS_LocalSound (\"misc/menu3.wav\");\n\t\n\tswitch (graphics_cursor)\n\t{\n\tcase 0:  // bilinear filtering\n\t\tCvar_ToggleValue(&gl_bilinear);\n\t\tbreak;\n\tcase 1:\t// gamma\n\t\tv_gamma.value -= dir * 0.05;\n\t\tif (v_gamma.value < 0.5)\n\t\t\tv_gamma.value = 0.5;\n\t\tif (v_gamma.value > 1)\n\t\t\tv_gamma.value = 1;\n\t\tCvar_SetValue (\"v_gamma\", v_gamma.value);\n\t\tbreak;\n\tcase 2: // overbright\n\t\tgl_overbright.value += dir;\n\t\tif (gl_overbright.value < 0)\n\t\t\tgl_overbright.value = 0;\n\t\tif (gl_overbright.value > 2)\n\t\t\tgl_overbright.value = 2;\n\t\tCvar_SetValue (\"gl_overbright\", gl_overbright.value);\n\t\tbreak;\n\tcase 3: // hud transparency\n\t\tscr_sbaralpha.value += dir * 0.1;\n\t\tif (scr_sbaralpha.value < 0)\n\t\t\tscr_sbaralpha.value = 0;\n\t\tif (scr_sbaralpha.value > 1)\n\t\t\tscr_sbaralpha.value = 1;\n\t\tCvar_SetValue (\"scr_sbaralpha\", scr_sbaralpha.value);\n\t\tbreak;\n\tcase 4:  // mirrors opacity\n\t\tr_mirroralpha.value += dir * 0.1;\n\t\tif (r_mirroralpha.value < 0)\n\t\t\tr_mirroralpha.value = 0;\n\t\tif (r_mirroralpha.value > 1)\n\t\t\tr_mirroralpha.value = 1;\n\t\tCvar_SetValue (\"r_mirroralpha\", r_mirroralpha.value);\n\t\tbreak;\n\tcase 5: // water opacity\n\t\tr_wateralpha.value += dir * 0.1;\n\t\tif (r_wateralpha.value < 0)\n\t\t\tr_wateralpha.value = 0;\n\t\tif (r_wateralpha.value > 1)\n\t\t\tr_wateralpha.value = 1;\n\t\tCvar_SetValue (\"r_wateralpha\", r_wateralpha.value);\n\t\tbreak;\n\tcase 6:\t// dynamic torchflares\n\t\tCvar_ToggleValue(&gl_torchflares);\n\t\tbreak;\n\tcase 7:\t// dynamic shadows\n\t\tCvar_ToggleValue(&r_shadows);\n\t\tbreak;\n\tcase 8:\t// Fog\n\t\tif (gl_fog.value) Cvar_SetValue (\"r_fullbright\", 0);\n\t\telse Cvar_SetValue (\"r_fullbright\", 1);\n\t\tCvar_ToggleValue (&gl_fog);\n\t\tbreak;\n\tcase 9:  // cel shading\n\t\tgl_outline.value += dir;\n\t\tif (gl_outline.value > 6) gl_outline.value = 6;\n\t\telse if (gl_outline.value < 0) gl_outline.value = 0;\n\t\tCvar_SetValue (\"gl_outline\",gl_outline.value);\n\t\tbreak;\n\tcase 10:  // anaglyph 3d\n\t\tst_separation.value = st_separation.value == 0.5 ? 0.0 : 0.5;\n\t\tCvar_SetValue (\"st_separation\",st_separation.value);\n\t\tbreak;\n\tcase 11:\t// antialiasing\n\t\tantialiasing += dir;\n\t\tif (antialiasing < 0) antialiasing = 8;\n\t\telse if (antialiasing > 8) antialiasing = 0;\n\t\tSetAntiAliasing(antialiasing);\n\t\tbreak;\n\tcase 12:\t// resolution\n\t\tif (r_idx == -1) {\n\t\t\tfor (r_idx = 0; r_idx < N_RES; r_idx++) {\n\t\t\t\tif (cfg_width == res[r_idx][0]) break;\n\t\t\t}\n\t\t}\n\t\tr_idx = (r_idx + dir + N_RES) % N_RES;\n\t\tSetResolution(res[r_idx][0], res[r_idx][1]);\n\t\tbreak;\n\tcase 13:\n\t\tCvar_SetValue (\"vid_vsync\", !vid_vsync.value);\n\t\tbreak;\n\tcase 14:\t// performance test\n\t\tkey_dest = key_benchmark;\n\t\tm_state = m_none;\n\t\tcls.demonum = m_save_demonum;\n\t\tCbuf_AddText(\"benchmark demo1\\n\");\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nvoid M_DrawSlider (int x, int y, float range)\n{\n\tint\ti;\n\n\tif (range < 0)\n\t\trange = 0;\n\tif (range > 1)\n\t\trange = 1;\n\tM_DrawCharacter (x-8, y, 128);\n\tfor (i=0 ; i<SLIDER_RANGE ; i++)\n\t\tM_DrawCharacter (x + i*8, y, 129);\n\tM_DrawCharacter (x+i*8, y, 130);\n\tM_DrawCharacter (x + (SLIDER_RANGE-1)*8 * range, y, 131);\n}\n\nvoid M_DrawCheckbox (int x, int y, int on)\n{\n\tM_Print (x, y, on ? \"on\" : \"off\");\n}\n\nvoid M_Graphics_Draw (void)\n{\n\tfloat\t\tr;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_option.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\t\n\tM_Print (16, 32, \"    Bilinear Filtering\");\n\tM_DrawCheckbox (220, 32, gl_bilinear.value);\n\t\n\tM_Print (16, 40, \"            Brightness\");\n\tr = (1.0 - v_gamma.value) / 0.5;\n\tM_DrawSlider (220, 40, r);\n\t\n\tM_Print (16, 48, \"      Light Overbright\");\n\tr = gl_overbright.value / 2;\n\tM_DrawSlider (220, 48, r);\n\t\n\tM_Print (16, 56, \"      HUD Transparency\");\n\tM_DrawSlider (220, 56, scr_sbaralpha.value);\n\t\n\tM_Print (16, 64, \"       Mirrors Opacity\");\n\tr = r_mirroralpha.value;\n\tM_DrawSlider (220, 64, r);\n\t\n\tM_Print (16, 72, \"         Water Opacity\");\n\tr = r_wateralpha.value;\n\tM_DrawSlider (220, 72, r);\n\t\n\tM_Print (16, 80, \"        Dynamic Lights\");\n\tM_DrawCheckbox (220, 80, gl_torchflares.value);\n\n\tM_Print (16, 88, \"       Dynamic Shadows\");\n\tM_DrawCheckbox (220, 88, r_shadows.value);\n\t\n\tM_Print (16, 96, \"         Fog Rendering\");\n\tM_DrawCheckbox (220, 96, gl_fog.value);\n\t\n\tM_Print (16, 104, \"           Cel Shading\");\n\tr = gl_outline.value / 6;\n\tM_DrawSlider (220, 104, r);\n\t\n\tM_Print (16, 112,\"           Anaglyph 3D\");\n\tM_DrawCheckbox (220, 112, st_separation.value != 0);\n\n\tM_Print (16, 120,\"         Anti-Aliasing\");\n\tswitch (antialiasing) {\n\tcase 1:\n\t\tM_Print (220, 120, \"MSAA 2x\");\n\t\tbreak;\n\tcase 2:\n\t\tM_Print (220, 120, \"MSAA 4x\");\n\t\tbreak;\n\tcase 3:\n\t\tM_Print (220, 120, \"SSAA 2x\");\n\t\tbreak;\n\tcase 4:\n\t\tM_Print (220, 120, \"SSAA 4x\");\n\t\tbreak;\n\tcase 5:\n\t\tM_Print (220, 120, \"MSAA 2x + SSAA 2x\");\n\t\tbreak;\n\tcase 6:\n\t\tM_Print (220, 120, \"MSAA 2x + SSAA 4x\");\n\t\tbreak;\n\tcase 7:\n\t\tM_Print (220, 120, \"MSAA 4x + SSAA 2x\");\n\t\tbreak;\n\tcase 8:\n\t\tM_Print (220, 120, \"MSAA 4x + SSAA 4x\");\n\t\tbreak;\n\tdefault:\n\t\tM_Print (220, 120, \"Disabled\");\n\t\tbreak;\n\t}\n\t\n\tchar res_str[64];\n\tsprintf(res_str, \"%dx%d\", cfg_width, cfg_height);\n\tM_Print (16, 128,\"            Resolution\");\n\tM_Print (220, 128, res_str);\n\n\tM_Print (16, 136,\"                V-Sync\");\n\tM_DrawCheckbox (220, 136, vid_vsync.value);\n\t\n\tM_Print (16, 152,\"      Test Performance\");\n\t\n\t// Warn users for reboot required\n\tif (graphics_cursor == 11 || graphics_cursor == 12) {\n\t\tM_PrintCentered (210, \"Editing this option will require\");\n\t\tM_PrintCentered (218, \"  an app reboot to take effect  \");\n\t}\n\t\n// cursor\n\tif (graphics_cursor == GRAPHICS_ITEMS)\n\t\tM_DrawCharacter (200, 152, 12+((int)(realtime*4)&1));\n\telse\n\t\tM_DrawCharacter (200, 32 + graphics_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\nvoid M_Graphics_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Options_f ();\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_entersound = true;\n\t\tM_AdjustSliders2 (1);\n\t\treturn;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tgraphics_cursor--;\n\t\tif (graphics_cursor < 0)\n\t\t\tgraphics_cursor = GRAPHICS_ITEMS;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tgraphics_cursor++;\n\t\tif (graphics_cursor > GRAPHICS_ITEMS)\n\t\t\tgraphics_cursor = 0;\n\t\tbreak;\n\n\tcase K_LEFTARROW:\n\t\tM_AdjustSliders2 (-1);\n\t\tbreak;\n\n\tcase K_RIGHTARROW:\n\t\tM_AdjustSliders2 (1);\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* OPTIONS MENU */\n\n#define\tOPTIONS_ITEMS 20\n\nint\toptions_cursor;\n\nvoid M_Menu_Options_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_options;\n\tm_entersound = true;\n}\n\nchar *w_pos[] = {\"Center\", \"Right\", \"Left\", \"Hidden\"};\nint w_pos_idx = -1;\n\nvoid M_AdjustSliders (int dir)\n{\n\tS_LocalSound (\"misc/menu3.wav\");\n\n\tswitch (options_cursor)\n\t{\n\tcase 5:\t// screen size\n\t\tviewsize.value += dir * 10;\n\t\tif (viewsize.value < 30)\n\t\t\tviewsize.value = 30;\n\t\tif (viewsize.value > 120)\n\t\t\tviewsize.value = 120;\n\t\tCvar_SetValue (\"viewsize\", viewsize.value);\n\t\tbreak;\n\tcase 6:\t// camera sensitivity\n\t\tsensitivity.value += dir * 0.5;\n\t\tif (sensitivity.value < 1)\n\t\t\tsensitivity.value = 1;\n\t\tif (sensitivity.value > 11)\n\t\t\tsensitivity.value = 11;\n\t\tCvar_SetValue (\"sensitivity\", sensitivity.value);\n\t\tbreak;\n\tcase 7:\t// invert camera\n\t\tCvar_ToggleValue (&invert_camera);\n\t\tbreak;\n\tcase 8:\t// music volume\n\t\tbgmvolume.value += dir * 0.1;\n\t\tif (bgmvolume.value < 0)\n\t\t\tbgmvolume.value = 0;\n\t\tif (bgmvolume.value > 1)\n\t\t\tbgmvolume.value = 1;\n\t\tCvar_SetValue (\"bgmvolume\", bgmvolume.value);\n\t\tbreak;\n\tcase 9:\t// sfx volume\n\t\tvolume.value += dir * 0.1;\n\t\tif (volume.value < 0)\n\t\t\tvolume.value = 0;\n\t\tif (volume.value > 1)\n\t\t\tvolume.value = 1;\n\t\tCvar_SetValue (\"volume\", volume.value);\n\t\tbreak;\n\tcase 10:\t// retrotouch\n\t\tCvar_SetValue (\"retrotouch\", !retrotouch.value);\n\t\tbreak;\n\tcase 11:\t// motion camera\n\t\tCvar_SetValue (\"motioncam\", !motioncam.value);\n\t\tbreak;\n\tcase 12:\t// motion camera sensitivity horizontal\n\t\tmotion_horizontal_sensitivity.value += dir * 0.5;\n\t\tif (motion_horizontal_sensitivity.value < 0)\n\t\t\tmotion_horizontal_sensitivity.value = 0;\n\t\tif (motion_horizontal_sensitivity.value > 10)\n\t\t\tmotion_horizontal_sensitivity.value = 10;\n\t\tCvar_SetValue (\"motion_horizontal_sensitivity\", motion_horizontal_sensitivity.value);\n\t\tbreak;\n\tcase 13:\t// motion camera sensitivity vertical\n\t\tmotion_vertical_sensitivity.value += dir * 0.5;\n\t\tif (motion_vertical_sensitivity.value < 0)\n\t\t\tmotion_vertical_sensitivity.value = 0;\n\t\tif (motion_vertical_sensitivity.value > 10)\n\t\t\tmotion_vertical_sensitivity.value = 10;\n\t\tCvar_SetValue (\"motion_vertical_sensitivity\", motion_vertical_sensitivity.value);\n\t\tbreak;\n\tcase 14:\t// rumble\n\t\tCvar_SetValue (\"pstv_rumble\", !pstv_rumble.value);\n\t\tbreak;\n\tcase 15:\t// show fps\n\t\tCvar_SetValue (\"show_fps\", !show_fps.value);\n\t\tbreak;\n\tcase 16:\t// crosshair\n\t\tcrosshair.value += dir;\n\t\tif (crosshair.value > 2) crosshair.value = 0;\n\t\telse if (crosshair.value < 0) crosshair.value = 2;\n\t\tCvar_SetValue (\"crosshair\", crosshair.value);\n\t\tbreak;\n\tcase 17:\t// show weapon\n\t\tw_pos_idx += dir;\n\t\tif (w_pos_idx > 3) w_pos_idx = 0;\n\t\tif (w_pos_idx < 0) w_pos_idx = 3;\n\t\tswitch (w_pos_idx) {\n\t\t\tcase 1:\n\t\t\t\tCvar_SetValue (\"r_drawviewmodel\", 1);\n\t\t\t\tCvar_SetValue (\"r_viewmodeloffset\", 8);\n\t\t\t\tbreak;\n\t\t\tcase 2:\n\t\t\t\tCvar_SetValue (\"r_drawviewmodel\", 1);\n\t\t\t\tCvar_SetValue (\"r_viewmodeloffset\", -8);\n\t\t\t\tbreak;\n\t\t\tcase 3:\n\t\t\t\tCvar_SetValue (\"r_drawviewmodel\", 0);\n\t\t\t\tbreak;\n\t\t\tdefault:\n\t\t\t\tCvar_SetValue (\"r_drawviewmodel\", 1);\n\t\t\t\tCvar_SetValue (\"r_viewmodeloffset\", 0);\n\t\t\t\tbreak;\n\t\t}\n\t\tbreak;\n\tcase 18:\t// field of view\n\t\tfov.value += dir * 5;\n\t\tif (fov.value > 130) fov.value = 130;\n\t\telse if (fov.value < 75) fov.value = 75;\n\t\tCvar_SetValue (\"fov\",fov.value);\n\t\tbreak;\n\tcase 19:\t// smooth animations\n\t\tCvar_ToggleValue(&r_interpolate_model_animation);\n\t\tCvar_ToggleValue(&r_interpolate_model_transform);\n\t\tbreak;\n\tcase 20:\t// specular mode\n\t\tCvar_SetValue (\"gl_xflip\", !gl_xflip.value);\n\t\tbreak;\n\tdefault:\n\t\tbreak;\n\t}\n}\n\nvoid M_Options_Draw (void)\n{\n\tfloat\t\tr;\n\tqpic_t\t*p;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_option.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tM_Print (16, 32, \"     Controls Settings\");\n\tM_Print (16, 40, \"     Graphics Settings\");\n\tM_Print (16, 48, \"          Open Console\");\n\tM_Print (16, 56, \"        Open Mods Menu\");\n\tM_Print (16, 64, \"     Reset to defaults\");\n\n\tM_Print (16, 72, \"           Screen size\");\n\tr = (viewsize.value - 30) / (120 - 30);\n\tM_DrawSlider (220, 72, r);\n\t\n\tM_Print (16, 80, \"    Camera Sensitivity\");\n\tr = (sensitivity.value - 1)/10;\n\tM_DrawSlider (220, 80, r);\n\t\n\tM_Print (16, 88, \"         Invert Camera\");\n\tM_DrawCheckbox (220, 88, invert_camera.value);\n\n\tM_Print (16, 96,\"          Music Volume\");\n\tr = bgmvolume.value;\n\tM_DrawSlider (220, 96, r);\n\t\n\tM_Print (16, 104,\"          Sound Volume\");\n\tr = volume.value;\n\tM_DrawSlider (220, 104, r);\n\t\n\tM_Print (16, 112,\"        Use Retrotouch\");\n\tM_DrawCheckbox (220, 112, retrotouch.value);\n\n\tM_Print (16, 120,\"         Use Gyroscope\");\n\tM_DrawCheckbox (220, 120, motioncam.value);\n\t\n\tM_Print (16, 128,\"    Gyro X Sensitivity\");\n\tr = motion_horizontal_sensitivity.value/10;\n\tM_DrawSlider (220, 128, r);\n\n\tM_Print (16, 136,\"    Gyro Y Sensitivity\");\n\tr = motion_vertical_sensitivity.value/10;\n\tM_DrawSlider (220, 136, r);\n\n\tM_Print (16, 144,\"         Rumble Effect\");\n\tM_DrawCheckbox (220, 144, pstv_rumble.value);\n\t\n\tM_Print (16, 152,\"        Show Framerate\");\n\tM_DrawCheckbox (220, 152, show_fps.value);\n\t\n\tM_Print (16, 160,\"        Show Crosshair\");\n\tif (crosshair.value == 0)\n\t\tM_Print (220, 160, \"Off\");\n\telse if (crosshair.value == 1)\n\t\tM_Print (220, 160, \"Original\");\n\telse\n\t\tM_Print (220, 160, \"Custom\");\n\t\n\tM_Print (16, 168,\"       Weapon Position\");\n\tif (w_pos_idx == -1) {\n\t\tif (!r_drawviewmodel.value) w_pos_idx = 3;\n\t\telse if (r_viewmodeloffset.value < 0) w_pos_idx = 2;\n\t\telse if (r_viewmodeloffset.value > 0) w_pos_idx = 1;\n\t\telse w_pos_idx = 0;\n\t}\n\tM_Print (220, 168, w_pos[w_pos_idx]);\n\t\n\tM_Print (16, 176,\"         Field of View\");\n\tr = (fov.value - 75) / 55;\n\tM_DrawSlider (220, 176, r);\n\t\n\tM_Print (16, 184,\"     Smooth Animations\");\n\tM_DrawCheckbox (220, 184, r_interpolate_model_animation.value);\n\t\n\tM_Print (16, 192,\"         Specular Mode\");\n\tM_DrawCheckbox (220, 192, gl_xflip.value);\n\n\tM_DrawCharacter (200, 32 + options_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Options_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Main_f ();\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_entersound = true;\n\t\tswitch (options_cursor)\n\t\t{\n\t\tcase 0: // Controls Settings\n\t\t\tM_Menu_Keys_f ();\n\t\t\tbreak;\n\t\tcase 1: // Graphics Settings\n\t\t\tM_Menu_Graphics_f ();\n\t\t\tbreak;\n\t\tcase 2: // Open Console\n\t\t\tm_state = m_none;\n\t\t\tCon_ToggleConsole_f ();\n\t\t\tbreak;\n\t\tcase 3: // Open Mods Menu\n\t\t\tM_Menu_Mods_f ();\n\t\t\tbreak;\n\t\tcase 4: // Reset to defaults\n\t\t\tCbuf_AddText (\"exec default.cfg\\n\");\n\t\t\tIN_ResetInputs();\n\t\t\tviewsize.value = 120;\n\t\t\tv_gamma.value = 1;\n\t\t\tsensitivity.value = 3;\n\t\t\tinvert_camera.value = 0;\n\t\t\tbgmvolume.value = 1.0;\n\t\t\tvolume.value = 0.7f;\n\t\t\tretrotouch.value = 0;\n\t\t\tpstv_rumble.value = 1.0f;\n\t\t\tshow_fps.value = 0;\n\t\t\tr_drawviewmodel.value = 1;\n\t\t\tcrosshair.value = 1;\n\t\t\tfov.value = 90;\n\t\t\tgl_fog.value = 0;\n\t\t\tgl_torchflares.value = 1;\n\t\t\tr_shadows.value = 1;\n\t\t\tr_interpolate_model_animation.value = 0;\n\t\t\tr_interpolate_model_transform.value = 0;\n\t\t\tr_mirroralpha.value = 0.8f;\n\t\t\tr_wateralpha.value = 1.0f;\n\t\t\tgl_xflip.value = 0;\n\t\t\tmotioncam.value = 0;\n\t\t\tvid_vsync.value = 1;\n\t\t\tmotion_horizontal_sensitivity.value = 3;\n\t\t\tmotion_vertical_sensitivity.value = 3;\n\t\t\tscr_sbaralpha.value = 0.5f;\n\t\t\tgl_outline.value = 0;\n\t\t\tst_separation.value = 0;\n\t\t\tw_pos_idx = 0;\n\t\t\tr_viewmodeloffset.value = 0;\n\t\t\tgl_overbright.value = 0;\n\t\t\tCvar_SetValue (\"viewsize\", viewsize.value);\n\t\t\tCvar_SetValue (\"v_gamma\", v_gamma.value);\n\t\t\tCvar_SetValue (\"sensitivity\", sensitivity.value);\n\t\t\tCvar_SetValue (\"invert_camera\", invert_camera.value);\n\t\t\tCvar_SetValue (\"bgmvolume\", bgmvolume.value);\n\t\t\tCvar_SetValue (\"volume\", volume.value);\n\t\t\tCvar_SetValue (\"retrotouch\", retrotouch.value);\n\t\t\tCvar_SetValue (\"pstv_rumble\", pstv_rumble.value);\n\t\t\tCvar_SetValue (\"show_fps\", show_fps.value);\n\t\t\tCvar_SetValue (\"r_drawviewmodel\", r_drawviewmodel.value);\n\t\t\tCvar_SetValue (\"crosshair\", crosshair.value);\n\t\t\tCvar_SetValue (\"fov\", fov.value);\n\t\t\tCvar_SetValue (\"gl_fog\", gl_fog.value);\n\t\t\tCvar_SetValue (\"gl_torchflares\", gl_torchflares.value);\n\t\t\tCvar_SetValue (\"r_shadows\", r_shadows.value);\n\t\t\tCvar_SetValue (\"r_interpolate_model_animation\", r_interpolate_model_animation.value);\n\t\t\tCvar_SetValue (\"r_interpolate_model_transform\", r_interpolate_model_transform.value);\n\t\t\tCvar_SetValue (\"r_mirroralpha\", r_mirroralpha.value);\n\t\t\tCvar_SetValue (\"r_wateralpha\", r_wateralpha.value);\n\t\t\tCvar_SetValue (\"gl_xflip\", gl_xflip.value);\n\t\t\tCvar_SetValue (\"motioncam\", motioncam.value);\n\t\t\tCvar_SetValue (\"motion_horizontal_sensitivity\", motion_horizontal_sensitivity.value);\n\t\t\tCvar_SetValue (\"motion_vertical_sensitivity\", motion_vertical_sensitivity.value);\n\t\t\tCvar_SetValue (\"scr_sbaralpha\", scr_sbaralpha.value);\n\t\t\tCvar_SetValue (\"vid_vsync\", vid_vsync.value);\n\t\t\tCvar_SetValue (\"gl_outline\", gl_outline.value);\n\t\t\tCvar_SetValue (\"r_viewmodeloffset\", r_viewmodeloffset.value);\n\t\t\tCvar_SetValue (\"st_separation\",st_separation.value);\n\t\t\tCvar_SetValue (\"gl_overbright\",gl_overbright.value);\n\t\t\tSetResolution(960, 544);\n\t\t\tantialiasing = 2;\n\t\t\tr_idx = -1;\n\t\t\tSetAntiAliasing(antialiasing);\n            Cbuf_AddText (\"gl_texturemode GL_LINEAR\\n\");\n\t\t\tbreak;\n\t\tdefault: // All other settings\n\t\t\tM_AdjustSliders (1);\n\t\t\tbreak;\n\t\t}\n\t\treturn;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\toptions_cursor--;\n\t\tif (options_cursor < 0)\n\t\t\toptions_cursor = OPTIONS_ITEMS;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\toptions_cursor++;\n\t\tif (options_cursor > OPTIONS_ITEMS)\n\t\t\toptions_cursor = 0;\n\t\tbreak;\n\n\tcase K_LEFTARROW:\n\t\tM_AdjustSliders (-1);\n\t\tbreak;\n\n\tcase K_RIGHTARROW:\n\t\tM_AdjustSliders (1);\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* KEYS MENU */\n\n#define BIND_BINDABLE 0\n#define BIND_SEPARATOR 1\n\nchar *bindnames[][2] =\n{\n{\"+attack\", \t\t\"attack\"},\n{\"impulse 10\", \t\t\"next weapon\"},\n{\"impulse 12\",\t \t\"previous weapon\" },\n{\"+jump\", \t\t\t\"jump / swim up\"},\n{\"+forward\", \t\t\"move forward\"},\n{\"+back\", \t\t\t\"move back\"},\n{\"+moveleft\", \t\t\"move left\" },\n{\"+moveright\", \t\t\"move right\" },\n{\"+speed\", \t\t\t\"run\" },\n{\"+moveup\",\t\t\t\"swim up\" },\n{\"+movedown\",\t\t\"swim down\" },\n{\"centerview\", \t\t\"center view\"},\n{\"+left\", \t\t\t\"turn left\"},\n{\"+right\", \t\t\t\"turn right\"},\n{\"+strafe\", \t\t\"sidestep\"},\n{\"+lookup\", \t\t\"look up\"},\n{\"+lookdown\", \t\t\"look down\"}\n};\n\n#define\tNUMCOMMANDS\t(sizeof(bindnames)/sizeof(bindnames[0]))\n\nint\t\tkeys_cursor;\nint\t\tbind_grab;\n\nvoid M_Menu_Keys_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_keys;\n\tm_entersound = true;\n}\n\n\nvoid M_FindKeysForCommand (char *command, int *twokeys)\n{\n\tint\t\tcount;\n\tint\t\tj;\n\tint\t\tl;\n\tchar\t*b;\n\n\ttwokeys[0] = twokeys[1] = -1;\n\tl = strlen(command);\n\tcount = 0;\n\n\tfor (j=0 ; j<256 ; j++)\n\t{\n\t\tb = keybindings[j];\n\t\tif (!b)\n\t\t\tcontinue;\n\t\tif (!strncmp (b, command, l) )\n\t\t{\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\nvoid M_UnbindCommand (char *command)\n{\n\tint\t\tj;\n\tint\t\tl;\n\tchar\t*b;\n\n\tl = strlen(command);\n\n\tfor (j=0 ; j<256 ; j++)\n\t{\n\t\tb = keybindings[j];\n\t\tif (!b)\n\t\t\tcontinue;\n\t\tif (!strncmp (b, command, l) )\n\t\t\tKey_SetBinding (j, \"\");\n\t}\n}\n\n\nvoid M_Keys_Draw (void)\n{\n\tint\t\ti, l;\n\tint\t\tkeys[2];\n\tchar\t*name;\n\tint\t\tx, y;\n\tqpic_t\t*p;\n\n\tp = Draw_CachePic (\"gfx/ttl_cstm.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tif (bind_grab)\n\t\tM_Print (12, 32, \"Press a key or button for this action\");\n\telse\n\t\tM_Print (18, 32, \"Cross to change, Select to clear\");\n\n// search for known bindings\n\tfor (i=0 ; i<NUMCOMMANDS ; i++)\n\t{\n\t\ty = 48 + 8*i;\n\n\t\tM_Print (16, y, bindnames[i][1]);\n\n\t\tl = strlen (bindnames[i][0]);\n\n\t\tM_FindKeysForCommand (bindnames[i][0], keys);\n\n\t\tif (keys[0] == -1)\n\t\t{\n\t\t\tM_Print (140, y, \"???\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tname = Key_KeynumToString (keys[0]);\n\t\t\tM_Print (140, y, name);\n\t\t\tx = strlen(name) * 8;\n\t\t\tif (keys[1] != -1)\n\t\t\t{\n\t\t\t\tM_Print (140 + x + 8, y, \"or\");\n\t\t\t\tM_Print (140 + x + 32, y, Key_KeynumToString (keys[1]));\n\t\t\t}\n\t\t}\n\t}\n\n\tif (bind_grab)\n\t\tM_DrawCharacter (130, 48 + keys_cursor*8, '=');\n\telse\n\t\tM_DrawCharacter (130, 48 + keys_cursor*8, 12+((int)(realtime*4)&1));\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_Keys_Key (int k)\n{\n\tchar\tcmd[80];\n\tint\t\tkeys[2];\n\n\tif (bind_grab)\n\t{\t// defining a key\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tif (k == K_START) // Start cancels\n\t\t{\n\t\t\tbind_grab = false;\n\t\t}\n\t\telse if (k != '`')\n\t\t{\n\t\t\tsprintf (cmd, \"bind \\\"%s\\\" \\\"%s\\\"\\n\", Key_KeynumToString (k), bindnames[keys_cursor][0]);\n\t\t\tCbuf_InsertText (cmd);\n\t\t}\n\n\t\tbind_grab = false;\n\t\treturn;\n\t}\n\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Options_f ();\n\t\tbreak;\n\n\tcase K_LEFTARROW:\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tkeys_cursor--;\n\t\tif (keys_cursor < 0)\n\t\t\tkeys_cursor = NUMCOMMANDS-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\tcase K_RIGHTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tkeys_cursor++;\n\t\tif (keys_cursor >= NUMCOMMANDS)\n\t\t\tkeys_cursor = 0;\n\t\tbreak;\n\n\tcase K_CIRCLE:\t\t// go into bind mode\n\tcase K_CROSS:\t\t// go into bind mode\n\t\tM_FindKeysForCommand (bindnames[keys_cursor][0], keys);\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tif (keys[1] != -1)\n\t\t\tM_UnbindCommand (bindnames[keys_cursor][0]);\n\t\tbind_grab = true;\n\t\tbreak;\n\n\tcase K_SELECT:\t\t\t\t// delete bindings\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tM_UnbindCommand (bindnames[keys_cursor][0]);\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* VIDEO MENU */\n\nvoid M_Menu_Video_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_video;\n\tm_entersound = true;\n}\n\n\nvoid M_Video_Draw (void)\n{\n\t(*vid_menudrawfn) ();\n}\n\n\nvoid M_Video_Key (int key)\n{\n\t(*vid_menukeyfn) (key);\n}\n\n//=============================================================================\n/* HELP MENU */\n\nint\t\thelp_page;\n#define\tNUM_HELP_PAGES\t6\n\n\nvoid M_Menu_Help_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_help;\n\tm_entersound = true;\n\thelp_page = 0;\n}\n\n\n\nvoid M_Help_Draw (void)\n{\n\tM_DrawPic (0, 0, Draw_CachePic ( va(\"gfx/help%i.lmp\", help_page)) );\n}\n\n\nvoid M_Help_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Main_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\tcase K_RIGHTARROW:\n\t\tm_entersound = true;\n\t\tif (++help_page >= NUM_HELP_PAGES)\n\t\t\thelp_page = 0;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\tcase K_LEFTARROW:\n\t\tm_entersound = true;\n\t\tif (--help_page < 0)\n\t\t\thelp_page = NUM_HELP_PAGES-1;\n\t\tbreak;\n\t}\n\n}\n\n//=============================================================================\n/* QUIT MENU */\n\nint\t\tmsgNumber;\nint\t\tm_quit_prevstate;\nbool\twasInMenus;\n\n#ifndef\t_WIN32\nchar *quitMessage [] =\n{\n/* .........1.........2.... */\n  \"  Are you gonna quit    \",\n  \"  this game just like   \",\n  \"   everything else?     \",\n  \"                        \",\n\n  \" Milord, methinks that  \",\n  \"   thou art a lowly     \",\n  \" quitter. Is this true? \",\n  \"                        \",\n\n  \" Do I need to bust your \",\n  \"  face open for trying  \",\n  \"        to quit?        \",\n  \"                        \",\n\n  \" Man, I oughta smack you\",\n  \"   for trying to quit!  \",\n  \"     Press X to get     \",\n  \"      smacked out.      \",\n\n  \" What, you want to stop \",\n  \"   playing VitaQuake?   \",\n  \"     Press X or O to    \",\n  \"   return to LiveArea.  \",\n\n  \" Press X to quit like a \",\n  \"   big loser in life.   \",\n  \"  Return back to stay   \",\n  \"  proud and successful! \",\n\n  \"   If you press X to    \",\n  \"  quit, I will summon   \",\n  \"  Satan all over your   \",\n  \"      memory card!      \",\n\n  \"  Um, Asmodeus dislikes \",\n  \" his children trying to \",\n  \" quit. Press X to return\",\n  \"   to your Tinkertoys.  \",\n\n  \"  If you quit now, I'll \",\n  \"  throw a blanket-party \",\n  \"   for you next time!   \",\n  \"                        \"\n};\n#endif\n\nvoid M_Menu_Quit_f (void)\n{\n\tif (m_state == m_quit)\n\t\treturn;\n\twasInMenus = (key_dest == key_menu);\n\tkey_dest = key_menu;\n\tm_quit_prevstate = m_state;\n\tm_state = m_quit;\n\tm_entersound = true;\n\tmsgNumber = rand()&7;\n}\n\n\nvoid M_Quit_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_TRIANGLE:\n\tcase K_SELECT:\n\tcase 'n':\n\tcase 'N':\n\t\tif (wasInMenus)\n\t\t{\n\t\t\tm_state = m_quit_prevstate;\n\t\t\tm_entersound = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tkey_dest = key_game;\n\t\t\tm_state = m_none;\n\t\t}\n\t\tbreak;\n\n\tcase K_CROSS:\n\tcase K_CIRCLE:\n\t\tkey_dest = key_console;\n\t\tHost_Quit_f ();\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n}\n\n\nvoid M_Quit_Draw (void)\n{\n\tif (wasInMenus)\n\t{\n\t\tm_state = m_quit_prevstate;\n\t\tm_recursiveDraw = true;\n\t\tM_Draw ();\n\t\tm_state = m_quit;\n\t}\n\n#ifdef _WIN32\t// ToDo: Move this to a Credits subsection\n\tM_DrawTextBox (0, 0, 38, 23);\n\tM_PrintWhite (16, 12,  \"  Quake version 1.09 by id Software\\n\\n\");\n\tM_PrintWhite (16, 28,  \"Programming        Art \\n\");\n\tM_Print (16, 36,  \" John Carmack       Adrian Carmack\\n\");\n\tM_Print (16, 44,  \" Michael Abrash     Kevin Cloud\\n\");\n\tM_Print (16, 52,  \" John Cash          Paul Steed\\n\");\n\tM_Print (16, 60,  \" Dave 'Zoid' Kirsch\\n\");\n\tM_PrintWhite (16, 68,  \"Design             Biz\\n\");\n\tM_Print (16, 76,  \" John Romero        Jay Wilbur\\n\");\n\tM_Print (16, 84,  \" Sandy Petersen     Mike Wilson\\n\");\n\tM_Print (16, 92,  \" American McGee     Donna Jackson\\n\");\n\tM_Print (16, 100,  \" Tim Willits        Todd Hollenshead\\n\");\n\tM_PrintWhite (16, 108, \"Support            Projects\\n\");\n\tM_Print (16, 116, \" Barrett Alexander  Shawn Green\\n\");\n\tM_PrintWhite (16, 124, \"Sound Effects\\n\");\n\tM_Print (16, 132, \" Trent Reznor and Nine Inch Nails\\n\\n\");\n\tM_PrintWhite (16, 140, \"Quake is a trademark of Id Software,\\n\");\n\tM_PrintWhite (16, 148, \"inc., (c)1996 Id Software, inc. All\\n\");\n\tM_PrintWhite (16, 156, \"rights reserved. NIN logo is a\\n\");\n\tM_PrintWhite (16, 164, \"registered trademark licensed to\\n\");\n\tM_PrintWhite (16, 172, \"Nothing Interactive, Inc. All rights\\n\");\n\tM_PrintWhite (16, 180, \"reserved. Press y to exit\\n\");\n#else\n\tM_DrawTextBox (56, 76, 24, 4);\n\tM_Print (64, 84,  quitMessage[msgNumber*4+0]);\n\tM_Print (64, 92,  quitMessage[msgNumber*4+1]);\n\tM_Print (64, 100, quitMessage[msgNumber*4+2]);\n\tM_Print (64, 108, quitMessage[msgNumber*4+3]);\n#endif\n\n\tDraw_Batched();\n}\n\n\n//=============================================================================\n/* LAN CONFIG MENU */\n\nint\t\tlanConfig_cursor = 1;\nint\t\tlanConfig_cursor_table [] = {72, 92, 112, 144, 158};\n#define NUM_LANCONFIG_CMDS\t4\n\nint \tlanConfig_port;\nchar\tlanConfig_portname[6];\nchar\tlanConfig_joinname[22];\n\nvoid M_Menu_LanConfig_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_lanconfig;\n\tm_entersound = true;\n\tif (lanConfig_cursor == -1)\n\t{\n\t\tif (JoiningGame && TCPIPConfig)\n\t\t\tlanConfig_cursor = NUM_LANCONFIG_CMDS;\n\t}\n\tif (StartingGame && lanConfig_cursor >= 3)\n\t\tlanConfig_cursor = 1;\n\tlanConfig_port = DEFAULTnet_hostport;\n\tsprintf(lanConfig_portname, \"%u\", lanConfig_port);\n\n\tm_return_onerror = false;\n\tm_return_reason[0] = 0;\n}\n\nchar protocol[64];\nuint8_t proto_idx = 0;\n\nvoid M_LanConfig_Draw (void)\n{\n\tqpic_t\t*p;\n\tint\t\tbasex;\n\tchar\t*startJoin;\n\t\n\t\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tbasex = (320-p->width)/2;\n\tM_DrawPic (basex, 4, p);\n\n\tif (StartingGame)\n\t\tstartJoin = \"New Game\";\n\telse\n\t\tstartJoin = \"Join Game\";\n\n\tif (proto_idx == 0) sprintf(protocol, \"TCP/IP\");\n\telse sprintf(protocol, \"AdHoc\");\n\t\n\tM_DrawTextBox (basex+8*8, lanConfig_cursor_table[0]-8, 6, 1);\n\tif (JoiningGame) {\n\t\tM_DrawTextBox (basex+8, lanConfig_cursor_table[3]-8, 22, 1);\n\t\tM_Print (basex, lanConfig_cursor_table[2], \"Search for local games...\");\n\t\tM_Print (basex, 128, \"Join game at:\");\n\t\tM_Print (basex+16, lanConfig_cursor_table[3], lanConfig_joinname);\n\t\tM_Print (basex, 158, \"Join an online server\");\n\t} else {\n\t\tM_DrawTextBox (basex, lanConfig_cursor_table[2]-8, 2, 1);\n\t\tM_Print (basex+8, lanConfig_cursor_table[2], \"OK\");\n\t}\n\n\tM_Print (basex, 32, va (\"%s - %s\", startJoin, protocol));\n\tbasex += 8;\n\n\tM_Print (basex, 52, \"Address:\");\n\tM_Print (basex+9*8, 52, my_tcpip_address);\n\n\tM_Print (basex, lanConfig_cursor_table[0], \"Port\");\n\tM_Print (basex+9*8, lanConfig_cursor_table[0], lanConfig_portname);\n\tM_Print (basex, lanConfig_cursor_table[1], \"Protocol\");\n\tM_Print (basex+9*8, lanConfig_cursor_table[1], protocol);\n\n\tM_DrawCharacter (basex-8, lanConfig_cursor_table [lanConfig_cursor], 12+((int)(realtime*4)&1));\n\n\tif (lanConfig_cursor == 0)\n\t\tM_DrawCharacter (basex+9*8 + 8*strlen(lanConfig_portname), lanConfig_cursor_table [0], 10+((int)(realtime*4)&1));\n\n\tif (lanConfig_cursor == 3)\n\t\tM_DrawCharacter (basex+16 + 8*strlen(lanConfig_joinname), lanConfig_cursor_table [3], 10+((int)(realtime*4)&1));\n\n\tif (*m_return_reason)\n\t\tM_PrintWhite (basex, 168, m_return_reason);\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_LanConfig_Key (int key)\n{\n\tint\t\tl;\n\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_MultiPlayer_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tlanConfig_cursor--;\n\t\tif (lanConfig_cursor < 0)\n\t\t\tif (JoiningGame)\n\t\t\t\tlanConfig_cursor = NUM_LANCONFIG_CMDS;\n\t\t\telse\n\t\t\t\tlanConfig_cursor = NUM_LANCONFIG_CMDS-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tlanConfig_cursor++;\n\t\tif (lanConfig_cursor > NUM_LANCONFIG_CMDS)\n\t\t\tlanConfig_cursor = 0;\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tif (lanConfig_cursor == 0)\n\t\t\tbreak;\n\n\t\tm_entersound = true;\n\n\t\tM_ConfigureNetSubsystem ();\n\t\t\n\t\tif (lanConfig_cursor == 1)\n\t\t{\n\t\t\tDatagram_Shutdown();\n\t\t\tproto_idx = (proto_idx + 1) % 2;\n\t\t\tif (proto_idx == 1) { // Setup AdHoc\n\t\t\t\t// Start sceNetAdhoc and sceNetAdhocctl\n\t\t\t\tsceNetAdhocInit();\n\t\t\t\tSceNetAdhocctlAdhocId adhocId;\n\t\t\t\tmemset(&adhocId, 0, sizeof(SceNetAdhocctlAdhocId));\n\t\t\t\tadhocId.type = SCE_NET_ADHOCCTL_ADHOCTYPE_RESERVED;\n\t\t\t\tmemcpy(&adhocId.data[0], \"QUAK00001\", SCE_NET_ADHOCCTL_ADHOCID_LEN);\n\t\t\t\tsceNetAdhocctlInit(&adhocId);\n\t\n\t\t\t\tSceNetCheckDialogParam param;\n\t\t\t\tsceNetCheckDialogParamInit(&param);\n\t\t\t\tSceNetAdhocctlGroupName groupName;\n\t\t\t\tmemset(groupName.data, 0, SCE_NET_ADHOCCTL_GROUPNAME_LEN);\n\t\t\t\tparam.groupName = &groupName;\n\t\t\t\tmemcpy(&param.npCommunicationId.data, \"QUAK00001\", 9);\n\t\t\t\tparam.npCommunicationId.term = '\\0';\n\t\t\t\tparam.npCommunicationId.num = 0;\n\t\t\t\tparam.mode = SCE_NETCHECK_DIALOG_MODE_PSP_ADHOC_CONN;\n\t\t\t\tparam.timeoutUs = 0;\n\t\n\t\t\t\tint res = sceNetCheckDialogInit(&param);\n\t\t\t\tif (res >= 0) {\n\t\t\t\t\tnetcheck_dialog_running = 1;\n\t\t\t\t}\n\t\t\t} else Datagram_Init();\n\t\t}\n\n\t\tif (lanConfig_cursor == 2)\n\t\t{\n\t\t\tif (StartingGame)\n\t\t\t{\n\t\t\t\tM_Menu_GameOptions_f ();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tM_Menu_Search_f();\n\t\t\tbreak;\n\t\t}\n\n\t\tif (lanConfig_cursor == 3)\n\t\t{\n\t\t\tm_return_state = m_state;\n\t\t\tm_return_onerror = true;\n\t\t\tkey_dest = key_game;\n\t\t\tm_state = m_none;\n\t\t\tCbuf_AddText ( va (\"connect \\\"%s\\\"\\n\", lanConfig_joinname) );\n\t\t\tbreak;\n\t\t}\n\n\t\tif (lanConfig_cursor == 4)\n\t\t{\n\t\t\tM_Menu_OnlineServerList_f ();\n\t\t\tbreak;\n\t\t}\n\n\t\tbreak;\n\n\tcase K_BACKSPACE:\n\t\tif (lanConfig_cursor == 0)\n\t\t{\n\t\t\tif (strlen(lanConfig_portname))\n\t\t\t\tlanConfig_portname[strlen(lanConfig_portname)-1] = 0;\n\t\t}\n\n\t\tif (lanConfig_cursor == 3)\n\t\t{\n\t\t\tif (strlen(lanConfig_joinname))\n\t\t\t\tlanConfig_joinname[strlen(lanConfig_joinname)-1] = 0;\n\t\t}\n\t\tbreak;\n\n\tdefault:\n\t\tif (key < 32 || key > 127)\n\t\t\tbreak;\n\n\t\tif (lanConfig_cursor == 3)\n\t\t{\n\t\t\tl = strlen(lanConfig_joinname);\n\t\t\tif (l < 21)\n\t\t\t{\n\t\t\t\tlanConfig_joinname[l+1] = 0;\n\t\t\t\tlanConfig_joinname[l] = key;\n\t\t\t}\n\t\t}\n\n\t\tif (key < '0' || key > '9')\n\t\t\tbreak;\n\t\tif (lanConfig_cursor == 0)\n\t\t{\n\t\t\tl = strlen(lanConfig_portname);\n\t\t\tif (l < 5)\n\t\t\t{\n\t\t\t\tlanConfig_portname[l+1] = 0;\n\t\t\t\tlanConfig_portname[l] = key;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (StartingGame && lanConfig_cursor == 3)\n\t\tif (key == K_UPARROW)\n\t\t\tlanConfig_cursor = 2;\n\t\telse\n\t\t\tlanConfig_cursor = 0;\n\n\tl =  atoi(lanConfig_portname);\n\tif (l > 65535)\n\t\tl = lanConfig_port;\n\telse\n\t\tlanConfig_port = l;\n\tsprintf(lanConfig_portname, \"%u\", lanConfig_port);\n}\n\n//=============================================================================\n/* ONLINE SERVERLIST MENU */\n\nint\t\tonlineServerList_cursor = 0;\n\nvoid M_Menu_OnlineServerList_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_onlineserverlist;\n\tm_entersound = true;\n\tm_return_onerror = false;\n\tm_return_reason[0] = 0;\n}\n\n#define NUM_SERVERS 5\n\nvoid M_OnlineServerList_Draw (void)\n{\n\tqpic_t\t*p;\n\tint\t\tbasex;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tbasex = (320-p->width)/2;\n\tM_DrawPic (basex, 4, p);\n\n\tM_Print (basex, 32, \"EU Official Server (Shareware Only)\");\n\tM_Print (basex, 40, \"EU Official Server (Deatmatch Maps)\");\n\tM_Print (basex, 48, \"NCTech Spaceball1 Server\");\n\tM_Print (basex, 56, \"Shmack Practice Mode Server\");\n\tM_Print (basex, 64, \"Clan HDZ DM Server\");\n\n\tM_DrawCharacter (basex-8, 32+onlineServerList_cursor*8, 12+((int)(realtime*4)&1));\n\n\tif (*m_return_reason)\n\t\tM_PrintWhite (basex, 148, m_return_reason);\n\t\n\tDraw_Batched();\n}\n\n\nvoid M_OnlineServerList_Key (int key)\n{\n\tint\t\tl;\n\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_MultiPlayer_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tonlineServerList_cursor--;\n\t\tif (onlineServerList_cursor < 0)\n\t\t\tonlineServerList_cursor = NUM_SERVERS-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tonlineServerList_cursor++;\n\t\tif (onlineServerList_cursor >= NUM_SERVERS)\n\t\t\tonlineServerList_cursor = 0;\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tm_return_state = m_state;\n\t\tm_return_onerror = true;\n\t\tkey_dest = key_game;\n\t\tm_state = m_none;\n\t\tCbuf_AddText (\"stopdemo\\n\");\n\n\t\tif (onlineServerList_cursor == 0) Cbuf_AddText (\"connect 212.24.100.151\\n\");\n\t\tif (onlineServerList_cursor == 1) Cbuf_AddText (\"connect 212.24.100.151:27000\\n\");\n\t\tif (onlineServerList_cursor == 2) Cbuf_AddText (\"connect quake.nctech.ca\\n\");\n\t\tif (onlineServerList_cursor == 3) Cbuf_AddText (\"connect quake.shmack.net\\n\");\n\t\tif (onlineServerList_cursor == 4) Cbuf_AddText (\"connect dm.clanhdz.com\\n\");\n\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* GAME OPTIONS MENU */\n\ntypedef struct\n{\n\tchar\t*name;\n\tchar\t*description;\n} level_t;\n\nlevel_t\t\tlevels[] =\n{\n\t{\"start\", \"Entrance\"},\t// 0\n\n\t{\"e1m1\", \"Slipgate Complex\"},\t\t\t\t// 1\n\t{\"e1m2\", \"Castle of the Damned\"},\n\t{\"e1m3\", \"The Necropolis\"},\n\t{\"e1m4\", \"The Grisly Grotto\"},\n\t{\"e1m5\", \"Gloom Keep\"},\n\t{\"e1m6\", \"The Door To Chthon\"},\n\t{\"e1m7\", \"The House of Chthon\"},\n\t{\"e1m8\", \"Ziggurat Vertigo\"},\n\n\t{\"e2m1\", \"The Installation\"},\t\t\t\t// 9\n\t{\"e2m2\", \"Ogre Citadel\"},\n\t{\"e2m3\", \"Crypt of Decay\"},\n\t{\"e2m4\", \"The Ebon Fortress\"},\n\t{\"e2m5\", \"The Wizard's Manse\"},\n\t{\"e2m6\", \"The Dismal Oubliette\"},\n\t{\"e2m7\", \"Underearth\"},\n\n\t{\"e3m1\", \"Termination Central\"},\t\t\t// 16\n\t{\"e3m2\", \"The Vaults of Zin\"},\n\t{\"e3m3\", \"The Tomb of Terror\"},\n\t{\"e3m4\", \"Satan's Dark Delight\"},\n\t{\"e3m5\", \"Wind Tunnels\"},\n\t{\"e3m6\", \"Chambers of Torment\"},\n\t{\"e3m7\", \"The Haunted Halls\"},\n\n\t{\"e4m1\", \"The Sewage System\"},\t\t\t\t// 23\n\t{\"e4m2\", \"The Tower of Despair\"},\n\t{\"e4m3\", \"The Elder God Shrine\"},\n\t{\"e4m4\", \"The Palace of Hate\"},\n\t{\"e4m5\", \"Hell's Atrium\"},\n\t{\"e4m6\", \"The Pain Maze\"},\n\t{\"e4m7\", \"Azure Agony\"},\n\t{\"e4m8\", \"The Nameless City\"},\n\n\t{\"end\", \"Shub-Niggurath's Pit\"},\t\t\t// 31\n\n\t{\"dm1\", \"Place of Two Deaths\"},\t\t\t\t// 32\n\t{\"dm2\", \"Claustrophobopolis\"},\n\t{\"dm3\", \"The Abandoned Base\"},\n\t{\"dm4\", \"The Bad Place\"},\n\t{\"dm5\", \"The Cistern\"},\n\t{\"dm6\", \"The Dark Zone\"}\n};\n\n//MED 01/06/97 added hipnotic levels\nlevel_t     hipnoticlevels[] =\n{\n   {\"start\", \"Command HQ\"},  // 0\n\n   {\"hip1m1\", \"The Pumping Station\"},          // 1\n   {\"hip1m2\", \"Storage Facility\"},\n   {\"hip1m3\", \"The Lost Mine\"},\n   {\"hip1m4\", \"Research Facility\"},\n   {\"hip1m5\", \"Military Complex\"},\n\n   {\"hip2m1\", \"Ancient Realms\"},          // 6\n   {\"hip2m2\", \"The Black Cathedral\"},\n   {\"hip2m3\", \"The Catacombs\"},\n   {\"hip2m4\", \"The Crypt\"},\n   {\"hip2m5\", \"Mortum's Keep\"},\n   {\"hip2m6\", \"The Gremlin's Domain\"},\n\n   {\"hip3m1\", \"Tur Torment\"},       // 12\n   {\"hip3m2\", \"Pandemonium\"},\n   {\"hip3m3\", \"Limbo\"},\n   {\"hip3m4\", \"The Gauntlet\"},\n\n   {\"hipend\", \"Armagon's Lair\"},       // 16\n\n   {\"hipdm1\", \"The Edge of Oblivion\"}           // 17\n};\n\n//PGM 01/07/97 added rogue levels\n//PGM 03/02/97 added dmatch level\nlevel_t\t\troguelevels[] =\n{\n\t{\"start\",\t\"Split Decision\"},\n\t{\"r1m1\",\t\"Deviant's Domain\"},\n\t{\"r1m2\",\t\"Dread Portal\"},\n\t{\"r1m3\",\t\"Judgement Call\"},\n\t{\"r1m4\",\t\"Cave of Death\"},\n\t{\"r1m5\",\t\"Towers of Wrath\"},\n\t{\"r1m6\",\t\"Temple of Pain\"},\n\t{\"r1m7\",\t\"Tomb of the Overlord\"},\n\t{\"r2m1\",\t\"Tempus Fugit\"},\n\t{\"r2m2\",\t\"Elemental Fury I\"},\n\t{\"r2m3\",\t\"Elemental Fury II\"},\n\t{\"r2m4\",\t\"Curse of Osiris\"},\n\t{\"r2m5\",\t\"Wizard's Keep\"},\n\t{\"r2m6\",\t\"Blood Sacrifice\"},\n\t{\"r2m7\",\t\"Last Bastion\"},\n\t{\"r2m8\",\t\"Source of Evil\"},\n\t{\"ctf1\",    \"Division of Change\"}\n};\n\ntypedef struct\n{\n\tchar\t*description;\n\tint\t\tfirstLevel;\n\tint\t\tlevels;\n} episode_t;\n\nepisode_t\tepisodes[] =\n{\n\t{\"Welcome to Quake\", 0, 1},\n\t{\"Doomed Dimension\", 1, 8},\n\t{\"Realm of Black Magic\", 9, 7},\n\t{\"Netherworld\", 16, 7},\n\t{\"The Elder World\", 23, 8},\n\t{\"Final Level\", 31, 1},\n\t{\"Deathmatch Arena\", 32, 6}\n};\n\n//MED 01/06/97  added hipnotic episodes\nepisode_t   hipnoticepisodes[] =\n{\n   {\"Scourge of Armagon\", 0, 1},\n   {\"Fortress of the Dead\", 1, 5},\n   {\"Dominion of Darkness\", 6, 6},\n   {\"The Rift\", 12, 4},\n   {\"Final Level\", 16, 1},\n   {\"Deathmatch Arena\", 17, 1}\n};\n\n//PGM 01/07/97 added rogue episodes\n//PGM 03/02/97 added dmatch episode\nepisode_t\trogueepisodes[] =\n{\n\t{\"Introduction\", 0, 1},\n\t{\"Hell's Fortress\", 1, 7},\n\t{\"Corridors of Time\", 8, 8},\n\t{\"Deathmatch Arena\", 16, 1}\n};\n\nint\tstartepisode;\nint\tstartlevel;\nint maxplayers;\nbool m_serverInfoMessage = false;\ndouble m_serverInfoMessageTime;\n\nvoid M_Menu_GameOptions_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_gameoptions;\n\tm_entersound = true;\n\tif (maxplayers == 0)\n\t\tmaxplayers = svs.maxclients;\n\tif (maxplayers < 2)\n\t\tmaxplayers = svs.maxclientslimit;\n}\n\n\nint gameoptions_cursor_table[] = {40, 56, 64, 72, 80, 88, 96, 112, 120};\n#define\tNUM_GAMEOPTIONS\t9\nint\t\tgameoptions_cursor;\n\nvoid M_GameOptions_Draw (void)\n{\n\tqpic_t\t*p;\n\tint\t\tx;\n\n\tM_DrawTransPic (16, 4, Draw_CachePic (\"gfx/qplaque.lmp\") );\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\n\tM_DrawTextBox (152, 32, 10, 1);\n\tM_Print (160, 40, \"begin game\");\n\n\tM_Print (0, 56, \"      Max players\");\n\tM_Print (160, 56, va(\"%i\", maxplayers) );\n\n\tM_Print (0, 64, \"        Game Type\");\n\tif (coop.value)\n\t\tM_Print (160, 64, \"Cooperative\");\n\telse\n\t\tM_Print (160, 64, \"Deathmatch\");\n\n\tM_Print (0, 72, \"        Teamplay\");\n\tif (rogue)\n\t{\n\t\tchar *msg;\n\n\t\tswitch((int)teamplay.value)\n\t\t{\n\t\t\tcase 1: msg = \"No Friendly Fire\"; break;\n\t\t\tcase 2: msg = \"Friendly Fire\"; break;\n\t\t\tcase 3: msg = \"Tag\"; break;\n\t\t\tcase 4: msg = \"Capture the Flag\"; break;\n\t\t\tcase 5: msg = \"One Flag CTF\"; break;\n\t\t\tcase 6: msg = \"Three Team CTF\"; break;\n\t\t\tdefault: msg = \"Off\"; break;\n\t\t}\n\t\tM_Print (160, 72, msg);\n\t}\n\telse\n\t{\n\t\tchar *msg;\n\n\t\tswitch((int)teamplay.value)\n\t\t{\n\t\t\tcase 1: msg = \"No Friendly Fire\"; break;\n\t\t\tcase 2: msg = \"Friendly Fire\"; break;\n\t\t\tdefault: msg = \"Off\"; break;\n\t\t}\n\t\tM_Print (160, 72, msg);\n\t}\n\n\tM_Print (0, 80, \"            Skill\");\n\tif (skill.value == 0)\n\t\tM_Print (160, 80, \"Easy difficulty\");\n\telse if (skill.value == 1)\n\t\tM_Print (160, 80, \"Normal difficulty\");\n\telse if (skill.value == 2)\n\t\tM_Print (160, 80, \"Hard difficulty\");\n\telse\n\t\tM_Print (160, 80, \"Nightmare difficulty\");\n\n\tM_Print (0, 88, \"       Frag Limit\");\n\tif (fraglimit.value == 0)\n\t\tM_Print (160, 88, \"none\");\n\telse\n\t\tM_Print (160, 88, va(\"%i frags\", (int)fraglimit.value));\n\n\tM_Print (0, 96, \"       Time Limit\");\n\tif (timelimit.value == 0)\n\t\tM_Print (160, 96, \"none\");\n\telse\n\t\tM_Print (160, 96, va(\"%i minutes\", (int)timelimit.value));\n\n\tM_Print (0, 112, \"         Episode\");\n   //MED 01/06/97 added hipnotic episodes\n   if (hipnotic)\n      M_Print (160, 112, hipnoticepisodes[startepisode].description);\n   //PGM 01/07/97 added rogue episodes\n   else if (rogue)\n      M_Print (160, 112, rogueepisodes[startepisode].description);\n   else\n      M_Print (160, 112, episodes[startepisode].description);\n\n\tM_Print (0, 120, \"           Level\");\n   //MED 01/06/97 added hipnotic episodes\n   if (hipnotic)\n   {\n      M_Print (160, 120, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].description);\n      M_Print (160, 128, hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name);\n   }\n   //PGM 01/07/97 added rogue episodes\n   else if (rogue)\n   {\n      M_Print (160, 120, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].description);\n      M_Print (160, 128, roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name);\n   }\n   else\n   {\n      M_Print (160, 120, levels[episodes[startepisode].firstLevel + startlevel].description);\n      M_Print (160, 128, levels[episodes[startepisode].firstLevel + startlevel].name);\n   }\n\n// line cursor\n\tM_DrawCharacter (144, gameoptions_cursor_table[gameoptions_cursor], 12+((int)(realtime*4)&1));\n\n\tif (m_serverInfoMessage)\n\t{\n\t\tif ((realtime - m_serverInfoMessageTime) < 5.0)\n\t\t{\n\t\t\tx = (320-26*8)/2 + 8;\n\t\t\tM_Print (x, 146, \"  More than 4 players   \");\n\t\t\tM_Print (x, 154, \" requires using command \");\n\t\t\tM_Print (x, 162, \"line parameters; please \");\n\t\t\tM_Print (x, 170, \"   see techinfo.txt.    \");\n\t\t\tDraw_Batched();\n\n\t\t\tM_DrawTextBox ((320-26*8)/2, 138, 24, 4);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tDraw_Batched();\n\t\t\tm_serverInfoMessage = false;\n\t\t}\n\t} else\n\t\tDraw_Batched();\n}\n\n\nvoid M_NetStart_Change (int dir)\n{\n\tint count;\n\n\tswitch (gameoptions_cursor)\n\t{\n\tcase 1:\n\t\tmaxplayers += dir;\n\t\tif (maxplayers > svs.maxclientslimit)\n\t\t{\n\t\t\tmaxplayers = svs.maxclientslimit;\n\t\t\tm_serverInfoMessage = true;\n\t\t\tm_serverInfoMessageTime = realtime;\n\t\t}\n\t\tif (maxplayers < 2)\n\t\t\tmaxplayers = 2;\n\t\tbreak;\n\n\tcase 2:\n\t\tCvar_SetValue (\"coop\", coop.value ? 0 : 1);\n\t\tbreak;\n\n\tcase 3:\n\t\tif (rogue)\n\t\t\tcount = 6;\n\t\telse\n\t\t\tcount = 2;\n\n\t\tCvar_SetValue (\"teamplay\", teamplay.value + dir);\n\t\tif (teamplay.value > count)\n\t\t\tCvar_SetValue (\"teamplay\", 0);\n\t\telse if (teamplay.value < 0)\n\t\t\tCvar_SetValue (\"teamplay\", count);\n\t\tbreak;\n\n\tcase 4:\n\t\tCvar_SetValue (\"skill\", skill.value + dir);\n\t\tif (skill.value > 3)\n\t\t\tCvar_SetValue (\"skill\", 0);\n\t\tif (skill.value < 0)\n\t\t\tCvar_SetValue (\"skill\", 3);\n\t\tbreak;\n\n\tcase 5:\n\t\tCvar_SetValue (\"fraglimit\", fraglimit.value + dir*10);\n\t\tif (fraglimit.value > 100)\n\t\t\tCvar_SetValue (\"fraglimit\", 0);\n\t\tif (fraglimit.value < 0)\n\t\t\tCvar_SetValue (\"fraglimit\", 100);\n\t\tbreak;\n\n\tcase 6:\n\t\tCvar_SetValue (\"timelimit\", timelimit.value + dir*5);\n\t\tif (timelimit.value > 60)\n\t\t\tCvar_SetValue (\"timelimit\", 0);\n\t\tif (timelimit.value < 0)\n\t\t\tCvar_SetValue (\"timelimit\", 60);\n\t\tbreak;\n\n\tcase 7:\n\t\tstartepisode += dir;\n\t//MED 01/06/97 added hipnotic count\n\t\tif (hipnotic)\n\t\t\tcount = 6;\n\t//PGM 01/07/97 added rogue count\n\t//PGM 03/02/97 added 1 for dmatch episode\n\t\telse if (rogue)\n\t\t\tcount = 4;\n\t\telse if (registered.value)\n\t\t\tcount = 7;\n\t\telse\n\t\t\tcount = 2;\n\n\t\tif (startepisode < 0)\n\t\t\tstartepisode = count - 1;\n\n\t\tif (startepisode >= count)\n\t\t\tstartepisode = 0;\n\n\t\tstartlevel = 0;\n\t\tbreak;\n\n\tcase 8:\n\t\tstartlevel += dir;\n    //MED 01/06/97 added hipnotic episodes\n\t\tif (hipnotic)\n\t\t\tcount = hipnoticepisodes[startepisode].levels;\n\t//PGM 01/06/97 added hipnotic episodes\n\t\telse if (rogue)\n\t\t\tcount = rogueepisodes[startepisode].levels;\n\t\telse\n\t\t\tcount = episodes[startepisode].levels;\n\n\t\tif (startlevel < 0)\n\t\t\tstartlevel = count - 1;\n\n\t\tif (startlevel >= count)\n\t\t\tstartlevel = 0;\n\t\tbreak;\n\t}\n}\n\nvoid M_GameOptions_Key (int key)\n{\n\tswitch (key)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_Net_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tgameoptions_cursor--;\n\t\tif (gameoptions_cursor < 0)\n\t\t\tgameoptions_cursor = NUM_GAMEOPTIONS-1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tgameoptions_cursor++;\n\t\tif (gameoptions_cursor >= NUM_GAMEOPTIONS)\n\t\t\tgameoptions_cursor = 0;\n\t\tbreak;\n\n\tcase K_LEFTARROW:\n\t\tif (gameoptions_cursor == 0)\n\t\t\tbreak;\n\t\tS_LocalSound (\"misc/menu3.wav\");\n\t\tM_NetStart_Change (-1);\n\t\tbreak;\n\n\tcase K_RIGHTARROW:\n\t\tif (gameoptions_cursor == 0)\n\t\t\tbreak;\n\t\tS_LocalSound (\"misc/menu3.wav\");\n\t\tM_NetStart_Change (1);\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tif (gameoptions_cursor == 0)\n\t\t{\n\t\t\tif (sv.active)\n\t\t\t\tCbuf_AddText (\"disconnect\\n\");\n\t\t\tCbuf_AddText (\"listen 0\\n\");\t// so host_netport will be re-examined\n\t\t\tCbuf_AddText ( va (\"maxplayers %u\\n\", maxplayers) );\n\t\t\tSCR_BeginLoadingPlaque ();\n\n\t\t\tif (hipnotic)\n\t\t\t\tCbuf_AddText ( va (\"map %s\\n\", hipnoticlevels[hipnoticepisodes[startepisode].firstLevel + startlevel].name) );\n\t\t\telse if (rogue)\n\t\t\t\tCbuf_AddText ( va (\"map %s\\n\", roguelevels[rogueepisodes[startepisode].firstLevel + startlevel].name) );\n\t\t\telse\n\t\t\t\tCbuf_AddText ( va (\"map %s\\n\", levels[episodes[startepisode].firstLevel + startlevel].name) );\n\n\t\t\treturn;\n\t\t}\n\n\t\tM_NetStart_Change (1);\n\t\tbreak;\n\t}\n}\n\n//=============================================================================\n/* SEARCH MENU */\n\nbool\tsearchComplete = false;\ndouble\t\tsearchCompleteTime;\n\nvoid M_Menu_Search_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_search;\n\tm_entersound = false;\n\tslistSilent = true;\n\tslistLocal = false;\n\tsearchComplete = false;\n\tNET_Slist_f();\n\n}\n\n\nvoid M_Search_Draw (void)\n{\n\tqpic_t\t*p;\n\tint x;\n\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tx = (320/2) - ((12*8)/2) + 4;\n\tM_DrawTextBox (x-8, 32, 12, 1);\n\tDraw_String (x, 40, \"Searching...\", 128);\n\n\tif(slistInProgress)\n\t{\n\t\tNET_Poll();\n\t\treturn;\n\t}\n\n\tif (! searchComplete)\n\t{\n\t\tsearchComplete = true;\n\t\tsearchCompleteTime = realtime;\n\t}\n\n\tif (hostCacheCount)\n\t{\n\t\tM_Menu_ServerList_f ();\n\t\treturn;\n\t}\n\n\tDraw_String ((320/2) - ((22*8)/2), 64, \"No Quake servers found\", 0);\n\tif ((realtime - searchCompleteTime) < 3.0)\n\t\treturn;\n\n\tM_Menu_LanConfig_f ();\n}\n\n\nvoid M_Search_Key (int key)\n{\n}\n\n//=============================================================================\n/* SLIST MENU */\n\nint\t\tslist_cursor;\nbool slist_sorted;\n\nvoid M_Menu_ServerList_f (void)\n{\n\tkey_dest = key_menu;\n\tm_state = m_slist;\n\tm_entersound = true;\n\tslist_cursor = 0;\n\tm_return_onerror = false;\n\tm_return_reason[0] = 0;\n\tslist_sorted = false;\n}\n\n\nvoid M_ServerList_Draw (void)\n{\n\tint\t\tn;\n\tchar\tstring [64];\n\tqpic_t\t*p;\n\n\tif (!slist_sorted)\n\t{\n\t\tif (hostCacheCount > 1)\n\t\t{\n\t\t\tint\ti,j;\n\t\t\thostcache_t temp;\n\t\t\tfor (i = 0; i < hostCacheCount; i++)\n\t\t\t\tfor (j = i+1; j < hostCacheCount; j++)\n\t\t\t\t\tif (strcmp(hostcache[j].name, hostcache[i].name) < 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tmemcpy(&temp, &hostcache[j], sizeof(hostcache_t));\n\t\t\t\t\t\tmemcpy(&hostcache[j], &hostcache[i], sizeof(hostcache_t));\n\t\t\t\t\t\tmemcpy(&hostcache[i], &temp, sizeof(hostcache_t));\n\t\t\t\t\t}\n\t\t}\n\t\tslist_sorted = true;\n\t}\n\n\tp = Draw_CachePic (\"gfx/p_multi.lmp\");\n\tM_DrawPic ( (320-p->width)/2, 4, p);\n\tfor (n = 0; n < hostCacheCount; n++)\n\t{\n\t\tif (hostcache[n].maxusers)\n\t\t\tsprintf(string, \"%-15.15s %-15.15s %2u/%2u\\n\", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);\n\t\telse\n\t\t\tsprintf(string, \"%-15.15s %-15.15s\\n\", hostcache[n].name, hostcache[n].map);\n\t\tM_Print (16, 32 + 8*n, string);\n\t}\n\tM_DrawCharacter (0, 32 + slist_cursor*8, 12+((int)(realtime*4)&1));\n\n\tif (*m_return_reason)\n\t\tM_PrintWhite (16, 148, m_return_reason);\n}\n\n\nvoid M_ServerList_Key (int k)\n{\n\tswitch (k)\n\t{\n\tcase K_ENTER:\n\tcase K_START:\n\tcase K_TRIANGLE:\n\t\tM_Menu_LanConfig_f ();\n\t\tbreak;\n\n\tcase K_SPACE:\n\t\tM_Menu_Search_f ();\n\t\tbreak;\n\n\tcase K_UPARROW:\n\tcase K_LEFTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tslist_cursor--;\n\t\tif (slist_cursor < 0)\n\t\t\tslist_cursor = hostCacheCount - 1;\n\t\tbreak;\n\n\tcase K_DOWNARROW:\n\tcase K_RIGHTARROW:\n\t\tS_LocalSound (\"misc/menu1.wav\");\n\t\tslist_cursor++;\n\t\tif (slist_cursor >= hostCacheCount)\n\t\t\tslist_cursor = 0;\n\t\tbreak;\n\n\tcase K_CIRCLE:\n\tcase K_CROSS:\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tm_return_state = m_state;\n\t\tm_return_onerror = true;\n\t\tslist_sorted = false;\n\t\tkey_dest = key_game;\n\t\tm_state = m_none;\n\t\tCbuf_AddText ( va (\"connect \\\"%s\\\"\\n\", hostcache[slist_cursor].cname) );\n\t\tbreak;\n\n\tdefault:\n\t\tbreak;\n\t}\n\n}\n\n//=============================================================================\n/* Menu Subsystem */\n\n\nvoid M_Init (void)\n{\n\tCmd_AddCommand (\"togglemenu\", M_ToggleMenu_f);\n\n\tCmd_AddCommand (\"menu_main\", M_Menu_Main_f);\n\tCmd_AddCommand (\"menu_singleplayer\", M_Menu_SinglePlayer_f);\n\tCmd_AddCommand (\"menu_load\", M_Menu_Load_f);\n\tCmd_AddCommand (\"menu_save\", M_Menu_Save_f);\n\tCmd_AddCommand (\"menu_multiplayer\", M_Menu_MultiPlayer_f);\n\tCmd_AddCommand (\"menu_setup\", M_Menu_Setup_f);\n\tCmd_AddCommand (\"menu_options\", M_Menu_Options_f);\n\tCmd_AddCommand (\"menu_keys\", M_Menu_Keys_f);\n\tCmd_AddCommand (\"menu_video\", M_Menu_Video_f);\n\tCmd_AddCommand (\"help\", M_Menu_Help_f);\n\tCmd_AddCommand (\"menu_quit\", M_Menu_Quit_f);\n}\n\n\nvoid M_Draw (void)\n{\n\tif (m_state == m_none || key_dest != key_menu)\n\t\treturn;\n\n\tif (!m_recursiveDraw)\n\t{\n\t\tscr_copyeverything = 1;\n\n\t\tif (scr_con_current)\n\t\t{\n\t\t\tDraw_ConsoleBackground ();\n\t\t\tVID_UnlockBuffer ();\n\t\t\tS_ExtraUpdate ();\n\t\t\tVID_LockBuffer ();\n\t\t}\n\t\telse\n\t\t\tDraw_FadeScreen ();\n\n\t\tscr_fullupdate = 0;\n\t}\n\telse\n\t{\n\t\tm_recursiveDraw = false;\n\t}\n\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n\tswitch (m_state)\n\t{\n\tcase m_none:\n\t\tbreak;\n\n\tcase m_main:\n\t\tM_Main_Draw ();\n\t\tbreak;\n\n\tcase m_singleplayer:\n\t\tM_SinglePlayer_Draw ();\n\t\tbreak;\n\n\tcase m_load:\n\t\tM_Load_Draw ();\n\t\tbreak;\n\n\tcase m_save:\n\t\tM_Save_Draw ();\n\t\tbreak;\n\n\tcase m_multiplayer:\n\t\tM_MultiPlayer_Draw ();\n\t\tbreak;\n\n\tcase m_setup:\n\t\tM_Setup_Draw ();\n\t\tbreak;\n\n\tcase m_net:\n\t\tM_Net_Draw ();\n\t\tbreak;\n\n\tcase m_options:\n\t\tM_Options_Draw ();\n\t\tbreak;\n\t\t\n\tcase m_graphics:\n\t\tM_Graphics_Draw();\n\t\tbreak;\n\t\t\n\tcase m_mods:\n\t\tM_Mods_Draw();\n\t\tbreak;\n\n\tcase m_keys:\n\t\tM_Keys_Draw ();\n\t\tbreak;\n\n\tcase m_video:\n\t\tM_Video_Draw ();\n\t\tbreak;\n\n\tcase m_help:\n\t\tM_Help_Draw ();\n\t\tbreak;\n\n\tcase m_quit:\n\t\tM_Quit_Draw ();\n\t\tbreak;\n\n\tcase m_lanconfig:\n\t\tM_LanConfig_Draw ();\n\t\tbreak;\n\n\tcase m_gameoptions:\n\t\tM_GameOptions_Draw ();\n\t\tbreak;\n\n\tcase m_search:\n\t\tM_Search_Draw ();\n\t\tbreak;\n\n\tcase m_slist:\n\t\tM_ServerList_Draw ();\n\t\tbreak;\n\n\tcase m_onlineserverlist:\n\t\tM_OnlineServerList_Draw();\n\t\tbreak;\n\n\tcase m_benchmark:\n\t\tM_Benchmark_Draw();\n\t\tbreak;\n\t}\n\n\tif (m_entersound)\n\t{\n\t\tS_LocalSound (\"misc/menu2.wav\");\n\t\tm_entersound = false;\n\t}\n\n\tVID_UnlockBuffer ();\n\tS_ExtraUpdate ();\n\tVID_LockBuffer ();\n}\n\n\nvoid M_Keydown (int key)\n{\n\tswitch (m_state)\n\t{\n\tcase m_none:\n\t\treturn;\n\n\tcase m_main:\n\t\tM_Main_Key (key);\n\t\treturn;\n\n\tcase m_singleplayer:\n\t\tM_SinglePlayer_Key (key);\n\t\treturn;\n\n\tcase m_load:\n\t\tM_Load_Key (key);\n\t\treturn;\n\n\tcase m_save:\n\t\tM_Save_Key (key);\n\t\treturn;\n\n\tcase m_multiplayer:\n\t\tM_MultiPlayer_Key (key);\n\t\treturn;\n\n\tcase m_setup:\n\t\tM_Setup_Key (key);\n\t\treturn;\n\n\tcase m_net:\n\t\tM_Net_Key (key);\n\t\treturn;\n\n\tcase m_options:\n\t\tM_Options_Key (key);\n\t\treturn;\n\t\t\n\tcase m_graphics:\n\t\tM_Graphics_Key (key);\n\t\treturn;\n\n\tcase m_mods:\n\t\tM_Mods_Key (key);\n\t\treturn;\n\n\tcase m_keys:\n\t\tM_Keys_Key (key);\n\t\treturn;\n\n\tcase m_video:\n\t\tM_Video_Key (key);\n\t\treturn;\n\n\tcase m_help:\n\t\tM_Help_Key (key);\n\t\treturn;\n\n\tcase m_quit:\n\t\tM_Quit_Key (key);\n\t\treturn;\n\n\tcase m_lanconfig:\n\t\tM_LanConfig_Key (key);\n\t\treturn;\n\n\tcase m_gameoptions:\n\t\tM_GameOptions_Key (key);\n\t\treturn;\n\n\tcase m_search:\n\t\tM_Search_Key (key);\n\t\tbreak;\n\n\tcase m_slist:\n\t\tM_ServerList_Key (key);\n\t\treturn;\n\n\tcase m_onlineserverlist:\n\t\tM_OnlineServerList_Key (key);\n\t\tbreak;\n\n\tcase m_benchmark:\n\t\tM_Benchmark_Key (key);\n\t\tbreak;\n\t}\n}\n\n\nvoid M_ConfigureNetSubsystem(void)\n{\n// enable/disable net systems to match desired config\n\n\tCbuf_AddText (\"stopdemo\\n\");\n\n\t//if (IPXConfig || TCPIPConfig)\n\t\tnet_hostport = lanConfig_port;\n}\n"
  },
  {
    "path": "source/menu.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n//\n// the net drivers should just set the apropriate bits in m_activenet,\n// instead of having the menu code look through their internal tables\n//\n#define\tMNET_IPX\t\t1\n#define\tMNET_TCP\t\t2\n\nextern\tint\tm_activenet;\n\n//\n// menus\n//\nvoid M_Init (void);\nvoid M_Keydown (int key);\nvoid M_Draw (void);\nvoid M_ToggleMenu_f (void);\n\n\n"
  },
  {
    "path": "source/model.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#ifndef __MODEL__\n#define __MODEL__\n\n#include \"modelgen.h\"\n#include \"spritegn.h\"\n\n/*\n\nd*_t structures are on-disk representations\nm*_t structures are in-memory\n\n*/\n\n/*\n==============================================================================\n\nBRUSH MODELS\n\n==============================================================================\n*/\n\n\n//\n// in memory representation\n//\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct\n{\n\tvec3_t\t\tposition;\n} mvertex_t;\n\n#define\tSIDE_FRONT\t0\n#define\tSIDE_BACK\t1\n#define\tSIDE_ON\t\t2\n\n\n// plane_t structure\n// !!! if this is changed, it must be changed in asm_i386.h too !!!\ntypedef struct mplane_s\n{\n\tvec3_t\tnormal;\n\tfloat\tdist;\n\tbyte\ttype;\t\t\t// for texture axis selection and fast side tests\n\tbyte\tsignbits;\t\t// signx + signy<<1 + signz<<1\n\tbyte\tpad[2];\n} mplane_t;\n\ntypedef struct texture_s\n{\n\tchar\t\tname[16];\n\tunsigned\twidth, height;\n\tint\t\t\tanim_total;\t\t\t\t// total tenths in sequence ( 0 = no)\n\tint\t\t\tanim_min, anim_max;\t\t// time for this frame min <=time< max\n\tstruct texture_s *anim_next;\t\t// in the animation sequence\n\tstruct texture_s *alternate_anims;\t// bmodels in frmae 1 use these\n\tunsigned\toffsets[MIPLEVELS];\t\t// four mip maps stored\n} texture_t;\n\n\n#define\tSURF_PLANEBACK\t\tBIT(1)\n#define\tSURF_DRAWSKY\t\tBIT(2)\n#define SURF_DRAWSPRITE\t\tBIT(3)\n#define SURF_DRAWTURB\t\tBIT(4)\n#define SURF_DRAWTILED\t\tBIT(5)\n#define SURF_DRAWBACKGROUND\tBIT(6)\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct\n{\n\tunsigned short\tv[2];\n\tunsigned int\tcachededgeoffset;\n} medge_t;\n\ntypedef struct\n{\n\tfloat\t\tvecs[2][4];\n\tfloat\t\tmipadjust;\n\ttexture_t\t*texture;\n\tint\t\t\tflags;\n} mtexinfo_t;\n\ntypedef struct msurface_s\n{\n\tint\t\t\tvisframe;\t\t// should be drawn when node is crossed\n\n\tint\t\t\tdlightframe;\n\tint\t\t\tdlightbits;\n\n\tmplane_t\t*plane;\n\tint\t\t\tflags;\n\n\tint\t\t\tfirstedge;\t// look up in model->surfedges[], negative numbers\n\tint\t\t\tnumedges;\t// are backwards edges\n\n// surface generation data\n\tstruct surfcache_s\t*cachespots[MIPLEVELS];\n\n\tshort\t\ttexturemins[2];\n\tshort\t\textents[2];\n\n\tmtexinfo_t\t*texinfo;\n\n// lighting info\n\tbyte\t\tstyles[MAXLIGHTMAPS];\n\tbyte\t\t*samples;\t\t// [numstyles*surfsize]\n} msurface_t;\n\ntypedef struct mnode_s\n{\n// common with leaf\n\tint\t\t\tcontents;\t\t// 0, to differentiate from leafs\n\tint\t\t\tvisframe;\t\t// node needs to be traversed if current\n\n\tshort\t\tminmaxs[6];\t\t// for bounding box culling\n\n\tstruct mnode_s\t*parent;\n\n// node specific\n\tmplane_t\t*plane;\n\tstruct mnode_s\t*children[2];\n\n\tunsigned short\t\tfirstsurface;\n\tunsigned short\t\tnumsurfaces;\n} mnode_t;\n\n\n\ntypedef struct mleaf_s\n{\n// common with node\n\tint\t\t\tcontents;\t\t// wil be a negative contents number\n\tint\t\t\tvisframe;\t\t// node needs to be traversed if current\n\n\tshort\t\tminmaxs[6];\t\t// for bounding box culling\n\n\tstruct mnode_s\t*parent;\n\n// leaf specific\n\tbyte\t\t*compressed_vis;\n\tefrag_t\t\t*efrags;\n\n\tmsurface_t\t**firstmarksurface;\n\tint\t\t\tnummarksurfaces;\n\tint\t\t\tkey;\t\t\t// BSP sequence number for leaf's contents\n\tbyte\t\tambient_sound_level[NUM_AMBIENTS];\n} mleaf_t;\n\n// !!! if this is changed, it must be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tdclipnode_t\t*clipnodes;\n\tmplane_t\t*planes;\n\tint\t\t\tfirstclipnode;\n\tint\t\t\tlastclipnode;\n\tvec3_t\t\tclip_mins;\n\tvec3_t\t\tclip_maxs;\n} hull_t;\n\n/*\n==============================================================================\n\nSPRITE MODELS\n\n==============================================================================\n*/\n\n\n// FIXME: shorten these?\ntypedef struct mspriteframe_s\n{\n\tint\t\twidth;\n\tint\t\theight;\n\tvoid\t*pcachespot;\t\t\t// remove?\n\tfloat\tup, down, left, right;\n\tbyte\tpixels[4];\n} mspriteframe_t;\n\ntypedef struct\n{\n\tint\t\t\t\tnumframes;\n\tfloat\t\t\t*intervals;\n\tmspriteframe_t\t*frames[1];\n} mspritegroup_t;\n\ntypedef struct\n{\n\tspriteframetype_t\ttype;\n\tmspriteframe_t\t\t*frameptr;\n} mspriteframedesc_t;\n\ntypedef struct\n{\n\tint\t\t\t\t\ttype;\n\tint\t\t\t\t\tmaxwidth;\n\tint\t\t\t\t\tmaxheight;\n\tint\t\t\t\t\tnumframes;\n\tfloat\t\t\t\tbeamlength;\t\t// remove?\n\tvoid\t\t\t\t*cachespot;\t\t// remove?\n\tmspriteframedesc_t\tframes[1];\n} msprite_t;\n\n\n/*\n==============================================================================\n\nALIAS MODELS\n\nAlias models are position independent, so the cache manager can move them.\n==============================================================================\n*/\n\ntypedef struct\n{\n\taliasframetype_t\ttype;\n\ttrivertx_t\t\t\tbboxmin;\n\ttrivertx_t\t\t\tbboxmax;\n\tint\t\t\t\t\tframe;\n\tchar\t\t\t\tname[16];\n} maliasframedesc_t;\n\ntypedef struct\n{\n\taliasskintype_t\t\ttype;\n\tvoid\t\t\t\t*pcachespot;\n\tint\t\t\t\t\tskin;\n} maliasskindesc_t;\n\ntypedef struct\n{\n\ttrivertx_t\t\t\tbboxmin;\n\ttrivertx_t\t\t\tbboxmax;\n\tint\t\t\t\t\tframe;\n} maliasgroupframedesc_t;\n\ntypedef struct\n{\n\tint\t\t\t\t\t\tnumframes;\n\tint\t\t\t\t\t\tintervals;\n\tmaliasgroupframedesc_t\tframes[1];\n} maliasgroup_t;\n\ntypedef struct\n{\n\tint\t\t\t\t\tnumskins;\n\tint\t\t\t\t\tintervals;\n\tmaliasskindesc_t\tskindescs[1];\n} maliasskingroup_t;\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct mtriangle_s {\n\tint\t\t\t\t\tfacesfront;\n\tint\t\t\t\t\tvertindex[3];\n} mtriangle_t;\n\ntypedef struct {\n\tint\t\t\t\t\tmodel;\n\tint\t\t\t\t\tstverts;\n\tint\t\t\t\t\tskindesc;\n\tint\t\t\t\t\ttriangles;\n\tmaliasframedesc_t\tframes[1];\n} aliashdr_t;\n\n//===================================================================\n\n//\n// Whole model\n//\n\ntypedef enum {mod_brush, mod_sprite, mod_alias} modtype_t;\n\n#define\tMF_ROCKET\t1\t\t\t// leave a trail\n#define\tMF_GRENADE\t2\t\t\t// leave a trail\n#define\tMF_GIB\t\t4\t\t\t// leave a trail\n#define\tMF_ROTATE\t8\t\t\t// rotate (bonus items)\n#define\tMF_TRACER\t16\t\t\t// green split trail\n#define\tMF_ZOMGIB\t32\t\t\t// small blood trail\n#define\tMF_TRACER2\t64\t\t\t// orange split trail + rotate\n#define\tMF_TRACER3\t128\t\t\t// purple trail\n\ntypedef struct model_s\n{\n\tchar\t\tname[MAX_QPATH];\n\tbool\tneedload;\t\t// bmodels and sprites don't cache normally\n\n\tmodtype_t\ttype;\n\tint\t\t\tnumframes;\n\tsynctype_t\tsynctype;\n\n\tint\t\t\tflags;\n\n//\n// volume occupied by the model\n//\n\tvec3_t\t\tmins, maxs;\n\tfloat\t\tradius;\n\n//\n// brush model\n//\n\tint\t\t\tfirstmodelsurface, nummodelsurfaces;\n\n\tint\t\t\tnumsubmodels;\n\tdmodel_t\t*submodels;\n\n\tint\t\t\tnumplanes;\n\tmplane_t\t*planes;\n\n\tint\t\t\tnumleafs;\t\t// number of visible leafs, not counting 0\n\tmleaf_t\t\t*leafs;\n\n\tint\t\t\tnumvertexes;\n\tmvertex_t\t*vertexes;\n\n\tint\t\t\tnumedges;\n\tmedge_t\t\t*edges;\n\n\tint\t\t\tnumnodes;\n\tmnode_t\t\t*nodes;\n\n\tint\t\t\tnumtexinfo;\n\tmtexinfo_t\t*texinfo;\n\n\tint\t\t\tnumsurfaces;\n\tmsurface_t\t*surfaces;\n\n\tint\t\t\tnumsurfedges;\n\tint\t\t\t*surfedges;\n\n\tint\t\t\tnumclipnodes;\n\tdclipnode_t\t*clipnodes;\n\n\tint\t\t\tnummarksurfaces;\n\tmsurface_t\t**marksurfaces;\n\n\thull_t\t\thulls[MAX_MAP_HULLS];\n\n\tint\t\t\tnumtextures;\n\ttexture_t\t**textures;\n\n\tbyte\t\t*visdata;\n\tbyte\t\t*lightdata;\n\tsigned char\t\t*entities;\n\n//\n// additional model data\n//\n\tcache_user_t\tcache;\t\t// only access through Mod_Extradata\n\n} model_t;\n\n//============================================================================\n\nvoid\tMod_Init (void);\nvoid\tMod_ClearAll (void);\nmodel_t *Mod_ForName (char *name, bool crash);\nvoid\t*Mod_Extradata (model_t *mod);\t// handles caching\nvoid\tMod_TouchModel (char *name);\n\nmleaf_t *Mod_PointInLeaf (float *p, model_t *model);\nbyte\t*Mod_LeafPVS (mleaf_t *leaf, model_t *model);\n\n#endif\t// __MODEL__\n"
  },
  {
    "path": "source/modelgen.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//\n// modelgen.h: header file for model generation program\n//\n\n// *********************************************************\n// * This file must be identical in the modelgen directory *\n// * and in the Quake directory, because it's used to      *\n// * pass data from one to the other via model files.      *\n// *********************************************************\n\n#ifdef INCLUDELIBS\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <math.h>\n#include <string.h>\n\n#include \"cmdlib.h\"\n#include \"scriplib.h\"\n#include \"trilib.h\"\n#include \"lbmlib.h\"\n#include \"mathlib.h\"\n\n#endif\n\n#define ALIAS_VERSION\t6\n\n#define ALIAS_ONSEAM\t\t\t\t0x0020\n\n// must match definition in spritegn.h\n#ifndef SYNCTYPE_T\n#define SYNCTYPE_T\ntypedef enum {ST_SYNC=0, ST_RAND } synctype_t;\n#endif\n\ntypedef enum { ALIAS_SINGLE=0, ALIAS_GROUP } aliasframetype_t;\n\ntypedef enum { ALIAS_SKIN_SINGLE=0, ALIAS_SKIN_GROUP } aliasskintype_t;\n\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\tvec3_t\t\tscale;\n\tvec3_t\t\tscale_origin;\n\tfloat\t\tboundingradius;\n\tvec3_t\t\teyeposition;\n\tint\t\t\tnumskins;\n\tint\t\t\tskinwidth;\n\tint\t\t\tskinheight;\n\tint\t\t\tnumverts;\n\tint\t\t\tnumtris;\n\tint\t\t\tnumframes;\n\tsynctype_t\tsynctype;\n\tint\t\t\tflags;\n\tfloat\t\tsize;\n} mdl_t;\n\n// TODO: could be shorts\n\ntypedef struct {\n\tint\t\tonseam;\n\tint\t\ts;\n\tint\t\tt;\n} stvert_t;\n\ntypedef struct dtriangle_s {\n\tint\t\t\t\t\tfacesfront;\n\tint\t\t\t\t\tvertindex[3];\n} dtriangle_t;\n\n#define DT_FACES_FRONT\t\t\t\t0x0010\n\n// This mirrors trivert_t in trilib.h, is present so Quake knows how to\n// load this data\n\ntypedef struct {\n\tbyte\tv[3];\n\tbyte\tlightnormalindex;\n} trivertx_t;\n\ntypedef struct {\n\ttrivertx_t\tbboxmin;\t// lightnormal isn't used\n\ttrivertx_t\tbboxmax;\t// lightnormal isn't used\n\tchar\t\tname[16];\t// frame name from grabbing\n} daliasframe_t;\n\ntypedef struct {\n\tint\t\t\tnumframes;\n\ttrivertx_t\tbboxmin;\t// lightnormal isn't used\n\ttrivertx_t\tbboxmax;\t// lightnormal isn't used\n} daliasgroup_t;\n\ntypedef struct {\n\tint\t\t\tnumskins;\n} daliasskingroup_t;\n\ntypedef struct {\n\tfloat\tinterval;\n} daliasinterval_t;\n\ntypedef struct {\n\tfloat\tinterval;\n} daliasskininterval_t;\n\ntypedef struct {\n\tint\ttype;\n} daliasframetype_t;\n\ntypedef struct {\n\tint\ttype;\n} daliasskintype_t;\n\n#define IDPOLYHEADER\t(('O'<<24)+('P'<<16)+('D'<<8)+'I')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// little-endian \"IDPO\"\n"
  },
  {
    "path": "source/mpdosock.h",
    "content": "/* WINSOCK.H--definitions to be used with the WINSOCK.DLL\n * Copyright (c) 1993-1995, Microsoft Corp. All rights reserved.\n *\n * This header file corresponds to version 1.1 of the Windows Sockets specification.\n *\n * This file includes parts which are Copyright (c) 1982-1986 Regents\n * of the University of California.  All rights reserved.  The\n * Berkeley Software License Agreement specifies the terms and\n * conditions for redistribution.\n *\n */\n\n#ifndef _WINSOCKAPI_\n#define _WINSOCKAPI_\n\n#define FAR\n#define PASCAL\n\n/*\n * Basic system type definitions, taken from the BSD file sys/types.h.\n */\ntypedef unsigned char   u_char;\ntypedef unsigned short  u_short;\ntypedef unsigned int    u_int;\ntypedef unsigned long   u_long;\n\n/*\n * The new type to be used in all\n * instances which refer to sockets.\n */\ntypedef u_int           SOCKET;\n\n/*\n * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.\n *\n *\n * Ioctl's have the command encoded in the lower word,\n * and the size of any in or out parameters in the upper\n * word.  The high 2 bits of the upper word are used\n * to encode the in/out status of the parameter; for now\n * we restrict parameters to at most 128 bytes.\n */\n#define IOCPARM_MASK    0x7f            /* parameters must be < 128 bytes */\n#define IOC_VOID        0x20000000      /* no parameters */\n#define IOC_OUT         0x40000000      /* copy out parameters */\n#define IOC_IN          0x80000000      /* copy in parameters */\n#define IOC_INOUT       (IOC_IN|IOC_OUT)\n                                        /* 0x20000000 distinguishes new &\n                                           old ioctl's */\n#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))\n\n#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\n\n#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\n\n#define FIONREAD    _IOR('f', 127, u_long) /* get # bytes to read */\n#define FIONBIO     _IOW('f', 126, u_long) /* set/clear non-blocking i/o */\n#define FIOASYNC    _IOW('f', 125, u_long) /* set/clear async i/o */\n\n/* Socket I/O Controls */\n#define SIOCSHIWAT  _IOW('s',  0, u_long)  /* set high watermark */\n#define SIOCGHIWAT  _IOR('s',  1, u_long)  /* get high watermark */\n#define SIOCSLOWAT  _IOW('s',  2, u_long)  /* set low watermark */\n#define SIOCGLOWAT  _IOR('s',  3, u_long)  /* get low watermark */\n#define SIOCATMARK  _IOR('s',  7, u_long)  /* at oob mark? */\n\n/*\n * Structures returned by network data base library, taken from the\n * BSD file netdb.h.  All addresses are supplied in host order, and\n * returned in network order (suitable for use in system calls).\n */\n\nstruct  hostent {\n        char    FAR * h_name;           /* official name of host */\n        char    FAR * FAR * h_aliases;  /* alias list */\n        short   h_addrtype;             /* host address type */\n        short   h_length;               /* length of address */\n        char    FAR * FAR * h_addr_list; /* list of addresses */\n#define h_addr  h_addr_list[0]          /* address, for backward compat */\n};\n\n/*\n * It is assumed here that a network number\n * fits in 32 bits.\n */\nstruct  netent {\n        char    FAR * n_name;           /* official name of net */\n        char    FAR * FAR * n_aliases;  /* alias list */\n        short   n_addrtype;             /* net address type */\n        u_long  n_net;                  /* network # */\n};\n\nstruct  servent {\n        char    FAR * s_name;           /* official service name */\n        char    FAR * FAR * s_aliases;  /* alias list */\n        short   s_port;                 /* port # */\n        char    FAR * s_proto;          /* protocol to use */\n};\n\nstruct  protoent {\n        char    FAR * p_name;           /* official protocol name */\n        char    FAR * FAR * p_aliases;  /* alias list */\n        short   p_proto;                /* protocol # */\n};\n\n/*\n * Constants and structures defined by the internet system,\n * Per RFC 790, September 1981, taken from the BSD file netinet/in.h.\n */\n\n/*\n * Protocols\n */\n#define IPPROTO_IP              0               /* dummy for IP */\n#define IPPROTO_ICMP            1               /* control message protocol */\n#define IPPROTO_GGP             2               /* gateway^2 (deprecated) */\n#define IPPROTO_TCP             6               /* tcp */\n#define IPPROTO_PUP             12              /* pup */\n#define IPPROTO_UDP             17              /* user datagram protocol */\n#define IPPROTO_IDP             22              /* xns idp */\n#define IPPROTO_ND              77              /* UNOFFICIAL net disk proto */\n\n#define IPPROTO_RAW             255             /* raw IP packet */\n#define IPPROTO_MAX             256\n\n/*\n * Port/socket numbers: network standard functions\n */\n#define IPPORT_ECHO             7\n#define IPPORT_DISCARD          9\n#define IPPORT_SYSTAT           11\n#define IPPORT_DAYTIME          13\n#define IPPORT_NETSTAT          15\n#define IPPORT_FTP              21\n#define IPPORT_TELNET           23\n#define IPPORT_SMTP             25\n#define IPPORT_TIMESERVER       37\n#define IPPORT_NAMESERVER       42\n#define IPPORT_WHOIS            43\n#define IPPORT_MTP              57\n\n/*\n * Port/socket numbers: host specific functions\n */\n#define IPPORT_TFTP             69\n#define IPPORT_RJE              77\n#define IPPORT_FINGER           79\n#define IPPORT_TTYLINK          87\n#define IPPORT_SUPDUP           95\n\n/*\n * UNIX TCP sockets\n */\n#define IPPORT_EXECSERVER       512\n#define IPPORT_LOGINSERVER      513\n#define IPPORT_CMDSERVER        514\n#define IPPORT_EFSSERVER        520\n\n/*\n * UNIX UDP sockets\n */\n#define IPPORT_BIFFUDP          512\n#define IPPORT_WHOSERVER        513\n#define IPPORT_ROUTESERVER      520\n                                        /* 520+1 also used */\n\n/*\n * Ports < IPPORT_RESERVED are reserved for\n * privileged processes (e.g. root).\n */\n#define IPPORT_RESERVED         1024\n\n/*\n * Link numbers\n */\n#define IMPLINK_IP              155\n#define IMPLINK_LOWEXPER        156\n#define IMPLINK_HIGHEXPER       158\n\n/*\n * Internet address (old style... should be updated)\n */\nstruct in_addr {\n        union {\n                struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;\n                struct { u_short s_w1,s_w2; } S_un_w;\n                u_long S_addr;\n        } S_un;\n#define s_addr  S_un.S_addr\n                                /* can be used for most tcp & ip code */\n#define s_host  S_un.S_un_b.s_b2\n                                /* host on imp */\n#define s_net   S_un.S_un_b.s_b1\n                                /* network */\n#define s_imp   S_un.S_un_w.s_w2\n                                /* imp */\n#define s_impno S_un.S_un_b.s_b4\n                                /* imp # */\n#define s_lh    S_un.S_un_b.s_b3\n                                /* logical host */\n};\n\n/*\n * Definitions of bits in internet address integers.\n * On subnets, the decomposition of addresses to host and net parts\n * is done according to subnet mask, not the masks here.\n */\n#define IN_CLASSA(i)            (((long)(i) & 0x80000000) == 0)\n#define IN_CLASSA_NET           0xff000000\n#define IN_CLASSA_NSHIFT        24\n#define IN_CLASSA_HOST          0x00ffffff\n#define IN_CLASSA_MAX           128\n\n#define IN_CLASSB(i)            (((long)(i) & 0xc0000000) == 0x80000000)\n#define IN_CLASSB_NET           0xffff0000\n#define IN_CLASSB_NSHIFT        16\n#define IN_CLASSB_HOST          0x0000ffff\n#define IN_CLASSB_MAX           65536\n\n#define IN_CLASSC(i)            (((long)(i) & 0xe0000000) == 0xc0000000)\n#define IN_CLASSC_NET           0xffffff00\n#define IN_CLASSC_NSHIFT        8\n#define IN_CLASSC_HOST          0x000000ff\n\n#define INADDR_ANY              (u_long)0x00000000\n#define INADDR_LOOPBACK         0x7f000001\n#define INADDR_BROADCAST        (u_long)0xffffffff\n#define INADDR_NONE             0xffffffff\n\n/*\n * Socket address, internet style.\n */\nstruct sockaddr_in {\n        short   sin_family;\n        u_short sin_port;\n        struct  in_addr sin_addr;\n        char    sin_zero[8];\n};\n\n#define WSADESCRIPTION_LEN      256\n#define WSASYS_STATUS_LEN       128\n\n\n/*\n * Options for use with [gs]etsockopt at the IP level.\n */\n#define IP_OPTIONS          1           /* set/get IP per-packet options    */\n#define IP_MULTICAST_IF     2           /* set/get IP multicast interface   */\n#define IP_MULTICAST_TTL    3           /* set/get IP multicast timetolive  */\n#define IP_MULTICAST_LOOP   4           /* set/get IP multicast loopback    */\n#define IP_ADD_MEMBERSHIP   5           /* add  an IP group membership      */\n#define IP_DROP_MEMBERSHIP  6           /* drop an IP group membership      */\n\n#define IP_DEFAULT_MULTICAST_TTL   1    /* normally limit m'casts to 1 hop  */\n#define IP_DEFAULT_MULTICAST_LOOP  1    /* normally hear sends if a member  */\n#define IP_MAX_MEMBERSHIPS         20   /* per socket; must fit in one mbuf */\n\n/*\n * Argument structure for IP_ADD_MEMBERSHIP and IP_DROP_MEMBERSHIP.\n */\nstruct ip_mreq {\n        struct in_addr  imr_multiaddr;  /* IP multicast address of group */\n        struct in_addr  imr_interface;  /* local IP address of interface */\n};\n\n/*\n * Definitions related to sockets: types, address families, options,\n * taken from the BSD file sys/socket.h.\n */\n\n/*\n * This is used instead of -1, since the\n * SOCKET type is unsigned.\n */\n#define INVALID_SOCKET  (SOCKET)(~0)\n#define SOCKET_ERROR            (-1)\n\n/*\n * Types\n */\n#define SOCK_STREAM     1               /* stream socket */\n#define SOCK_DGRAM      2               /* datagram socket */\n#define SOCK_RAW        3               /* raw-protocol interface */\n#define SOCK_RDM        4               /* reliably-delivered message */\n#define SOCK_SEQPACKET  5               /* sequenced packet stream */\n\n/*\n * Option flags per-socket.\n */\n#define SO_DEBUG        0x0001          /* turn on debugging info recording */\n#define SO_ACCEPTCONN   0x0002          /* socket has had listen() */\n#define SO_REUSEADDR    0x0004          /* allow local address reuse */\n#define SO_KEEPALIVE    0x0008          /* keep connections alive */\n#define SO_DONTROUTE    0x0010          /* just use interface addresses */\n#define SO_BROADCAST    0x0020          /* permit sending of broadcast msgs */\n#define SO_USELOOPBACK  0x0040          /* bypass hardware when possible */\n#define SO_LINGER       0x0080          /* linger on close if data present */\n#define SO_OOBINLINE    0x0100          /* leave received OOB data in line */\n\n#define SO_DONTLINGER   (u_int)(~SO_LINGER)\n\n/*\n * Additional options.\n */\n#define SO_SNDBUF       0x1001          /* send buffer size */\n#define SO_RCVBUF       0x1002          /* receive buffer size */\n#define SO_SNDLOWAT     0x1003          /* send low-water mark */\n#define SO_RCVLOWAT     0x1004          /* receive low-water mark */\n#define SO_SNDTIMEO     0x1005          /* send timeout */\n#define SO_RCVTIMEO     0x1006          /* receive timeout */\n#define SO_ERROR        0x1007          /* get error status and clear */\n#define SO_TYPE         0x1008          /* get socket type */\n\n/*\n * Options for connect and disconnect data and options.  Used only by\n * non-TCP/IP transports such as DECNet, OSI TP4, etc.\n */\n#define SO_CONNDATA     0x7000\n#define SO_CONNOPT      0x7001\n#define SO_DISCDATA     0x7002\n#define SO_DISCOPT      0x7003\n#define SO_CONNDATALEN  0x7004\n#define SO_CONNOPTLEN   0x7005\n#define SO_DISCDATALEN  0x7006\n#define SO_DISCOPTLEN   0x7007\n\n/*\n * Option for opening sockets for synchronous access.\n */\n#define SO_OPENTYPE     0x7008\n\n#define SO_SYNCHRONOUS_ALERT    0x10\n#define SO_SYNCHRONOUS_NONALERT 0x20\n\n/*\n * Other NT-specific options.\n */\n#define SO_MAXDG        0x7009\n#define SO_MAXPATHDG    0x700A\n\n/*\n * TCP options.\n */\n#define TCP_NODELAY     0x0001\n#define TCP_BSDURGENT   0x7000\n\n/*\n * Address families.\n */\n#define AF_UNSPEC       0               /* unspecified */\n#define AF_UNIX         1               /* local to host (pipes, portals) */\n#define AF_INET         2               /* internetwork: UDP, TCP, etc. */\n#define AF_IMPLINK      3               /* arpanet imp addresses */\n#define AF_PUP          4               /* pup protocols: e.g. BSP */\n#define AF_CHAOS        5               /* mit CHAOS protocols */\n#define AF_IPX          6               /* IPX and SPX */\n#define AF_NS           6               /* XEROX NS protocols */\n#define AF_ISO          7               /* ISO protocols */\n#define AF_OSI          AF_ISO          /* OSI is ISO */\n#define AF_ECMA         8               /* european computer manufacturers */\n#define AF_DATAKIT      9               /* datakit protocols */\n#define AF_CCITT        10              /* CCITT protocols, X.25 etc */\n#define AF_SNA          11              /* IBM SNA */\n#define AF_DECnet       12              /* DECnet */\n#define AF_DLI          13              /* Direct data link interface */\n#define AF_LAT          14              /* LAT */\n#define AF_HYLINK       15              /* NSC Hyperchannel */\n#define AF_APPLETALK    16              /* AppleTalk */\n#define AF_NETBIOS      17              /* NetBios-style addresses */\n#define AF_VOICEVIEW    18              /* VoiceView */\n\n#define AF_MAX          19\n\n/*\n * Structure used by kernel to store most\n * addresses.\n */\nstruct sockaddr {\n        u_short sa_family;              /* address family */\n        char    sa_data[14];            /* up to 14 bytes of direct address */\n};\n\n/*\n * Structure used by kernel to pass protocol\n * information in raw sockets.\n */\nstruct sockproto {\n        u_short sp_family;              /* address family */\n        u_short sp_protocol;            /* protocol */\n};\n\n/*\n * Protocol families, same as address families for now.\n */\n#define PF_UNSPEC       AF_UNSPEC\n#define PF_UNIX         AF_UNIX\n#define PF_INET         AF_INET\n#define PF_IMPLINK      AF_IMPLINK\n#define PF_PUP          AF_PUP\n#define PF_CHAOS        AF_CHAOS\n#define PF_NS           AF_NS\n#define PF_IPX          AF_IPX\n#define PF_ISO          AF_ISO\n#define PF_OSI          AF_OSI\n#define PF_ECMA         AF_ECMA\n#define PF_DATAKIT      AF_DATAKIT\n#define PF_CCITT        AF_CCITT\n#define PF_SNA          AF_SNA\n#define PF_DECnet       AF_DECnet\n#define PF_DLI          AF_DLI\n#define PF_LAT          AF_LAT\n#define PF_HYLINK       AF_HYLINK\n#define PF_APPLETALK    AF_APPLETALK\n#define PF_VOICEVIEW    AF_VOICEVIEW\n\n#define PF_MAX          AF_MAX\n\n/*\n * Structure used for manipulating linger option.\n */\nstruct  linger {\n        u_short l_onoff;                /* option on/off */\n        u_short l_linger;               /* linger time */\n};\n\n/*\n * Level number for (get/set)sockopt() to apply to socket itself.\n */\n#define SOL_SOCKET      0xffff          /* options for socket level */\n\n/*\n * Maximum queue length specifiable by listen.\n */\n#define SOMAXCONN       5\n\n#define MSG_OOB         0x1             /* process out-of-band data */\n#define MSG_PEEK        0x2             /* peek at incoming message */\n#define MSG_DONTROUTE   0x4             /* send without using routing tables */\n\n#define MSG_MAXIOVLEN   16\n\n#define MSG_PARTIAL     0x8000          /* partial send or recv for message xport */\n\n/*\n * Define constant based on rfc883, used by gethostbyxxxx() calls.\n */\n#define MAXGETHOSTSTRUCT        1024\n\n/*\n * Define flags to be used with the WSAAsyncSelect() call.\n */\n#define FD_READ         0x01\n#define FD_WRITE        0x02\n#define FD_OOB          0x04\n#define FD_ACCEPT       0x08\n#define FD_CONNECT      0x10\n#define FD_CLOSE        0x20\n\n/*\n * All Windows Sockets error constants are biased by WSABASEERR from\n * the \"normal\"\n */\n#define WSABASEERR              10000\n/*\n * Windows Sockets definitions of regular Microsoft C error constants\n */\n#define WSAEINTR                (WSABASEERR+4)\n#define WSAEBADF                (WSABASEERR+9)\n#define WSAEACCES               (WSABASEERR+13)\n#define WSAEFAULT               (WSABASEERR+14)\n#define WSAEINVAL               (WSABASEERR+22)\n#define WSAEMFILE               (WSABASEERR+24)\n\n/*\n * Windows Sockets definitions of regular Berkeley error constants\n */\n#define WSAEWOULDBLOCK          (WSABASEERR+35)\n#define WSAEINPROGRESS          (WSABASEERR+36)\n#define WSAEALREADY             (WSABASEERR+37)\n#define WSAENOTSOCK             (WSABASEERR+38)\n#define WSAEDESTADDRREQ         (WSABASEERR+39)\n#define WSAEMSGSIZE             (WSABASEERR+40)\n#define WSAEPROTOTYPE           (WSABASEERR+41)\n#define WSAENOPROTOOPT          (WSABASEERR+42)\n#define WSAEPROTONOSUPPORT      (WSABASEERR+43)\n#define WSAESOCKTNOSUPPORT      (WSABASEERR+44)\n#define WSAEOPNOTSUPP           (WSABASEERR+45)\n#define WSAEPFNOSUPPORT         (WSABASEERR+46)\n#define WSAEAFNOSUPPORT         (WSABASEERR+47)\n#define WSAEADDRINUSE           (WSABASEERR+48)\n#define WSAEADDRNOTAVAIL        (WSABASEERR+49)\n#define WSAENETDOWN             (WSABASEERR+50)\n#define WSAENETUNREACH          (WSABASEERR+51)\n#define WSAENETRESET            (WSABASEERR+52)\n#define WSAECONNABORTED         (WSABASEERR+53)\n#define WSAECONNRESET           (WSABASEERR+54)\n#define WSAENOBUFS              (WSABASEERR+55)\n#define WSAEISCONN              (WSABASEERR+56)\n#define WSAENOTCONN             (WSABASEERR+57)\n#define WSAESHUTDOWN            (WSABASEERR+58)\n#define WSAETOOMANYREFS         (WSABASEERR+59)\n#define WSAETIMEDOUT            (WSABASEERR+60)\n#define WSAECONNREFUSED         (WSABASEERR+61)\n#define WSAELOOP                (WSABASEERR+62)\n#define WSAENAMETOOLONG         (WSABASEERR+63)\n#define WSAEHOSTDOWN            (WSABASEERR+64)\n#define WSAEHOSTUNREACH         (WSABASEERR+65)\n#define WSAENOTEMPTY            (WSABASEERR+66)\n#define WSAEPROCLIM             (WSABASEERR+67)\n#define WSAEUSERS               (WSABASEERR+68)\n#define WSAEDQUOT               (WSABASEERR+69)\n#define WSAESTALE               (WSABASEERR+70)\n#define WSAEREMOTE              (WSABASEERR+71)\n\n#define WSAEDISCON              (WSABASEERR+101)\n\n/*\n * Extended Windows Sockets error constant definitions\n */\n#define WSASYSNOTREADY          (WSABASEERR+91)\n#define WSAVERNOTSUPPORTED      (WSABASEERR+92)\n#define WSANOTINITIALISED       (WSABASEERR+93)\n\n/*\n * Error return codes from gethostbyname() and gethostbyaddr()\n * (when using the resolver). Note that these errors are\n * retrieved via WSAGetLastError() and must therefore follow\n * the rules for avoiding clashes with error numbers from\n * specific implementations or language run-time systems.\n * For this reason the codes are based at WSABASEERR+1001.\n * Note also that [WSA]NO_ADDRESS is defined only for\n * compatibility purposes.\n */\n\n#define h_errno         WSAGetLastError()\n\n/* Authoritative Answer: Host not found */\n#define WSAHOST_NOT_FOUND       (WSABASEERR+1001)\n#define HOST_NOT_FOUND          WSAHOST_NOT_FOUND\n\n/* Non-Authoritative: Host not found, or SERVERFAIL */\n#define WSATRY_AGAIN            (WSABASEERR+1002)\n#define TRY_AGAIN               WSATRY_AGAIN\n\n/* Non recoverable errors, FORMERR, REFUSED, NOTIMP */\n#define WSANO_RECOVERY          (WSABASEERR+1003)\n#define NO_RECOVERY             WSANO_RECOVERY\n\n/* Valid name, no data record of requested type */\n#define WSANO_DATA              (WSABASEERR+1004)\n#define NO_DATA                 WSANO_DATA\n\n/* no address, look for MX record */\n#define WSANO_ADDRESS           WSANO_DATA\n#define NO_ADDRESS              WSANO_ADDRESS\n\n/* Socket function prototypes */\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\nSOCKET PASCAL FAR accept (SOCKET s, struct sockaddr FAR *addr,\n                          int FAR *addrlen);\n\nint PASCAL FAR bind (SOCKET s, const struct sockaddr FAR *addr, int namelen);\n\nint PASCAL FAR closesocket (SOCKET s);\n\nint PASCAL FAR connect (SOCKET s, const struct sockaddr FAR *name, int namelen);\n\nint PASCAL FAR ioctlsocket (SOCKET s, long cmd, u_long FAR *argp);\n\nint PASCAL FAR getpeername (SOCKET s, struct sockaddr FAR *name,\n                            int FAR * namelen);\n\nint PASCAL FAR getsockname (SOCKET s, struct sockaddr FAR *name,\n                            int FAR * namelen);\n\nint PASCAL FAR getsockopt (SOCKET s, int level, int optname,\n                           char FAR * optval, int FAR *optlen);\n\nu_long PASCAL FAR htonl (u_long hostlong);\n\nu_short PASCAL FAR htons (u_short hostshort);\n\nunsigned long PASCAL FAR inet_addr (const char FAR * cp);\n\nchar FAR * PASCAL FAR inet_ntoa (struct in_addr in);\n\nint PASCAL FAR listen (SOCKET s, int backlog);\n\nu_long PASCAL FAR ntohl (u_long netlong);\n\nu_short PASCAL FAR ntohs (u_short netshort);\n\nint PASCAL FAR recv (SOCKET s, char FAR * buf, int len, int flags);\n\nint PASCAL FAR recvfrom (SOCKET s, char FAR * buf, int len, int flags,\n                         struct sockaddr FAR *from, int FAR * fromlen);\n\n\nint PASCAL FAR send (SOCKET s, const char FAR * buf, int len, int flags);\n\nint PASCAL FAR sendto (SOCKET s, const char FAR * buf, int len, int flags,\n                       const struct sockaddr FAR *to, int tolen);\n\nint PASCAL FAR setsockopt (SOCKET s, int level, int optname,\n                           const char FAR * optval, int optlen);\n\nint PASCAL FAR shutdown (SOCKET s, int how);\n\nSOCKET PASCAL FAR socket (int af, int type, int protocol);\n\n/* Database function prototypes */\n\nstruct hostent FAR * PASCAL FAR gethostbyaddr(const char FAR * addr,\n                                              int len, int type);\n\nstruct hostent FAR * PASCAL FAR gethostbyname(const char FAR * name);\n\nint PASCAL FAR gethostname (char FAR * name, int namelen);\n\nstruct servent FAR * PASCAL FAR getservbyport(int port, const char FAR * proto);\n\nstruct servent FAR * PASCAL FAR getservbyname(const char FAR * name,\n                                              const char FAR * proto);\n\nstruct protoent FAR * PASCAL FAR getprotobynumber(int proto);\n\nstruct protoent FAR * PASCAL FAR getprotobyname(const char FAR * name);\n\n#ifdef __cplusplus\n}\n#endif\n\n/* Microsoft Windows Extended data types */\ntypedef struct sockaddr SOCKADDR;\ntypedef struct sockaddr *PSOCKADDR;\ntypedef struct sockaddr FAR *LPSOCKADDR;\n\ntypedef struct sockaddr_in SOCKADDR_IN;\ntypedef struct sockaddr_in *PSOCKADDR_IN;\ntypedef struct sockaddr_in FAR *LPSOCKADDR_IN;\n\ntypedef struct linger LINGER;\ntypedef struct linger *PLINGER;\ntypedef struct linger FAR *LPLINGER;\n\ntypedef struct in_addr IN_ADDR;\ntypedef struct in_addr *PIN_ADDR;\ntypedef struct in_addr FAR *LPIN_ADDR;\n\ntypedef struct fd_set FD_SET;\ntypedef struct fd_set *PFD_SET;\ntypedef struct fd_set FAR *LPFD_SET;\n\ntypedef struct hostent HOSTENT;\ntypedef struct hostent *PHOSTENT;\ntypedef struct hostent FAR *LPHOSTENT;\n\ntypedef struct servent SERVENT;\ntypedef struct servent *PSERVENT;\ntypedef struct servent FAR *LPSERVENT;\n\ntypedef struct protoent PROTOENT;\ntypedef struct protoent *PPROTOENT;\ntypedef struct protoent FAR *LPPROTOENT;\n\ntypedef struct timeval TIMEVAL;\ntypedef struct timeval *PTIMEVAL;\ntypedef struct timeval FAR *LPTIMEVAL;\n\n#endif  /* _WINSOCKAPI_ */\n"
  },
  {
    "path": "source/neon_mathfun.c",
    "content": "/* NEON implementation of sin, cos, exp and log\n\n   Inspired by Intel Approximate Math library, and based on the\n   corresponding algorithms of the cephes math library\n*/\n\n/* Copyright (C) 2011  Julien Pommier\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  (this is the zlib license)\n*/\n\n#include \"neon_mathfun.h\"\n\n#define c_inv_mant_mask ~0x7f800000u\n#define c_cephes_SQRTHF 0.707106781186547524\n#define c_cephes_log_p0 7.0376836292E-2\n#define c_cephes_log_p1 - 1.1514610310E-1\n#define c_cephes_log_p2 1.1676998740E-1\n#define c_cephes_log_p3 - 1.2420140846E-1\n#define c_cephes_log_p4 + 1.4249322787E-1\n#define c_cephes_log_p5 - 1.6668057665E-1\n#define c_cephes_log_p6 + 2.0000714765E-1\n#define c_cephes_log_p7 - 2.4999993993E-1\n#define c_cephes_log_p8 + 3.3333331174E-1\n#define c_cephes_log_q1 -2.12194440e-4\n#define c_cephes_log_q2 0.693359375\n\n/* natural logarithm computed for 4 simultaneous float \n   return NaN for x <= 0\n*/\nv4sf log_ps(v4sf x) {\n  v4sf one = vdupq_n_f32(1);\n\n  x = vmaxq_f32(x, vdupq_n_f32(0)); /* force flush to zero on denormal values */\n  v4su invalid_mask = vcleq_f32(x, vdupq_n_f32(0));\n\n  v4si ux = vreinterpretq_s32_f32(x);\n  \n  v4si emm0 = vshrq_n_s32(ux, 23);\n\n  /* keep only the fractional part */\n  ux = vandq_s32(ux, vdupq_n_s32(c_inv_mant_mask));\n  ux = vorrq_s32(ux, vreinterpretq_s32_f32(vdupq_n_f32(0.5f)));\n  x = vreinterpretq_f32_s32(ux);\n\n  emm0 = vsubq_s32(emm0, vdupq_n_s32(0x7f));\n  v4sf e = vcvtq_f32_s32(emm0);\n\n  e = vaddq_f32(e, one);\n\n  /* part2: \n     if( x < SQRTHF ) {\n       e -= 1;\n       x = x + x - 1.0;\n     } else { x = x - 1.0; }\n  */\n  v4su mask = vcltq_f32(x, vdupq_n_f32(c_cephes_SQRTHF));\n  v4sf tmp = vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(x), mask));\n  x = vsubq_f32(x, one);\n  e = vsubq_f32(e, vreinterpretq_f32_u32(vandq_u32(vreinterpretq_u32_f32(one), mask)));\n  x = vaddq_f32(x, tmp);\n\n  v4sf z = vmulq_f32(x,x);\n\n  v4sf y = vdupq_n_f32(c_cephes_log_p0);\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p1));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p2));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p3));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p4));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p5));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p6));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p7));\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, vdupq_n_f32(c_cephes_log_p8));\n  y = vmulq_f32(y, x);\n\n  y = vmulq_f32(y, z);\n  \n\n  tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q1));\n  y = vaddq_f32(y, tmp);\n\n\n  tmp = vmulq_f32(z, vdupq_n_f32(0.5f));\n  y = vsubq_f32(y, tmp);\n\n  tmp = vmulq_f32(e, vdupq_n_f32(c_cephes_log_q2));\n  x = vaddq_f32(x, y);\n  x = vaddq_f32(x, tmp);\n  x = vreinterpretq_f32_u32(vorrq_u32(vreinterpretq_u32_f32(x), invalid_mask)); // negative arg will be NAN\n  return x;\n}\n\n#define c_exp_hi 88.3762626647949f\n#define c_exp_lo -88.3762626647949f\n\n#define c_cephes_LOG2EF 1.44269504088896341\n#define c_cephes_exp_C1 0.693359375\n#define c_cephes_exp_C2 -2.12194440e-4\n\n#define c_cephes_exp_p0 1.9875691500E-4\n#define c_cephes_exp_p1 1.3981999507E-3\n#define c_cephes_exp_p2 8.3334519073E-3\n#define c_cephes_exp_p3 4.1665795894E-2\n#define c_cephes_exp_p4 1.6666665459E-1\n#define c_cephes_exp_p5 5.0000001201E-1\n\n/* exp() computed for 4 float at once */\nv4sf exp_ps(v4sf x) {\n  v4sf tmp, fx;\n\n  v4sf one = vdupq_n_f32(1);\n  x = vminq_f32(x, vdupq_n_f32(c_exp_hi));\n  x = vmaxq_f32(x, vdupq_n_f32(c_exp_lo));\n\n  /* express exp(x) as exp(g + n*log(2)) */\n  fx = vmlaq_f32(vdupq_n_f32(0.5f), x, vdupq_n_f32(c_cephes_LOG2EF));\n\n  /* perform a floorf */\n  tmp = vcvtq_f32_s32(vcvtq_s32_f32(fx));\n\n  /* if greater, substract 1 */\n  v4su mask = vcgtq_f32(tmp, fx);    \n  mask = vandq_u32(mask, vreinterpretq_u32_f32(one));\n\n\n  fx = vsubq_f32(tmp, vreinterpretq_f32_u32(mask));\n\n  tmp = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C1));\n  v4sf z = vmulq_f32(fx, vdupq_n_f32(c_cephes_exp_C2));\n  x = vsubq_f32(x, tmp);\n  x = vsubq_f32(x, z);\n\n  static const float cephes_exp_p[6] = { c_cephes_exp_p0, c_cephes_exp_p1, c_cephes_exp_p2, c_cephes_exp_p3, c_cephes_exp_p4, c_cephes_exp_p5 };\n  v4sf y = vld1q_dup_f32(cephes_exp_p+0);\n  v4sf c1 = vld1q_dup_f32(cephes_exp_p+1); \n  v4sf c2 = vld1q_dup_f32(cephes_exp_p+2); \n  v4sf c3 = vld1q_dup_f32(cephes_exp_p+3); \n  v4sf c4 = vld1q_dup_f32(cephes_exp_p+4); \n  v4sf c5 = vld1q_dup_f32(cephes_exp_p+5);\n\n  y = vmulq_f32(y, x);\n  z = vmulq_f32(x,x);\n  y = vaddq_f32(y, c1);\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, c2);\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, c3);\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, c4);\n  y = vmulq_f32(y, x);\n  y = vaddq_f32(y, c5);\n  \n  y = vmulq_f32(y, z);\n  y = vaddq_f32(y, x);\n  y = vaddq_f32(y, one);\n\n  /* build 2^n */\n  int32x4_t mm;\n  mm = vcvtq_s32_f32(fx);\n  mm = vaddq_s32(mm, vdupq_n_s32(0x7f));\n  mm = vshlq_n_s32(mm, 23);\n  v4sf pow2n = vreinterpretq_f32_s32(mm);\n\n  y = vmulq_f32(y, pow2n);\n  return y;\n}\n\n#define c_minus_cephes_DP1 -0.78515625\n#define c_minus_cephes_DP2 -2.4187564849853515625e-4\n#define c_minus_cephes_DP3 -3.77489497744594108e-8\n#define c_sincof_p0 -1.9515295891E-4\n#define c_sincof_p1  8.3321608736E-3\n#define c_sincof_p2 -1.6666654611E-1\n#define c_coscof_p0  2.443315711809948E-005\n#define c_coscof_p1 -1.388731625493765E-003\n#define c_coscof_p2  4.166664568298827E-002\n#define c_cephes_FOPI 1.27323954473516 // 4 / M_PI\n\n/* evaluation of 4 sines & cosines at once.\n\n   The code is the exact rewriting of the cephes sinf function.\n   Precision is excellent as long as x < 8192 (I did not bother to\n   take into account the special handling they have for greater values\n   -- it does not return garbage for arguments over 8192, though, but\n   the extra precision is missing).\n\n   Note that it is such that sinf((float)M_PI) = 8.74e-8, which is the\n   surprising but correct result.\n\n   Note also that when you compute sin(x), cos(x) is available at\n   almost no extra price so both sin_ps and cos_ps make use of\n   sincos_ps..\n  */\nvoid sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos) { // any x\n  v4sf xmm1, xmm2, xmm3, y;\n\n  v4su emm2;\n  \n  v4su sign_mask_sin, sign_mask_cos;\n  sign_mask_sin = vcltq_f32(x, vdupq_n_f32(0));\n  x = vabsq_f32(x);\n\n  /* scale by 4/Pi */\n  y = vmulq_f32(x, vdupq_n_f32(c_cephes_FOPI));\n\n  /* store the integer part of y in mm0 */\n  emm2 = vcvtq_u32_f32(y);\n  /* j=(j+1) & (~1) (see the cephes sources) */\n  emm2 = vaddq_u32(emm2, vdupq_n_u32(1));\n  emm2 = vandq_u32(emm2, vdupq_n_u32(~1));\n  y = vcvtq_f32_u32(emm2);\n\n  /* get the polynom selection mask \n     there is one polynom for 0 <= x <= Pi/4\n     and another one for Pi/4<x<=Pi/2\n\n     Both branches will be computed.\n  */\n  v4su poly_mask = vtstq_u32(emm2, vdupq_n_u32(2));\n  \n  /* The magic pass: \"Extended precision modular arithmetic\" \n     x = ((x - y * DP1) - y * DP2) - y * DP3; */\n  xmm1 = vmulq_n_f32(y, c_minus_cephes_DP1);\n  xmm2 = vmulq_n_f32(y, c_minus_cephes_DP2);\n  xmm3 = vmulq_n_f32(y, c_minus_cephes_DP3);\n  x = vaddq_f32(x, xmm1);\n  x = vaddq_f32(x, xmm2);\n  x = vaddq_f32(x, xmm3);\n\n  sign_mask_sin = veorq_u32(sign_mask_sin, vtstq_u32(emm2, vdupq_n_u32(4)));\n  sign_mask_cos = vtstq_u32(vsubq_u32(emm2, vdupq_n_u32(2)), vdupq_n_u32(4));\n\n  /* Evaluate the first polynom  (0 <= x <= Pi/4) in y1, \n     and the second polynom      (Pi/4 <= x <= 0) in y2 */\n  v4sf z = vmulq_f32(x,x);\n  v4sf y1, y2;\n\n  y1 = vmulq_n_f32(z, c_coscof_p0);\n  y2 = vmulq_n_f32(z, c_sincof_p0);\n  y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p1));\n  y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p1));\n  y1 = vmulq_f32(y1, z);\n  y2 = vmulq_f32(y2, z);\n  y1 = vaddq_f32(y1, vdupq_n_f32(c_coscof_p2));\n  y2 = vaddq_f32(y2, vdupq_n_f32(c_sincof_p2));\n  y1 = vmulq_f32(y1, z);\n  y2 = vmulq_f32(y2, z);\n  y1 = vmulq_f32(y1, z);\n  y2 = vmulq_f32(y2, x);\n  y1 = vsubq_f32(y1, vmulq_f32(z, vdupq_n_f32(0.5f)));\n  y2 = vaddq_f32(y2, x);\n  y1 = vaddq_f32(y1, vdupq_n_f32(1));\n\n  /* select the correct result from the two polynoms */  \n  v4sf ys = vbslq_f32(poly_mask, y1, y2);\n  v4sf yc = vbslq_f32(poly_mask, y2, y1);\n  *ysin = vbslq_f32(sign_mask_sin, vnegq_f32(ys), ys);\n  *ycos = vbslq_f32(sign_mask_cos, yc, vnegq_f32(yc));\n}\n\nv4sf sin_ps(v4sf x) {\n  v4sf ysin, ycos; \n  sincos_ps(x, &ysin, &ycos); \n  return ysin;\n}\n\nv4sf cos_ps(v4sf x) {\n  v4sf ysin, ycos; \n  sincos_ps(x, &ysin, &ycos); \n  return ycos;\n}"
  },
  {
    "path": "source/neon_mathfun.h",
    "content": "#ifndef _NEON_MATHFUN_H_\n#define _NEON_MATHFUN_H_\n\n#include <arm_neon.h>\n\ntypedef float32x4_t v4sf;  // vector of 4 float\ntypedef uint32x4_t v4su;  // vector of 4 uint32\ntypedef int32x4_t v4si;  // vector of 4 uint32\n\nv4sf log_ps(v4sf x);\nv4sf exp_ps(v4sf x);\nvoid sincos_ps(v4sf x, v4sf *ysin, v4sf *ycos);\nv4sf sin_ps(v4sf x);\nv4sf cos_ps(v4sf x);\n\n#endif\n"
  },
  {
    "path": "source/net.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net.h -- quake's interface to the networking layer\n\nstruct qsockaddr\n{\n\tshort sa_family;\n\tunsigned char sa_data[14];\n};\n\n\n#define\tNET_NAMELEN\t\t\t64\n\n#define NET_MAXMESSAGE\t\t8192\n#define NET_HEADERSIZE\t\t(2 * sizeof(unsigned int))\n#define NET_DATAGRAMSIZE\t(MAX_DATAGRAM + NET_HEADERSIZE)\n\n// NetHeader flags\n#define NETFLAG_LENGTH_MASK\t0x0000ffff\n#define NETFLAG_DATA\t\t0x00010000\n#define NETFLAG_ACK\t\t\t0x00020000\n#define NETFLAG_NAK\t\t\t0x00040000\n#define NETFLAG_EOM\t\t\t0x00080000\n#define NETFLAG_UNRELIABLE\t0x00100000\n#define NETFLAG_CTL\t\t\t0x80000000\n\n\n#define NET_PROTOCOL_VERSION\t3\n\n// This is the network info/connection protocol.  It is used to find Quake\n// servers, get info about them, and connect to them.  Once connected, the\n// Quake game protocol (documented elsewhere) is used.\n//\n//\n// General notes:\n//\tgame_name is currently always \"QUAKE\", but is there so this same protocol\n//\t\tcan be used for future games as well; can you say Quake2?\n//\n// CCREQ_CONNECT\n//\t\tstring\tgame_name\t\t\t\t\"QUAKE\"\n//\t\tbyte\tnet_protocol_version\tNET_PROTOCOL_VERSION\n//\n// CCREQ_SERVER_INFO\n//\t\tstring\tgame_name\t\t\t\t\"QUAKE\"\n//\t\tbyte\tnet_protocol_version\tNET_PROTOCOL_VERSION\n//\n// CCREQ_PLAYER_INFO\n//\t\tbyte\tplayer_number\n//\n// CCREQ_RULE_INFO\n//\t\tstring\trule\n//\n//\n//\n// CCREP_ACCEPT\n//\t\tlong\tport\n//\n// CCREP_REJECT\n//\t\tstring\treason\n//\n// CCREP_SERVER_INFO\n//\t\tstring\tserver_address\n//\t\tstring\thost_name\n//\t\tstring\tlevel_name\n//\t\tbyte\tcurrent_players\n//\t\tbyte\tmax_players\n//\t\tbyte\tprotocol_version\tNET_PROTOCOL_VERSION\n//\n// CCREP_PLAYER_INFO\n//\t\tbyte\tplayer_number\n//\t\tstring\tname\n//\t\tlong\tcolors\n//\t\tlong\tfrags\n//\t\tlong\tconnect_time\n//\t\tstring\taddress\n//\n// CCREP_RULE_INFO\n//\t\tstring\trule\n//\t\tstring\tvalue\n\n//\tnote:\n//\t\tThere are two address forms used above.  The short form is just a\n//\t\tport number.  The address that goes along with the port is defined as\n//\t\t\"whatever address you receive this reponse from\".  This lets us use\n//\t\tthe host OS to solve the problem of multiple host addresses (possibly\n//\t\twith no routing between them); the host will use the right address\n//\t\twhen we reply to the inbound connection request.  The long from is\n//\t\ta full address and port in a string.  It is used for returning the\n//\t\taddress of a server that is not running locally.\n\n#define CCREQ_CONNECT\t\t0x01\n#define CCREQ_SERVER_INFO\t0x02\n#define CCREQ_PLAYER_INFO\t0x03\n#define CCREQ_RULE_INFO\t\t0x04\n\n#define CCREP_ACCEPT\t\t0x81\n#define CCREP_REJECT\t\t0x82\n#define CCREP_SERVER_INFO\t0x83\n#define CCREP_PLAYER_INFO\t0x84\n#define CCREP_RULE_INFO\t\t0x85\n\n// ProQuake -- MOD Compatibility\n#define MOD_NONE\t\t\t0x00 // NetQuake style\n#define MOD_PROQUAKE\t\t0x01 // ProQuake style\n#define MOD_QSMACK\t\t\t0x02 // QSmack style (?)\n\ntypedef struct qsocket_s\n{\n\tstruct qsocket_s\t*next;\n\tdouble\t\t\tconnecttime;\n\tdouble\t\t\tlastMessageTime;\n\tdouble\t\t\tlastSendTime;\n\n\tbool\t\tdisconnected;\n\tbool\t\tcanSend;\n\tbool\t\tsendNext;\n\t\n\tint\t\t\t\tdriver;\n\tint\t\t\t\tlandriver;\n\tint\t\t\t\tsocket;\n\tvoid\t\t\t*driverdata;\n\n\tunsigned int\tackSequence;\n\tunsigned int\tsendSequence;\n\tunsigned int\tunreliableSendSequence;\n\tint\t\t\t\tsendMessageLength;\n\tbyte\t\t\tsendMessage [NET_MAXMESSAGE];\n\n\tunsigned int\treceiveSequence;\n\tunsigned int\tunreliableReceiveSequence;\n\tint\t\t\t\treceiveMessageLength;\n\tbyte\t\t\treceiveMessage [NET_MAXMESSAGE];\n\n\tstruct qsockaddr\taddr;\n\tchar\t\t\t\taddress[NET_NAMELEN];\n\n\t// ProQuake protocol additions\n\tbyte\t\t\t\tproquake_connection;\t// 0: NetQuake, 1: ProQuake, 2: QSmack (ProQuake)\n\tbyte\t\t\t\tproquake_version;\t\t// = floor(version * 10) (must fit in one byte) (ProQuake)\n\tbyte\t\t\t\tproquake_flags;\t\t\t// Connection flags (ProQuake 3 behaviour)\n\tint\t\t\t\t\tclient_port;\t\t\t// Client Port used (ProQuake 3 behaviour)\n\tbool\t\t\t\tnet_wait;\t\t\t\t// NAT Fix for servers (ProQuake 3.4)\n\n} qsocket_t;\n\nextern qsocket_t\t*net_activeSockets;\nextern qsocket_t\t*net_freeSockets;\nextern int\t\t\tnet_numsockets;\n\ntypedef struct\n{\n\tchar\t\t*name;\n\tbool\tinitialized;\n\tint\t\t\tcontrolSock;\n\tint\t\t\t(*Init) (void);\n\tvoid\t\t(*Shutdown) (void);\n\tvoid\t\t(*Listen) (bool state);\n\tint \t\t(*OpenSocket) (int port);\n\tint \t\t(*CloseSocket) (int socket);\n\tint \t\t(*Connect) (int socket, struct qsockaddr *addr);\n\tint \t\t(*CheckNewConnections) (void);\n\tint \t\t(*Read) (int socket, byte *buf, int len, struct qsockaddr *addr);\n\tint \t\t(*Write) (int socket, byte *buf, int len, struct qsockaddr *addr);\n\tint \t\t(*Broadcast) (int socket, byte *buf, int len);\n\tchar *\t\t(*AddrToString) (struct qsockaddr *addr);\n\tint \t\t(*StringToAddr) (char *string, struct qsockaddr *addr);\n\tint \t\t(*GetSocketAddr) (int socket, struct qsockaddr *addr);\n\tint \t\t(*GetNameFromAddr) (struct qsockaddr *addr, char *name);\n\tint \t\t(*GetAddrFromName) (char *name, struct qsockaddr *addr);\n\tint\t\t\t(*AddrCompare) (struct qsockaddr *addr1, struct qsockaddr *addr2);\n\tint\t\t\t(*GetSocketPort) (struct qsockaddr *addr);\n\tint\t\t\t(*SetSocketPort) (struct qsockaddr *addr, int port);\n} net_landriver_t;\n\n#define\tMAX_NET_DRIVERS\t\t8\nextern int \t\t\t\tnet_numlandrivers;\nextern net_landriver_t\tnet_landrivers[MAX_NET_DRIVERS];\n\ntypedef struct\n{\n\tchar\t\t*name;\n\tbool\tinitialized;\n\tint\t\t\t(*Init) (void);\n\tvoid\t\t(*Listen) (bool state);\n\tvoid\t\t(*SearchForHosts) (bool xmit);\n\tqsocket_t\t*(*Connect) (char *host);\n\tqsocket_t \t*(*CheckNewConnections) (void);\n\tint\t\t\t(*QGetMessage) (qsocket_t *sock);\n\tint\t\t\t(*QSendMessage) (qsocket_t *sock, sizebuf_t *data);\n\tint\t\t\t(*SendUnreliableMessage) (qsocket_t *sock, sizebuf_t *data);\n\tbool\t(*CanSendMessage) (qsocket_t *sock);\n\tbool\t(*CanSendUnreliableMessage) (qsocket_t *sock);\n\tvoid\t\t(*Close) (qsocket_t *sock);\n\tvoid\t\t(*Shutdown) (void);\n\tint\t\t\tcontrolSock;\n} net_driver_t;\n\nextern int\t\t\tnet_numdrivers;\nextern net_driver_t\tnet_drivers[MAX_NET_DRIVERS];\n\nextern int\t\t\tDEFAULTnet_hostport;\nextern int\t\t\tnet_hostport;\n\nextern int net_driverlevel;\nextern cvar_t\t\thostname;\nextern char\t\t\tplayername[];\nextern int\t\t\tplayercolor;\n\nextern int\t\tmessagesSent;\nextern int\t\tmessagesReceived;\nextern int\t\tunreliableMessagesSent;\nextern int\t\tunreliableMessagesReceived;\n\nqsocket_t *NET_NewQSocket (void);\nvoid NET_FreeQSocket(qsocket_t *);\ndouble SetNetTime(void);\n\n\n#define HOSTCACHESIZE\t8\n\ntypedef struct\n{\n\tchar\tname[16];\n\tchar\tmap[16];\n\tchar\tcname[32];\n\tint\t\tusers;\n\tint\t\tmaxusers;\n\tint\t\tdriver;\n\tint\t\tldriver;\n\tstruct qsockaddr addr;\n} hostcache_t;\n\nextern int hostCacheCount;\nextern hostcache_t hostcache[HOSTCACHESIZE];\n\n#if !defined(_WIN32 ) && !defined (__linux__) && !defined (__sun__)\n#ifndef htonl\nextern unsigned long htonl (unsigned long hostlong);\n#endif\n#ifndef htons\nextern unsigned short htons (unsigned short hostshort);\n#endif\n#ifndef ntohl\nextern unsigned long ntohl (unsigned long netlong);\n#endif\n#ifndef ntohs\nextern unsigned short ntohs (unsigned short netshort);\n#endif\n#endif\n\n#ifdef IDGODS\nbool IsID(struct qsockaddr *addr);\n#endif\n\n//============================================================================\n//\n// public network functions\n//\n//============================================================================\n\nextern\tdouble\t\tnet_time;\nextern\tsizebuf_t\tnet_message;\nextern\tint\t\t\tnet_activeconnections;\n\nvoid\t\tNET_Init (void);\nvoid\t\tNET_Shutdown (void);\n\nstruct qsocket_s\t*NET_CheckNewConnections (void);\n// returns a new connection number if there is one pending, else -1\n\nstruct qsocket_s\t*NET_Connect (char *host);\n// called by client to connect to a host.  Returns -1 if not able to\n\nbool NET_CanSendMessage (qsocket_t *sock);\n// Returns true or false if the given qsocket can currently accept a\n// message to be transmitted.\n\nint\t\t\tNET_GetMessage (struct qsocket_s *sock);\n// returns data in net_message sizebuf\n// returns 0 if no data is waiting\n// returns 1 if a message was received\n// returns 2 if an unreliable message was received\n// returns -1 if the connection died\n\nint\t\t\tNET_SendMessage (struct qsocket_s *sock, sizebuf_t *data);\nint\t\t\tNET_SendUnreliableMessage (struct qsocket_s *sock, sizebuf_t *data);\n// returns 0 if the message connot be delivered reliably, but the connection\n//\t\tis still considered valid\n// returns 1 if the message was sent properly\n// returns -1 if the connection died\n\nint\t\t\tNET_SendToAll(sizebuf_t *data, int blocktime);\n// This is a reliable *blocking* send to all attached clients.\n\n\nvoid\t\tNET_Close (struct qsocket_s *sock);\n// if a dead connection is returned by a get or send function, this function\n// should be called when it is convenient\n\n// Server calls when a client is kicked off for a game related misbehavior\n// like an illegal protocal conversation.  Client calls when disconnecting\n// from a server.\n// A netcon_t number will not be reused until this function is called for it\n\nvoid NET_Poll(void);\n\n\ntypedef struct _PollProcedure\n{\n\tstruct _PollProcedure\t*next;\n\tdouble\t\t\t\t\tnextTime;\n\tvoid\t\t\t\t\t(*procedure)();\n\tvoid\t\t\t\t\t*arg;\n} PollProcedure;\n\nvoid SchedulePollProcedure(PollProcedure *pp, double timeOffset);\n\nextern\tbool\ttcpipAvailable;\nextern\tchar\t\tmy_tcpip_address[NET_NAMELEN];\n\nextern\tbool\tslistInProgress;\nextern\tbool\tslistSilent;\nextern\tbool\tslistLocal;\n\nvoid NET_Slist_f (void);\n"
  },
  {
    "path": "source/net_adhoc.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_adhoc.h\n\nint  AdHoc_Init (void);\nvoid AdHoc_Shutdown (void);\nvoid AdHoc_Listen (bool state);\nint  AdHoc_OpenSocket (int port);\nint  AdHoc_CloseSocket (int socket);\nint  AdHoc_Connect (int socket, struct qsockaddr *addr);\nint  AdHoc_CheckNewConnections (void);\nint  AdHoc_Read (int socket, byte *buf, int len, struct qsockaddr *addr);\nint  AdHoc_Write (int socket, byte *buf, int len, struct qsockaddr *addr);\nint  AdHoc_Broadcast (int socket, byte *buf, int len);\nchar *AdHoc_AddrToString (struct qsockaddr *addr);\nint  AdHoc_StringToAddr (char *string, struct qsockaddr *addr);\nint  AdHoc_GetSocketAddr (int socket, struct qsockaddr *addr);\nint  AdHoc_GetNameFromAddr (struct qsockaddr *addr, char *name);\nint  AdHoc_GetAddrFromName (char *name, struct qsockaddr *addr);\nint  AdHoc_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);\nint  AdHoc_GetSocketPort (struct qsockaddr *addr);\nint  AdHoc_SetSocketPort (struct qsockaddr *addr, int port);\n"
  },
  {
    "path": "source/net_adhoc_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_adhoc.c\n\n#include \"quakedef.h\"\n#include \"net_adhoc.h\"\n\n#include <sys/types.h>\n#include <vitasdk.h>\n#include <errno.h>\n\n#ifdef __sun__\n#include <sys/filio.h>\n#endif\n\n#ifdef NeXT\n#include <libc.h>\n#endif\n\nextern cvar_t hostname;\nextern void Log (const char *format, ...);\n\n#define ADHOC_NET 29\n\ntypedef struct sockaddr_adhoc\n{\n\tchar   len;\n\tshort family;\n\tuint16_t port;\n\tchar mac[6];\n\tchar zero[6];\n} sockaddr_adhoc;\n\nstatic int net_acceptsocket = -1;\t\t// socket for fielding new connections\nstatic int net_controlsocket;\nstatic int net_broadcastsocket = 0;\nstatic struct qsockaddr broadcastaddr;\n\n#include \"net_adhoc.h\"\n\n//=============================================================================\n\nint AdHoc_Init (void)\n{\n\tLog(\"ADHoc_Init called...\");\n\tstruct qsockaddr addr;\n\tchar *colon;\n\t\n\t// if the quake hostname isn't set, set it to player nickname\n\tif (!strcmp(hostname.string, \"UNNAMED\"))\n\t{\n\t\tSceAppUtilInitParam init_param;\n\t\tSceAppUtilBootParam boot_param;\n\t\tmemset(&init_param, 0, sizeof(SceAppUtilInitParam));\n\t\tmemset(&boot_param, 0, sizeof(SceAppUtilBootParam));\n\t\tsceAppUtilInit(&init_param, &boot_param);\n\t\tchar nick[SCE_SYSTEM_PARAM_USERNAME_MAXSIZE];\n\t\tsceAppUtilSystemParamGetString(SCE_SYSTEM_PARAM_ID_USERNAME, nick, SCE_SYSTEM_PARAM_USERNAME_MAXSIZE);\n\t\tCvar_Set (\"hostname\", nick);\n\t}\n\n\tif ((net_controlsocket = AdHoc_OpenSocket (0)) == -1)\n\t\tSys_Error(\"AdHoc_Init: Unable to open control socket\\n\");\n\n\t((struct sockaddr_adhoc *)&broadcastaddr)->family = ADHOC_NET;\n\tint i;\n\tfor(i=0; i<6; i++) ((struct sockaddr_adhoc *)&broadcastaddr)->mac[i] = 0xFF;\n\t((struct sockaddr_adhoc *)&broadcastaddr)->port = sceNetHtons(net_hostport);\n\n\tAdHoc_GetSocketAddr (net_controlsocket, &addr);\n\tstrcpy(my_tcpip_address,  AdHoc_AddrToString (&addr));\n\n\tcolon = strrchr (my_tcpip_address, ':');\n\tif (colon)\n\t\t*colon = 0;\n\t\n\tAdHoc_Listen(1);\n\t\n\tCon_Printf(\"AdHoc Initialized as IP %s\\n\", my_tcpip_address);\n\ttcpipAvailable = true;\n\n\treturn net_controlsocket;\n}\n\n//=============================================================================\n\nvoid AdHoc_Shutdown (void)\n{\n\tLog(\"AdHoc_Shutdown\");\n\tAdHoc_Listen (false);\n\tAdHoc_CloseSocket (net_controlsocket);\n\tsceNetAdhocctlTerm();\n\tsceNetAdhocTerm();\n}\n\n//=============================================================================\n\nvoid AdHoc_Listen (bool state)\n{\n\tLog(\"AdHoc_Listen\");\n\t// enable listening\n\tif (state)\n\t{\n\t\tif (net_acceptsocket != -1)\n\t\t\treturn;\n\t\tif ((net_acceptsocket = AdHoc_OpenSocket (net_hostport)) == -1)\n\t\t\tSys_Error (\"AdHoc_Listen: Unable to open accept socket\\n\");\n\t\treturn;\n\t}\n\n\t// disable listening\n\tif (net_acceptsocket == -1)\n\t\treturn;\n\tAdHoc_CloseSocket (net_acceptsocket);\n\tnet_acceptsocket = -1;\n}\n\n//=============================================================================\n\nint AdHoc_OpenSocket (int port)\n{\n\tLog(\"AdHoc_OpenSocket(%ld)\", port);\n\tuint8_t mac[8];\n\tsceNetAdhocctlGetEtherAddr((SceNetEtherAddr *)mac);\n\tint rc = sceNetAdhocPdpCreate((SceNetEtherAddr *)mac, port, 0x2000, 0);\n\tif(rc < 0) return -1;\n\treturn rc;\n}\n\n//=============================================================================\n\nint AdHoc_CloseSocket (int socket)\n{\n\tLog(\"AdHoc_CloseSocket\");\n\tif (socket == net_broadcastsocket)\n\t\tnet_broadcastsocket = 0;\n\treturn sceNetAdhocPdpDelete(socket, 0);\n}\n\n//=============================================================================\n\nint AdHoc_Connect (int socket, struct qsockaddr *addr)\n{\n\tLog(\"AdHoc_Connect\");\n\treturn 0;\n}\n\n//=============================================================================\n\nstatic SceNetAdhocPdpStat gPdpStat;\nSceNetAdhocPdpStat *findPdpStat(int socket, SceNetAdhocPdpStat *pdpStat)\n{\n\tif(socket == pdpStat->id) {\n\t\tmemcpy(&gPdpStat, pdpStat, sizeof(SceNetAdhocPdpStat));\n\t\treturn &gPdpStat;\n\t}\n\t\tif(pdpStat->next) return findPdpStat(socket, pdpStat->next);\n\t\treturn (SceNetAdhocPdpStat *)-1;\n}\n\nint AdHoc_CheckNewConnections (void)\n{\n\tLog(\"AdHoc_CheckNewConnections\");\n\tSceNetAdhocPdpStat pdpStat[20];\n\tint len = sizeof(SceNetAdhocPdpStat) * 20;\n\t\n\tif (net_acceptsocket == -1) return -1;\n\t\n\tint err = sceNetAdhocGetPdpStat(&len, pdpStat);\n\tif(err < 0) return -1;\n\t\n\tSceNetAdhocPdpStat *tempPdp = findPdpStat(net_acceptsocket, pdpStat);\n\tif (tempPdp < 0) return -1;\n\telse if (tempPdp->rcv_sb_cc > 0) return net_acceptsocket;\n\n\treturn -1;\n}\n\n//=============================================================================\n\nint AdHoc_Read (int socket, byte *buf, int len, struct qsockaddr *addr)\n{\n\tunsigned short port;\n\tint datalength = len;\n\tint ret;\n\t\n\tret = sceNetAdhocPdpRecv(socket, (SceNetEtherAddr *)((sockaddr_adhoc *)addr)->mac, &port, buf, &datalength, 0, 1);\n\tLog(\"AdHoc_Read returned %ld\",ret);\n\tif (ret == SCE_ERROR_NET_ADHOC_WOULD_BLOCK)\n\t\treturn 0;\n\telse if (ret < 0)\n\t\treturn -1;\n\t\n\t((sockaddr_adhoc *)addr)->port = port;\n\t\n\treturn datalength;\n}\n\n//=============================================================================\n\nint AdHoc_MakeSocketBroadcastCapable (int socket)\n{\n\tLog(\"AdHoc_MakeSocketBroadcastCapable\");\n\tnet_broadcastsocket = socket;\n\n\treturn 0;\n}\n\n//=============================================================================\n\nint AdHoc_Broadcast (int socket, byte *buf, int len)\n{\n\tLog(\"AdHoc_Broadcast\");\n\tint ret;\n\n\tif (socket != net_broadcastsocket)\n\t{\n\t\tif (net_broadcastsocket != 0)\n\t\t\tSys_Error(\"Attempted to use multiple broadcasts sockets\\n\");\n\t\tret = AdHoc_MakeSocketBroadcastCapable (socket);\n\t\tif (ret == -1)\n\t\t{\n\t\t\tCon_Printf(\"Unable to make socket broadcast capable\\n\");\n\t\t\treturn ret;\n\t\t}\n\t}\n\n\treturn AdHoc_Write (socket, buf, len, &broadcastaddr);\n}\n\n//=============================================================================\n\nint AdHoc_Write (int socket, byte *buf, int len, struct qsockaddr *addr)\n{\n\tint ret;\n\n\tret = sceNetAdhocPdpSend(socket, (SceNetEtherAddr *)((sockaddr_adhoc *)addr)->mac, ((sockaddr_adhoc *)addr)->port, buf, len, 0, 1);\n\tLog(\"AdHoc_Write returned %ld\",ret);\n\tif (ret == SCE_ERROR_NET_ADHOC_WOULD_BLOCK)\n\t\treturn 0;\n\telse if (ret < 0)\n\t\treturn -1;\n\treturn ret;\n}\n\n//=============================================================================\n\nchar *AdHoc_AddrToString (struct qsockaddr *addr)\n{\n\tstatic char buffer[22];\n\tint haddr;\n\n\tsceNetEtherNtostr((SceNetEtherAddr *)((sockaddr_adhoc *)addr)->mac, buffer, 22);\n\tsprintf(buffer + strlen(buffer), \":%d\", ((sockaddr_adhoc *)addr)->port);\n\tLog(\"AdHoc_AddrToString returned %s\",buffer);\n\treturn buffer;\n}\n\n//=============================================================================\n\nint AdHoc_StringToAddr (char *string, struct qsockaddr *addr)\n{\n\tLog(\"AdHoc_StringToAddr(%s)\",string);\n\tint ha1, ha2, ha3, ha4, ha5, ha6, hp;\n\n\tint r = sscanf(string, \"%x:%x:%x:%x:%x:%x:%d\", &ha1, &ha2, &ha3, &ha4, &ha5, &ha6, &hp);\n\tif (r < 7) hp = net_hostport;\n\taddr->sa_family = ADHOC_NET;\n\t((struct sockaddr_adhoc *)addr)->mac[0] = ha1 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->mac[1] = ha2 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->mac[2] = ha3 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->mac[3] = ha4 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->mac[4] = ha5 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->mac[5] = ha6 & 0xFF;\n\t((struct sockaddr_adhoc *)addr)->port = hp & 0xFFFF;\n\treturn 0;\n}\n\n//=============================================================================\n\nint AdHoc_GetSocketAddr (int socket, struct qsockaddr *addr)\n{\n\tLog(\"AdHoc_GetSocketAddr\");\n\tSceNetAdhocPdpStat pdpStat[20];\n\tint len = sizeof(SceNetAdhocPdpStat) * 20;\n\n\tint err = sceNetAdhocGetPdpStat(&len, pdpStat);\n\tif(err<0) return -1;\n\n\tSceNetAdhocPdpStat *tempPdp = findPdpStat(socket, pdpStat);\n\tif(tempPdp < 0) return -1;\n\n\tmemcpy(((struct sockaddr_adhoc *)addr)->mac, &tempPdp->laddr, 6);\n\t((struct sockaddr_adhoc *)addr)->port = tempPdp->lport;\n\taddr->sa_family = ADHOC_NET;\n\treturn 0;\n}\n\n//=============================================================================\n\nint AdHoc_GetNameFromAddr (struct qsockaddr *addr, char *name)\n{\n\tstrcpy (name, AdHoc_AddrToString (addr));\n\treturn 0;\n}\n\n//=============================================================================\n\nint AdHoc_GetAddrFromName(char *name, struct qsockaddr *addr)\n{\n\tLog(\"AdHoc_GetAddrFromName(%s)\", name);\n\treturn AdHoc_StringToAddr(name, addr);\n}\n\n//=============================================================================\n\nint AdHoc_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)\n{\n\tif (memcmp(((struct sockaddr_adhoc *)addr1)->mac, ((struct sockaddr_adhoc *)addr2)->mac, 6) != 0) return -1;\n\tif (((struct sockaddr_adhoc *)addr1)->port != ((struct sockaddr_adhoc *)addr2)->port) return 1;\n\t\n\tLog(\"AdHoc_AddrCompare returned 0\");\n\treturn 0;\n}\n\n//=============================================================================\n\nint AdHoc_GetSocketPort (struct qsockaddr *addr)\n{\n\tLog(\"AdHoc_GetSocketPort\");\n\treturn sceNetNtohs(((struct sockaddr_adhoc *)addr)->port);\n}\n\n\nint AdHoc_SetSocketPort (struct qsockaddr *addr, int port)\n{\n\tLog(\"AdHoc_SetSocketPort\");\n\t((struct sockaddr_adhoc *)addr)->port = sceNetHtons(port);\n\treturn 0;\n}\n\n//=============================================================================\n"
  },
  {
    "path": "source/net_dgrm.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_dgrm.c\n\n// This is enables a simple IP banning mechanism\n//#define BAN_TEST\n\n#ifdef BAN_TEST\n#if defined(_WIN32)\n#include <windows.h>\n#elif defined (NeXT)\n#include <sys/socket.h>\n#include <arpa/inet.h>\n#else\n#define AF_INET \t\t2\t/* internet */\nstruct in_addr\n{\n\tunion\n\t{\n\t\tstruct { unsigned char s_b1,s_b2,s_b3,s_b4; } S_un_b;\n\t\tstruct { unsigned short s_w1,s_w2; } S_un_w;\n\t\tunsigned long S_addr;\n\t} S_un;\n};\n#define\ts_addr\tS_un.S_addr\t/* can be used for most tcp & ip code */\nstruct sockaddr_in\n{\n    short\t\t\tsin_family;\n    unsigned short\tsin_port;\n\tstruct in_addr\tsin_addr;\n    char\t\t\tsin_zero[8];\n};\n//char *inet_ntoa(struct in_addr in);\n#define inet_ntoa(x) 1\n//unsigned long inet_addr(const char *cp);\n#define inet_addr(x) 1\n#endif\n#endif\t// BAN_TEST\n\n#include \"quakedef.h\"\n#include \"net_dgrm.h\"\n\nextern cvar_t pq_password;\n\n// these two macros are to make the code more readable\n#define sfunc\tnet_landrivers[sock->landriver]\n#define dfunc\tnet_landrivers[net_landriverlevel]\n\nstatic int net_landriverlevel;\n\n/* statistic counters */\nint\tpacketsSent = 0;\nint\tpacketsReSent = 0;\nint packetsReceived = 0;\nint receivedDuplicateCount = 0;\nint shortPacketCount = 0;\nint droppedDatagrams;\n\nstatic int myDriverLevel;\n\nstruct\n{\n\tunsigned int\tlength;\n\tunsigned int\tsequence;\n\tbyte\t\t\tdata[MAX_DATAGRAM];\n} packetBuffer;\n\nextern int m_return_state;\n//extern int m_state;\nextern bool m_return_onerror;\nextern char m_return_reason[32];\n\n\n// JPG - recognize ip:port\nvoid Strip_Port(char *ch)\n{\n\tint occurrances = 0;\n\tchar *last_valid_ch = NULL;\n\twhile (ch) {\n\t\tch = strchr(ch, ':');\n\t\tif (ch){\n\t\t\toccurrances++;\n\t\t\tlast_valid_ch = ch;\n\t\t\tch++;\n\t\t}\n\t}\n\tif ((occurrances == 1) || (occurrances == 6))\n\t{\n\t\tch = last_valid_ch;\n\t\tint old_port = net_hostport;\n\n\t\tsscanf(ch + 1, \"%d\", &net_hostport);\n\t\tif (proto_idx == 0) {\n\t\t\tfor (; ch[-1] == ' '; ch--);\n\t\t\t*ch = 0;\n\t\t}\n\t\tif (net_hostport != old_port)\n\t\t\tCon_Printf(\"Setting port to %d\\n\", net_hostport);\n\t}\n\telse //R00k if not specifying port then use default port\n\t{\n\t\tnet_hostport = DEFAULTnet_hostport;\n\t\tCon_Printf(\"Using port %d\\n\", net_hostport);\n\t}\n}\n\n#ifdef DEBUG\nchar *StrAddr (struct qsockaddr *addr)\n{\n\tstatic char buf[34];\n\tbyte *p = (byte *)addr;\n\tint n;\n\n\tfor (n = 0; n < 16; n++)\n\t\tsprintf (buf + n * 2, \"%02x\", *p++);\n\treturn buf;\n}\n#endif\n\n\n#ifdef BAN_TEST\nunsigned long banAddr = 0x00000000;\nunsigned long banMask = 0xffffffff;\n\nvoid NET_Ban_f (void)\n{\n\tchar\taddrStr [32];\n\tchar\tmaskStr [32];\n\tvoid\t(*print) (char *fmt, ...);\n\n\tif (cmd_source == src_command)\n\t{\n\t\tif (!sv.active)\n\t\t{\n\t\t\tCmd_ForwardToServer ();\n\t\t\treturn;\n\t\t}\n\t\tprint = Con_Printf;\n\t}\n\telse\n\t{\n\t\tif (pr_global_struct->deathmatch && !host_client->privileged)\n\t\t\treturn;\n\t\tprint = SV_ClientPrintf;\n\t}\n\n\tswitch (Cmd_Argc ())\n\t{\n\t\tcase 1:\n\t\t\tif (((struct in_addr *)&banAddr)->s_addr)\n\t\t\t{\n\t\t\t\tstrcpy(addrStr, inet_ntoa(*(struct in_addr *)&banAddr));\n\t\t\t\tstrcpy(maskStr, inet_ntoa(*(struct in_addr *)&banMask));\n\t\t\t\tprint(\"Banning %s [%s]\\n\", addrStr, maskStr);\n\t\t\t}\n\t\t\telse\n\t\t\t\tprint(\"Banning not active\\n\");\n\t\t\tbreak;\n\n\t\tcase 2:\n\t\t\tif (strcasecmp(Cmd_Argv(1), \"off\") == 0)\n\t\t\t\tbanAddr = 0x00000000;\n\t\t\telse\n\t\t\t\tbanAddr = inet_addr(Cmd_Argv(1));\n\t\t\tbanMask = 0xffffffff;\n\t\t\tbreak;\n\n\t\tcase 3:\n\t\t\tbanAddr = inet_addr(Cmd_Argv(1));\n\t\t\tbanMask = inet_addr(Cmd_Argv(2));\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tprint(\"BAN ip_address [mask]\\n\");\n\t\t\tbreak;\n\t}\n}\n#endif\n\n// JPG 3.00 - this code appears multiple times, so factor it out\nqsocket_t *Datagram_Reject(char *message, int acceptsock, struct qsockaddr *addr)\n{\n\tSZ_Clear(&net_message);\n\t// save space for the header, filled in later\n\tMSG_WriteLong(&net_message, 0);\n\tMSG_WriteByte(&net_message, CCREP_REJECT);\n\tMSG_WriteString(&net_message, message);\n\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\tdfunc.Write(acceptsock, net_message.data, net_message.cursize, addr);\n\tSZ_Clear(&net_message);\n\n\treturn NULL;\n}\n\nint Datagram_SendMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tunsigned int\tpacketLen;\n\tunsigned int\tdataLen;\n\tunsigned int\teom;\n\n#ifdef DEBUG\n\tif (data->cursize == 0)\n\t\tSys_Error(\"Datagram_SendMessage: zero length message\\n\");\n\n\tif (data->cursize > NET_MAXMESSAGE)\n\t\tSys_Error(\"Datagram_SendMessage: message too big %u\\n\", data->cursize);\n\n\tif (sock->canSend == false)\n\t\tSys_Error(\"SendMessage: called with canSend == false\\n\");\n#endif\n\n\tmemcpy(sock->sendMessage, data->data, data->cursize);\n\tsock->sendMessageLength = data->cursize;\n\n\tif (data->cursize <= MAX_DATAGRAM)\n\t{\n\t\tdataLen = data->cursize;\n\t\teom = NETFLAG_EOM;\n\t}\n\telse\n\t{\n\t\tdataLen = MAX_DATAGRAM;\n\t\teom = 0;\n\t}\n\tpacketLen = NET_HEADERSIZE + dataLen;\n\n\tpacketBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));\n\tpacketBuffer.sequence = BigLong(sock->sendSequence++);\n\tmemcpy (packetBuffer.data, sock->sendMessage, dataLen);\n\n\tsock->canSend = false;\n\n\tif (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)\n\t\treturn -1;\n\n\tsock->lastSendTime = net_time;\n\tpacketsSent++;\n\treturn 1;\n}\n\n\nint SendMessageNext (qsocket_t *sock)\n{\n\tunsigned int\tpacketLen;\n\tunsigned int\tdataLen;\n\tunsigned int\teom;\n\n\tif (sock->sendMessageLength <= MAX_DATAGRAM)\n\t{\n\t\tdataLen = sock->sendMessageLength;\n\t\teom = NETFLAG_EOM;\n\t}\n\telse\n\t{\n\t\tdataLen = MAX_DATAGRAM;\n\t\teom = 0;\n\t}\n\tpacketLen = NET_HEADERSIZE + dataLen;\n\n\tpacketBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));\n\tpacketBuffer.sequence = BigLong(sock->sendSequence++);\n\tmemcpy (packetBuffer.data, sock->sendMessage, dataLen);\n\n\tsock->sendNext = false;\n\n\tif (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)\n\t\treturn -1;\n\n\tsock->lastSendTime = net_time;\n\tpacketsSent++;\n\treturn 1;\n}\n\n\nint ReSendMessage (qsocket_t *sock)\n{\n\tunsigned int\tpacketLen;\n\tunsigned int\tdataLen;\n\tunsigned int\teom;\n\n\tif (sock->sendMessageLength <= MAX_DATAGRAM)\n\t{\n\t\tdataLen = sock->sendMessageLength;\n\t\teom = NETFLAG_EOM;\n\t}\n\telse\n\t{\n\t\tdataLen = MAX_DATAGRAM;\n\t\teom = 0;\n\t}\n\tpacketLen = NET_HEADERSIZE + dataLen;\n\n\tpacketBuffer.length = BigLong(packetLen | (NETFLAG_DATA | eom));\n\tpacketBuffer.sequence = BigLong(sock->sendSequence - 1);\n\tmemcpy (packetBuffer.data, sock->sendMessage, dataLen);\n\n\tsock->sendNext = false;\n\n\tif (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)\n\t\treturn -1;\n\n\tsock->lastSendTime = net_time;\n\tpacketsReSent++;\n\treturn 1;\n}\n\n\nbool Datagram_CanSendMessage (qsocket_t *sock)\n{\n\tif (sock->sendNext)\n\t\tSendMessageNext (sock);\n\n\treturn sock->canSend;\n}\n\n\nbool Datagram_CanSendUnreliableMessage (qsocket_t *sock)\n{\n\treturn true;\n}\n\n\nint Datagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tint \tpacketLen;\n\n#ifdef DEBUG\n\tif (data->cursize == 0)\n\t\tSys_Error(\"Datagram_SendUnreliableMessage: zero length message\\n\");\n\n\tif (data->cursize > MAX_DATAGRAM)\n\t\tSys_Error(\"Datagram_SendUnreliableMessage: message too big %u\\n\", data->cursize);\n#endif\n\n\tpacketLen = NET_HEADERSIZE + data->cursize;\n\n\tpacketBuffer.length = BigLong(packetLen | NETFLAG_UNRELIABLE);\n\tpacketBuffer.sequence = BigLong(sock->unreliableSendSequence++);\n\tmemcpy (packetBuffer.data, data->data, data->cursize);\n\n\tif (sfunc.Write (sock->socket, (byte *)&packetBuffer, packetLen, &sock->addr) == -1)\n\t\treturn -1;\n\n\tpacketsSent++;\n\treturn 1;\n}\n\n\nint\tDatagram_GetMessage (qsocket_t *sock)\n{\n\tunsigned int\tlength;\n\tunsigned int\tflags;\n\tint\t\t\t\tret = 0;\n\tstruct qsockaddr readaddr;\n\tunsigned int\tsequence;\n\tunsigned int\tcount;\n\n\tif (!sock->canSend)\n\t\tif ((net_time - sock->lastSendTime) > 1.0)\n\t\t\tReSendMessage (sock);\n\n\twhile(1)\n\t{\t\n\t\tlength = sfunc.Read (sock->socket, (byte *)&packetBuffer, NET_DATAGRAMSIZE, &readaddr);\n\n//\tif ((rand() & 255) > 220)\n//\t\tcontinue;\n\n\t\tif (length == 0)\n\t\t\tbreak;\n\n\t\tif (length == -1)\n\t\t{\n\t\t\tCon_Printf(\"Read error\\n\");\n\t\t\treturn -1;\n\t\t}\n\n\t\t// ProQuake: NAT support for Servers\n\t\tif (!sock->net_wait && sfunc.AddrCompare(&readaddr, &sock->addr) != 0)\t\n\t\t{\n#ifdef DEBUG\n\t\t\tCon_DPrintf(\"Forged packet received\\n\");\n\t\t\tCon_DPrintf(\"Expected: %s\\n\", StrAddr (&sock->addr));\n\t\t\tCon_DPrintf(\"Received: %s\\n\", StrAddr (&readaddr));\n#endif\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (length < NET_HEADERSIZE)\n\t\t{\n\t\t\tshortPacketCount++;\n\t\t\tcontinue;\n\t\t}\n\n\t\tlength = BigLong(packetBuffer.length);\n\t\tflags = length & (~NETFLAG_LENGTH_MASK);\n\t\tlength &= NETFLAG_LENGTH_MASK;\n\n\t\tif (length > NET_DATAGRAMSIZE)\n\t\t{\n\t\t\tCon_Printf(\"Invalid length\\n\");\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (flags & NETFLAG_CTL)\n\t\t\tcontinue;\n\n\t\tsequence = BigLong(packetBuffer.sequence);\n\t\tpacketsReceived++;\n\n\t\t// ProQuake\n\t\tif (sock->net_wait)\n\t\t{\n\t\t\tsock->addr = readaddr;\n\t\t\tstrcpy(sock->address, sfunc.AddrToString(&readaddr));\n\t\t\tsock->net_wait = false;\n\t\t}\n\n\t\tif (flags & NETFLAG_UNRELIABLE)\n\t\t{\n\t\t\tif (sequence < sock->unreliableReceiveSequence)\n\t\t\t{\n\t\t\t\tCon_DPrintf(\"Got a stale datagram\\n\");\n\t\t\t\tret = 0;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (sequence != sock->unreliableReceiveSequence)\n\t\t\t{\n\t\t\t\tcount = sequence - sock->unreliableReceiveSequence;\n\t\t\t\tdroppedDatagrams += count;\n\t\t\t\tCon_DPrintf(\"Dropped %u datagram(s)\\n\", count);\n\t\t\t}\n\t\t\tsock->unreliableReceiveSequence = sequence + 1;\n\n\t\t\tlength -= NET_HEADERSIZE;\n\n\t\t\tSZ_Clear (&net_message);\n\t\t\tSZ_Write (&net_message, packetBuffer.data, length);\n\n\t\t\tret = 2;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (flags & NETFLAG_ACK)\n\t\t{\n\t\t\tif (sequence != (sock->sendSequence - 1))\n\t\t\t{\n\t\t\t\tCon_DPrintf(\"Stale ACK received\\n\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sequence == sock->ackSequence)\n\t\t\t{\n\t\t\t\tsock->ackSequence++;\n\t\t\t\tif (sock->ackSequence != sock->sendSequence)\n\t\t\t\t\tCon_DPrintf(\"ack sequencing error\\n\");\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tCon_DPrintf(\"Duplicate ACK received\\n\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsock->sendMessageLength -= MAX_DATAGRAM;\n\t\t\tif (sock->sendMessageLength > 0)\n\t\t\t{\n\t\t\t\tmemcpy(sock->sendMessage, sock->sendMessage+MAX_DATAGRAM, sock->sendMessageLength);\n\t\t\t\tsock->sendNext = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tsock->sendMessageLength = 0;\n\t\t\t\tsock->canSend = true;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (flags & NETFLAG_DATA)\n\t\t{\n\t\t\tpacketBuffer.length = BigLong(NET_HEADERSIZE | NETFLAG_ACK);\n\t\t\tpacketBuffer.sequence = BigLong(sequence);\n\t\t\tsfunc.Write (sock->socket, (byte *)&packetBuffer, NET_HEADERSIZE, &readaddr);\n\n\t\t\tif (sequence != sock->receiveSequence)\n\t\t\t{\n\t\t\t\treceivedDuplicateCount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tsock->receiveSequence++;\n\n\t\t\tlength -= NET_HEADERSIZE;\n\n\t\t\tif (flags & NETFLAG_EOM)\n\t\t\t{\n\t\t\t\tSZ_Clear(&net_message);\n\t\t\t\tSZ_Write(&net_message, sock->receiveMessage, sock->receiveMessageLength);\n\t\t\t\tSZ_Write(&net_message, packetBuffer.data, length);\n\t\t\t\tsock->receiveMessageLength = 0;\n\n\t\t\t\tret = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tmemcpy(sock->receiveMessage + sock->receiveMessageLength, packetBuffer.data, length);\n\t\t\tsock->receiveMessageLength += length;\n\t\t\tcontinue;\n\t\t}\n\t}\n\n\tif (sock->sendNext)\n\t\tSendMessageNext (sock);\n\n\treturn ret;\n}\n\n\nvoid PrintStats(qsocket_t *s)\n{\n\tCon_Printf(\"canSend = %4u   \\n\", s->canSend);\n\tCon_Printf(\"sendSeq = %4u   \", s->sendSequence);\n\tCon_Printf(\"recvSeq = %4u   \\n\", s->receiveSequence);\n\tCon_Printf(\"\\n\");\n}\n\nvoid NET_Stats_f (void)\n{\n\tqsocket_t\t*s;\n\n\tif (Cmd_Argc () == 1)\n\t{\n\t\tCon_Printf(\"unreliable messages sent   = %i\\n\", unreliableMessagesSent);\n\t\tCon_Printf(\"unreliable messages recv   = %i\\n\", unreliableMessagesReceived);\n\t\tCon_Printf(\"reliable messages sent     = %i\\n\", messagesSent);\n\t\tCon_Printf(\"reliable messages received = %i\\n\", messagesReceived);\n\t\tCon_Printf(\"packetsSent                = %i\\n\", packetsSent);\n\t\tCon_Printf(\"packetsReSent              = %i\\n\", packetsReSent);\n\t\tCon_Printf(\"packetsReceived            = %i\\n\", packetsReceived);\n\t\tCon_Printf(\"receivedDuplicateCount     = %i\\n\", receivedDuplicateCount);\n\t\tCon_Printf(\"shortPacketCount           = %i\\n\", shortPacketCount);\n\t\tCon_Printf(\"droppedDatagrams           = %i\\n\", droppedDatagrams);\n\t}\n\telse if (strcmp(Cmd_Argv(1), \"*\") == 0)\n\t{\n\t\tfor (s = net_activeSockets; s; s = s->next)\n\t\t\tPrintStats(s);\n\t\tfor (s = net_freeSockets; s; s = s->next)\n\t\t\tPrintStats(s);\n\t}\n\telse\n\t{\n\t\tfor (s = net_activeSockets; s; s = s->next)\n\t\t\tif (strcasecmp(Cmd_Argv(1), s->address) == 0)\n\t\t\t\tbreak;\n\t\tif (s == NULL)\n\t\t\tfor (s = net_freeSockets; s; s = s->next)\n\t\t\t\tif (strcasecmp(Cmd_Argv(1), s->address) == 0)\n\t\t\t\t\tbreak;\n\t\tif (s == NULL)\n\t\t\treturn;\n\t\tPrintStats(s);\n\t}\n}\n\n\nstatic bool testInProgress = false;\nstatic int\t\ttestPollCount;\nstatic int\t\ttestDriver;\nstatic int\t\ttestSocket;\n\nstatic void Test_Poll(void);\nPollProcedure\ttestPollProcedure = {NULL, 0.0, Test_Poll};\n\nstatic void Test_Poll(void)\n{\n\tstruct qsockaddr clientaddr;\n\tint\t\tcontrol;\n\tint\t\tlen;\n\tchar\tname[32];\n\tchar\taddress[64];\n\tint\t\tcolors;\n\tint\t\tfrags;\n\tint\t\tconnectTime;\n\tbyte\tplayerNumber;\n\n\tnet_landriverlevel = testDriver;\n\n\twhile (1)\n\t{\n\t\tlen = dfunc.Read (testSocket, net_message.data, net_message.maxsize, &clientaddr);\n\t\tif (len < sizeof(int))\n\t\t\tbreak;\n\n\t\tnet_message.cursize = len;\n\n\t\tMSG_BeginReading ();\n\t\tcontrol = BigLong(*((int *)net_message.data));\n\t\tMSG_ReadLong();\n\t\tif (control == -1)\n\t\t\tbreak;\n\t\tif ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)\n\t\t\tbreak;\n\t\tif ((control & NETFLAG_LENGTH_MASK) != len)\n\t\t\tbreak;\n\n\t\tif (MSG_ReadByte() != CCREP_PLAYER_INFO)\n\t\t\tSys_Error(\"Unexpected repsonse to Player Info request\\n\");\n\n\t\tplayerNumber = MSG_ReadByte();\n\t\tstrcpy(name, MSG_ReadString());\n\t\tcolors = MSG_ReadLong();\n\t\tfrags = MSG_ReadLong();\n\t\tconnectTime = MSG_ReadLong();\n\t\tstrcpy(address, MSG_ReadString());\n\n\t\tCon_Printf(\"%s\\n  frags:%3i  colors:%u %u  time:%u\\n  %s\\n\", name, frags, colors >> 4, colors & 0x0f, connectTime / 60, address);\n\t}\n\n\ttestPollCount--;\n\tif (testPollCount)\n\t{\n\t\tSchedulePollProcedure(&testPollProcedure, 0.1);\n\t}\n\telse\n\t{\n\t\tdfunc.CloseSocket(testSocket);\n\t\ttestInProgress = false;\n\t}\n}\n\nstatic void Test_f (void)\n{\n\tchar\t*host;\n\tint\t\tn;\n\tint\t\tmax = MAX_SCOREBOARD;\n\tstruct qsockaddr sendaddr;\n\n\tif (testInProgress)\n\t\treturn;\n\n\thost = Cmd_Argv (1);\n\n\tif (host && hostCacheCount)\n\t{\n\t\tfor (n = 0; n < hostCacheCount; n++)\n\t\t\tif (strcasecmp (host, hostcache[n].name) == 0)\n\t\t\t{\n\t\t\t\tif (hostcache[n].driver != myDriverLevel)\n\t\t\t\t\tcontinue;\n\t\t\t\tnet_landriverlevel = hostcache[n].ldriver;\n\t\t\t\tmax = hostcache[n].maxusers;\n\t\t\t\tmemcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (n < hostCacheCount)\n\t\t\tgoto JustDoIt;\n\t}\n\n\tfor (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)\n\t{\n\t\tif (!net_landrivers[net_landriverlevel].initialized)\n\t\t\tcontinue;\n\n\t\t// see if we can resolve the host name\n\t\tif (dfunc.GetAddrFromName(host, &sendaddr) != -1)\n\t\t\tbreak;\n\t}\n\tif (net_landriverlevel == net_numlandrivers)\n\t\treturn;\n\nJustDoIt:\n\ttestSocket = dfunc.OpenSocket(0);\n\tif (testSocket == -1)\n\t\treturn;\n\n\ttestInProgress = true;\n\ttestPollCount = 20;\n\ttestDriver = net_landriverlevel;\n\n\tfor (n = 0; n < max; n++)\n\t{\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREQ_PLAYER_INFO);\n\t\tMSG_WriteByte(&net_message, n);\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | \t(net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Write (testSocket, net_message.data, net_message.cursize, &sendaddr);\n\t}\n\tSZ_Clear(&net_message);\n\tSchedulePollProcedure(&testPollProcedure, 0.1);\n}\n\n\nstatic bool test2InProgress = false;\nstatic int\t\ttest2Driver;\nstatic int\t\ttest2Socket;\n\nstatic void Test2_Poll(void);\nPollProcedure\ttest2PollProcedure = {NULL, 0.0, Test2_Poll};\n\nstatic void Test2_Poll(void)\n{\n\tstruct qsockaddr clientaddr;\n\tint\t\tcontrol;\n\tint\t\tlen;\n\tchar\tname[256];\n\tchar\tvalue[256];\n\n\tnet_landriverlevel = test2Driver;\n\tname[0] = 0;\n\n\tlen = dfunc.Read (test2Socket, net_message.data, net_message.maxsize, &clientaddr);\n\tif (len < sizeof(int))\n\t\tgoto Reschedule;\n\n\tnet_message.cursize = len;\n\n\tMSG_BeginReading ();\n\tcontrol = BigLong(*((int *)net_message.data));\n\tMSG_ReadLong();\n\tif (control == -1)\n\t\tgoto Error;\n\tif ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)\n\t\tgoto Error;\n\tif ((control & NETFLAG_LENGTH_MASK) != len)\n\t\tgoto Error;\n\n\tif (MSG_ReadByte() != CCREP_RULE_INFO)\n\t\tgoto Error;\n\n\tstrcpy(name, MSG_ReadString());\n\tif (name[0] == 0)\n\t\tgoto Done;\n\tstrcpy(value, MSG_ReadString());\n\n\tCon_Printf(\"%-16.16s  %-16.16s\\n\", name, value);\n\n\tSZ_Clear(&net_message);\n\t// save space for the header, filled in later\n\tMSG_WriteLong(&net_message, 0);\n\tMSG_WriteByte(&net_message, CCREQ_RULE_INFO);\n\tMSG_WriteString(&net_message, name);\n\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\tdfunc.Write (test2Socket, net_message.data, net_message.cursize, &clientaddr);\n\tSZ_Clear(&net_message);\n\nReschedule:\n\tSchedulePollProcedure(&test2PollProcedure, 0.05);\n\treturn;\n\nError:\n\tCon_Printf(\"Unexpected repsonse to Rule Info request\\n\");\nDone:\n\tdfunc.CloseSocket(test2Socket);\n\ttest2InProgress = false;\n\treturn;\n}\n\nstatic void Test2_f (void)\n{\n\tchar\t*host;\n\tint\t\tn;\n\tstruct qsockaddr sendaddr;\n\n\tif (test2InProgress)\n\t\treturn;\n\n\thost = Cmd_Argv (1);\n\n\tif (host && hostCacheCount)\n\t{\n\t\tfor (n = 0; n < hostCacheCount; n++)\n\t\t\tif (strcasecmp (host, hostcache[n].name) == 0)\n\t\t\t{\n\t\t\t\tif (hostcache[n].driver != myDriverLevel)\n\t\t\t\t\tcontinue;\n\t\t\t\tnet_landriverlevel = hostcache[n].ldriver;\n\t\t\t\tmemcpy(&sendaddr, &hostcache[n].addr, sizeof(struct qsockaddr));\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (n < hostCacheCount)\n\t\t\tgoto JustDoIt;\n\t}\n\n\tfor (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)\n\t{\n\t\tif (!net_landrivers[net_landriverlevel].initialized)\n\t\t\tcontinue;\n\n\t\t// see if we can resolve the host name\n\t\tif (dfunc.GetAddrFromName(host, &sendaddr) != -1)\n\t\t\tbreak;\n\t}\n\tif (net_landriverlevel == net_numlandrivers)\n\t\treturn;\n\nJustDoIt:\n\ttest2Socket = dfunc.OpenSocket(0);\n\tif (test2Socket == -1)\n\t\treturn;\n\n\ttest2InProgress = true;\n\ttest2Driver = net_landriverlevel;\n\n\tSZ_Clear(&net_message);\n\t// save space for the header, filled in later\n\tMSG_WriteLong(&net_message, 0);\n\tMSG_WriteByte(&net_message, CCREQ_RULE_INFO);\n\tMSG_WriteString(&net_message, \"\");\n\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\tdfunc.Write (test2Socket, net_message.data, net_message.cursize, &sendaddr);\n\tSZ_Clear(&net_message);\n\tSchedulePollProcedure(&test2PollProcedure, 0.05);\n}\n\nint first_boot = 1;\n\nint Datagram_Init (void)\n{\n\tint i;\n\tint csock;\n\n\tmyDriverLevel = net_driverlevel;\n\tif (first_boot) Cmd_AddCommand (\"net_stats\", NET_Stats_f);\n\n\tif (COM_CheckParm(\"-nolan\"))\n\t\treturn -1;\n\t\n\ti = proto_idx;\n\t//for (i = 0; i < net_numlandrivers; i++)\n\t\t{\n\t\tcsock = net_landrivers[i].Init ();\n\t\tif (csock == -1) return 0;\n\t\t\t//continue;\n\t\tnet_landrivers[i].initialized = true;\n\t\tnet_landrivers[i].controlSock = csock;\n\t\t}\n\t\n\tif (first_boot) {\n#ifdef BAN_TEST\n\t\tCmd_AddCommand (\"ban\", NET_Ban_f);\n#endif\n\t\tCmd_AddCommand (\"test\", Test_f);\n\t\tCmd_AddCommand (\"test2\", Test2_f);\n\t\tfirst_boot = 0;\n\t}\n\n\treturn 0;\n}\n\n\nvoid Datagram_Shutdown (void)\n{\n\tint i;\n\n//\n// shutdown the lan drivers\n//\n\tfor (i = 0; i < net_numlandrivers; i++)\n\t{\n\t\tif (net_landrivers[i].initialized)\n\t\t{\n\t\t\tnet_landrivers[i].Shutdown ();\n\t\t\tnet_landrivers[i].initialized = false;\n\t\t}\n\t}\n}\n\n\nvoid Datagram_Close (qsocket_t *sock)\n{\n\tsfunc.CloseSocket(sock->socket);\n}\n\n\nvoid Datagram_Listen (bool state)\n{\n\tint i;\n\n\tfor (i = 0; i < net_numlandrivers; i++)\n\t\tif (net_landrivers[i].initialized)\n\t\t\tnet_landrivers[i].Listen (state);\n}\n\n\nstatic qsocket_t *_Datagram_CheckNewConnections (void)\n{\n\tstruct qsockaddr clientaddr;\n\tstruct qsockaddr newaddr;\n\tint\t\t\tnewsock;\n\tint\t\t\tacceptsock;\n\tqsocket_t\t*sock;\n\tqsocket_t\t*s;\n\tint\t\t\tlen;\n\tint\t\t\tcommand;\n\tint\t\t\tcontrol;\n\tint\t\t\tret;\n\tbyte\t\tmod, mod_version, mod_flags; // ProQuake\n\n\tacceptsock = dfunc.CheckNewConnections();\n\tif (acceptsock == -1)\n\t\treturn NULL;\n\n\tSZ_Clear(&net_message);\n\n\tlen = dfunc.Read (acceptsock, net_message.data, net_message.maxsize, &clientaddr);\n\tif (len < sizeof(int))\n\t\treturn NULL;\n\tnet_message.cursize = len;\n\n\tMSG_BeginReading ();\n\tcontrol = BigLong(*((int *)net_message.data));\n\tMSG_ReadLong();\n\tif (control == -1)\n\t\treturn NULL;\n\tif ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)\n\t\treturn NULL;\n\tif ((control & NETFLAG_LENGTH_MASK) != len)\n\t\treturn NULL;\n\n\tcommand = MSG_ReadByte();\n\tif (command == CCREQ_SERVER_INFO)\n\t{\n\n\t\tchar name[256];\n\t\tstrcpy(name, hostname.string);\n\n\t\tif (strcmp(MSG_ReadString(), \"QUAKE\") != 0)\n\t\t\treturn NULL;\n\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREP_SERVER_INFO);\n\t\tdfunc.GetSocketAddr(acceptsock, &newaddr);\n\t\tMSG_WriteString(&net_message, dfunc.AddrToString(&newaddr));\n\t\tMSG_WriteString(&net_message, name);\n\t\tMSG_WriteString(&net_message, sv.name);\n\t\tMSG_WriteByte(&net_message, net_activeconnections);\n\t\tMSG_WriteByte(&net_message, svs.maxclients);\n\t\tMSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);\n\t\tSZ_Clear(&net_message);\n\t\treturn NULL;\n\t}\n\n\tif (command == CCREQ_PLAYER_INFO)\n\t{\n\t\tint\t\t\tplayerNumber;\n\t\tint\t\t\tactiveNumber;\n\t\tint\t\t\tclientNumber;\n\t\tclient_t\t*client;\n\t\t\n\t\tplayerNumber = MSG_ReadByte();\n\t\tactiveNumber = -1;\n\t\tfor (clientNumber = 0, client = svs.clients; clientNumber < svs.maxclients; clientNumber++, client++)\n\t\t{\n\t\t\tif (client->active)\n\t\t\t{\n\t\t\t\tactiveNumber++;\n\t\t\t\tif (activeNumber == playerNumber)\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (clientNumber == svs.maxclients)\n\t\t\treturn NULL;\n\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREP_PLAYER_INFO);\n\t\tMSG_WriteByte(&net_message, playerNumber);\n\t\tMSG_WriteString(&net_message, client->name);\n\t\tMSG_WriteLong(&net_message, client->colors);\n\t\tMSG_WriteLong(&net_message, (int)client->edict->v.frags);\n\t\tMSG_WriteLong(&net_message, (int)(net_time - client->netconnection->connecttime));\n\t\tMSG_WriteString(&net_message, client->netconnection->address);\n\t\t\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);\n\t\tSZ_Clear(&net_message);\n\n\t\treturn NULL;\n\t}\n\n\tif (command == CCREQ_RULE_INFO)\n\t{\n\t\tchar\t*prevCvarName;\n\t\tcvar_t\t*var;\n\n\t\t// find the search start location\n\t\tprevCvarName = MSG_ReadString();\n\t\tif (*prevCvarName)\n\t\t{\n\t\t\tvar = Cvar_FindVar (prevCvarName);\n\t\t\tif (!var)\n\t\t\t\treturn NULL;\n\t\t\tvar = var->next;\n\t\t}\n\t\telse\n\t\t\tvar = cvar_vars;\n\n\t\t// search for the next server cvar\n\t\twhile (var)\n\t\t{\n\t\t\tif (var->flags & CVAR_SERVERINFO)\n\t\t\t\tbreak;\n\t\t\tvar = var->next;\n\t\t}\n\n\t\t// send the response\n\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREP_RULE_INFO);\n\t\tif (var)\n\t\t{\n\t\t\tMSG_WriteString(&net_message, var->name);\n\t\t\tMSG_WriteString(&net_message, var->string);\n\t\t}\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);\n\t\tSZ_Clear(&net_message);\n\n\t\treturn NULL;\n\t}\n\n\tif (command != CCREQ_CONNECT)\n\t\treturn NULL;\n\n\tif (strcmp(MSG_ReadString(), \"QUAKE\") != 0)\n\t\treturn NULL;\n\n\tif (MSG_ReadByte() != NET_PROTOCOL_VERSION)\n\t\treturn Datagram_Reject(\"Incompatible version.\\n\", acceptsock, &clientaddr);\n\n#ifdef BAN_TEST\n\t// check for a ban\n\tif (clientaddr.sa_family == AF_INET)\n\t{\n\t\tunsigned long testAddr;\n\t\ttestAddr = ((struct sockaddr_in *)&clientaddr)->sin_addr.s_addr;\n\t\tif ((testAddr & banMask) == banAddr)\n\t\t\treturn Datagram_Reject(\"You have been banned.\\n\", acceptsock, &clientaddr);\n\t}\n#endif\n\n\t// see if this guy is already connected\n\tfor (s = net_activeSockets; s; s = s->next)\n\t{\n\t\tif (s->driver != net_driverlevel)\n\t\t\tcontinue;\n\t\tret = dfunc.AddrCompare(&clientaddr, &s->addr);\n\t\tif (ret >= 0)\n\t\t{\n\t\t\t// is this a duplicate connection reqeust?\n\t\t\tif (ret == 0 && net_time - s->connecttime < 2.0)\n\t\t\t{\n\t\t\t\t// yes, so send a duplicate reply\n\t\t\t\tSZ_Clear(&net_message);\n\t\t\t\t// save space for the header, filled in later\n\t\t\t\tMSG_WriteLong(&net_message, 0);\n\t\t\t\tMSG_WriteByte(&net_message, CCREP_ACCEPT);\n\t\t\t\tdfunc.GetSocketAddr(s->socket, &newaddr);\n\t\t\t\tMSG_WriteLong(&net_message, dfunc.GetSocketPort(&newaddr));\n\t\t\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\t\t\tdfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);\n\t\t\t\tSZ_Clear(&net_message);\n\t\t\t\treturn NULL;\n\t\t\t}\n\t\t\t// it's somebody coming back in from a crash/disconnect\n\t\t\t// so close the old qsocket and let their retry get them back in\n\t\t\t//NET_Close(s);\n\t\t\t//return NULL;\n\t\t}\n\t}\n\n\t// ProQuake additions, passwords, stuffs...\n\tif (len > 12)\n\t\tmod = MSG_ReadByte();\n\telse\n\t\tmod = MOD_NONE;\n\n\tif (len > 13)\n\t\tmod_version = MSG_ReadByte();\n\telse\n\t\tmod_version = 0;\n\n\tif (len > 14)\n\t\tmod_flags = MSG_ReadByte();\n\telse\n\t\tmod_flags = 0;\n\n\t// allocate a QSocket\n\tsock = NET_NewQSocket ();\n\tif (sock == NULL)\n\t\treturn Datagram_Reject(\"Server is full.\\n\", acceptsock, &clientaddr);\n\n\t// allocate a network socket\n\tnewsock = dfunc.OpenSocket(0);\n\tif (newsock == -1)\n\t{\n\t\tNET_FreeQSocket(sock);\n\t\treturn NULL;\n\t}\n\n\t// connect to the client\n\tif (dfunc.Connect (newsock, &clientaddr) == -1)\n\t{\n\t\tdfunc.CloseSocket(newsock);\n\t\tNET_FreeQSocket(sock);\n\t\treturn NULL;\n\t}\n\n\t// everything is allocated, just fill in the details\t\n\t// JPG - support for mods\n\tsock->proquake_connection = mod;\n\tsock->proquake_version = mod_version;\n\tsock->proquake_flags = mod_flags;\n\tif (mod == MOD_PROQUAKE && mod_version >= 34)\t// ProQuake 3.40\n\t\tsock->net_wait = true;\n\n\tsock->socket = newsock;\n\tsock->landriver = net_landriverlevel;\n\tsock->addr = clientaddr;\n\tstrcpy(sock->address, dfunc.AddrToString(&clientaddr));\n\n\t// send him back the info about the server connection he has been allocated\n\tSZ_Clear(&net_message);\n\t// save space for the header, filled in later\n\tMSG_WriteLong(&net_message, 0);\n\tMSG_WriteByte(&net_message, CCREP_ACCEPT);\n\tdfunc.GetSocketAddr(newsock, &newaddr);\n\tsock->client_port = dfunc.GetSocketPort(&newaddr);\n\tMSG_WriteLong(&net_message, sock->client_port);\n\tMSG_WriteByte(&net_message, MOD_PROQUAKE); // JPG - added this\n\tMSG_WriteByte(&net_message, VERSION_PROQUAKE * 10); // JPG 3.00\n\n\tMSG_WriteByte(&net_message, 0);\n\n\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\tdfunc.Write (acceptsock, net_message.data, net_message.cursize, &clientaddr);\n\tSZ_Clear(&net_message);\n\n\treturn sock;\n}\n\nqsocket_t *Datagram_CheckNewConnections (void)\n{\n\tqsocket_t *ret = NULL;\n\n\tfor (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)\n\t\tif (net_landrivers[net_landriverlevel].initialized)\n\t\t\tif ((ret = _Datagram_CheckNewConnections ()) != NULL)\n\t\t\t\tbreak;\n\treturn ret;\n}\n\n\nstatic void _Datagram_SearchForHosts (bool xmit)\n{\n\tint\t\tret;\n\tint\t\tn;\n\tint\t\ti;\n\tstruct qsockaddr readaddr;\n\tstruct qsockaddr myaddr;\n\tint\t\tcontrol;\n\n\tdfunc.GetSocketAddr (dfunc.controlSock, &myaddr);\n\tif (xmit)\n\t{\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREQ_SERVER_INFO);\n\t\tMSG_WriteString(&net_message, \"QUAKE\");\n\t\tMSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Broadcast(dfunc.controlSock, net_message.data, net_message.cursize);\n\t\tSZ_Clear(&net_message);\n\t}\n\n\twhile ((ret = dfunc.Read (dfunc.controlSock, net_message.data, net_message.maxsize, &readaddr)) > 0)\n\t{\n\t\tif (ret < sizeof(int))\n\t\t\tcontinue;\n\t\tnet_message.cursize = ret;\n\n\t\t// don't answer our own query\n\t\tif (dfunc.AddrCompare(&readaddr, &myaddr) >= 0)\n\t\t\tcontinue;\n\n\t\t// is the cache full?\n\t\tif (hostCacheCount == HOSTCACHESIZE)\n\t\t\tcontinue;\n\n\t\tMSG_BeginReading ();\n\t\tcontrol = BigLong(*((int *)net_message.data));\n\t\tMSG_ReadLong();\n\t\tif (control == -1)\n\t\t\tcontinue;\n\t\tif ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)\n\t\t\tcontinue;\n\t\tif ((control & NETFLAG_LENGTH_MASK) != ret)\n\t\t\tcontinue;\n\n\t\tif (MSG_ReadByte() != CCREP_SERVER_INFO)\n\t\t\tcontinue;\n\n\t\tdfunc.GetAddrFromName(MSG_ReadString(), &readaddr);\n\t\t// search the cache for this server\n\t\tfor (n = 0; n < hostCacheCount; n++)\n\t\t\tif (dfunc.AddrCompare(&readaddr, &hostcache[n].addr) == 0)\n\t\t\t\tbreak;\n\n\t\t// is it already there?\n\t\tif (n < hostCacheCount)\n\t\t\tcontinue;\n\n\t\t// add it\n\t\thostCacheCount++;\n\t\tstrcpy(hostcache[n].name, MSG_ReadString());\n\t\tstrcpy(hostcache[n].map, MSG_ReadString());\n\t\thostcache[n].users = MSG_ReadByte();\n\t\thostcache[n].maxusers = MSG_ReadByte();\n\t\tif (MSG_ReadByte() != NET_PROTOCOL_VERSION)\n\t\t{\n\t\t\tstrcpy(hostcache[n].cname, hostcache[n].name);\n\t\t\thostcache[n].cname[14] = 0;\n\t\t\tstrcpy(hostcache[n].name, \"*\");\n\t\t\tstrcat(hostcache[n].name, hostcache[n].cname);\n\t\t}\n\t\tmemcpy(&hostcache[n].addr, &readaddr, sizeof(struct qsockaddr));\n\t\thostcache[n].driver = net_driverlevel;\n\t\thostcache[n].ldriver = net_landriverlevel;\n\t\tstrcpy(hostcache[n].cname, dfunc.AddrToString(&readaddr));\n\n\t\t// check for a name conflict\n\t\tfor (i = 0; i < hostCacheCount; i++)\n\t\t{\n\t\t\tif (i == n)\n\t\t\t\tcontinue;\n\t\t\tif (strcasecmp (hostcache[n].name, hostcache[i].name) == 0)\n\t\t\t{\n\t\t\t\ti = strlen(hostcache[n].name);\n\t\t\t\tif (i < 15 && hostcache[n].name[i-1] > '8')\n\t\t\t\t{\n\t\t\t\t\thostcache[n].name[i] = '0';\n\t\t\t\t\thostcache[n].name[i+1] = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\thostcache[n].name[i-1]++;\n\t\t\t\ti = -1;\n\t\t\t}\n\t\t}\n\t}\n}\n\nvoid Datagram_SearchForHosts (bool xmit)\n{\n\tfor (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)\n\t{\n\t\tif (hostCacheCount == HOSTCACHESIZE)\n\t\t\tbreak;\n\t\tif (net_landrivers[net_landriverlevel].initialized)\n\t\t\t_Datagram_SearchForHosts (xmit);\n\t}\n}\n\nstatic qsocket_t *_Datagram_Connect (char *host)\n{\n\tstruct qsockaddr sendaddr;\n\tstruct qsockaddr readaddr;\n\tqsocket_t\t*sock;\n\tint\t\t\tnewsock;\n\tint\t\t\tret;\n\tint\t\t\treps;\n\tdouble\t\tstart_time;\n\tint\t\t\tcontrol;\n\tchar\t\t*reason;\n\n\t// see if we can resolve the host name\n\tif (dfunc.GetAddrFromName(host, &sendaddr) == -1)\n\t\treturn NULL;\n\n\tnewsock = dfunc.OpenSocket (0);\n\tif (newsock == -1)\n\t\treturn NULL;\n\n\tsock = NET_NewQSocket ();\n\tif (sock == NULL)\n\t\tgoto ErrorReturn2;\n\tsock->socket = newsock;\n\tsock->landriver = net_landriverlevel;\n\n\t// connect to the host\n\tif (dfunc.Connect (newsock, &sendaddr) == -1)\n\t\tgoto ErrorReturn;\n\n\t// send the connection request\n\tCon_Printf(\"trying...\\n\"); SCR_UpdateScreen ();\n\tstart_time = net_time;\n\n\tfor (reps = 0; reps < 3; reps++)\n\t{\n\t\tSZ_Clear(&net_message);\n\t\t// save space for the header, filled in later\n\t\tMSG_WriteLong(&net_message, 0);\n\t\tMSG_WriteByte(&net_message, CCREQ_CONNECT);\n\t\tMSG_WriteString(&net_message, \"QUAKE\");\n\t\tMSG_WriteByte(&net_message, NET_PROTOCOL_VERSION);\n\n\t\t// We are telling to the server we are using ProQuake, for compatibility purposes.\n\t\tMSG_WriteByte(&net_message, MOD_PROQUAKE);\t\t\t// Flag telling our client is ProQuake.\n\t\tMSG_WriteByte(&net_message, VERSION_PROQUAKE * 10); // Version used of ProQuake.\n\t\tMSG_WriteByte(&net_message, 0);\t\t\t\t\t\t// Connection Flags (3.0)\n\t\tMSG_WriteLong(&net_message, pq_password.value);\t\t// Password (ProQuake 3.0)\n\t\t//MSG_WriteByte(&net_message, 1);\t\t\t\t\t// Ch0wW: Added a byte to tell we're on a console (\n\t\t\n\t\t*((int *)net_message.data) = BigLong(NETFLAG_CTL | (net_message.cursize & NETFLAG_LENGTH_MASK));\n\t\tdfunc.Write (newsock, net_message.data, net_message.cursize, &sendaddr);\n\t\tSZ_Clear(&net_message);\n\t\tdo\n\t\t{\n\t\t\tret = dfunc.Read (newsock, net_message.data, net_message.maxsize, &readaddr);\n\t\t\t// if we got something, validate it\n\t\t\tif (ret > 0)\n\t\t\t{\n\t\t\t\t// is it from the right place?\n\t\t\t\tif (sfunc.AddrCompare(&readaddr, &sendaddr) != 0)\n\t\t\t\t{\n#ifdef DEBUG\n\t\t\t\t\tCon_Printf(\"wrong reply address\\n\");\n\t\t\t\t\tCon_Printf(\"Expected: %s\\n\", StrAddr (&sendaddr));\n\t\t\t\t\tCon_Printf(\"Received: %s\\n\", StrAddr (&readaddr));\n\t\t\t\t\tSCR_UpdateScreen ();\n#endif\n\t\t\t\t\tret = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (ret < sizeof(int))\n\t\t\t\t{\n\t\t\t\t\tret = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tnet_message.cursize = ret;\n\t\t\t\tMSG_BeginReading ();\n\n\t\t\t\tcontrol = BigLong(*((int *)net_message.data));\n\t\t\t\tMSG_ReadLong();\n\t\t\t\tif (control == -1)\n\t\t\t\t{\n\t\t\t\t\tret = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif ((control & (~NETFLAG_LENGTH_MASK)) !=  NETFLAG_CTL)\n\t\t\t\t{\n\t\t\t\t\tret = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif ((control & NETFLAG_LENGTH_MASK) != ret)\n\t\t\t\t{\n\t\t\t\t\tret = 0;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\twhile (ret == 0 && (SetNetTime() - start_time) < 2.5);\n\t\tif (ret)\n\t\t\tbreak;\n\t\tCon_Printf(\"still trying...\\n\"); SCR_UpdateScreen ();\n\t\tstart_time = SetNetTime();\n\t}\n\n\tif (ret == 0)\n\t{\n\t\treason = \"No Response\";\n\t\tCon_Printf(\"%s\\n\", reason);\n\t\tstrcpy(m_return_reason, reason);\n\t\tgoto ErrorReturn;\n\t}\n\n\tif (ret == -1)\n\t{\n\t\treason = \"Network Error\";\n\t\tCon_Printf(\"%s\\n\", reason);\n\t\tstrcpy(m_return_reason, reason);\n\t\tgoto ErrorReturn;\n\t}\n\n\tint len = ret;\n\tret = MSG_ReadByte();\n\tif (ret == CCREP_REJECT)\n\t{\n\t\treason = MSG_ReadString();\n\t\tCon_Printf(reason);\n\t\tstrncpy(m_return_reason, reason, 31);\n\t\tgoto ErrorReturn;\n\t}\n\n\tif (ret == CCREP_ACCEPT)\n\t{\n\t\tsock->client_port = MSG_ReadLong();\t// ProQuake: Change the port.\n\t\tmemcpy(&sock->addr, &sendaddr, sizeof(struct qsockaddr));\n\t\tdfunc.SetSocketPort(&sock->addr, sock->client_port);\n\t\t\n\t//Con_Printf (\"Client port is %s\\n\", dfunc.AddrToString(&sock->addr));\n\t// Client has received CCREP_ACCEPT meaning client may connect\n\t// Now find out if this is a ProQuake server ...\n\n\t// ProQuake -- Looking for what kind of mod it is using\n\tif (len > 9)\n\t\tsock->proquake_connection = MSG_ReadByte();\n\telse\n\t\tsock->proquake_connection = MOD_NONE;\n\t\n\t// ProQuake -- Looking for the version the server uses \n\tif (len > 10)\n\t\tsock->proquake_version = MSG_ReadByte();\n\telse\n\t\tsock->proquake_version = 0;\n\n\tif (len > 11)\n\t\tsock->proquake_flags = MSG_ReadByte();\n\telse\n\t\tsock->proquake_flags = 0;\n\n\t}\n\telse\n\t{\n\t\treason = \"Bad Response\";\n\t\tCon_Printf(\"%s\\n\", reason);\n\t\tstrcpy(m_return_reason, reason);\n\t\tgoto ErrorReturn;\n\t}\n\n\tdfunc.GetNameFromAddr (&sendaddr, sock->address);\n\n\tCon_Printf (\"Connection accepted\\n\");\n\tsock->lastMessageTime = SetNetTime();\n\t\n\t// switch the connection to the specified address\n\tif (dfunc.Connect (newsock, &sock->addr) == -1)\n\t{\n\t\treason = \"Connect to Game failed\";\n\t\tCon_Printf(\"%s\\n\", reason);\n\t\tstrcpy(m_return_reason, reason);\n\t\tgoto ErrorReturn;\n\t}\n\n\tm_return_onerror = false;\n\treturn sock;\n\nErrorReturn:\n\tNET_FreeQSocket(sock);\nErrorReturn2:\n\tdfunc.CloseSocket(newsock);\n\tif (m_return_onerror)\n\t{\n\t\tkey_dest = key_menu;\n\t\tm_state = m_return_state;\n\t\tm_return_onerror = false;\n\t}\n\treturn NULL;\n}\n\nqsocket_t *Datagram_Connect (char *host)\n{\n\tqsocket_t *ret = NULL;\n\n\tStrip_Port(host);\n\tfor (net_landriverlevel = 0; net_landriverlevel < net_numlandrivers; net_landriverlevel++)\n\t\tif (net_landrivers[net_landriverlevel].initialized)\n\t\t\tif ((ret = _Datagram_Connect (host)) != NULL)\n\t\t\t\tbreak;\n\treturn ret;\n}\n"
  },
  {
    "path": "source/net_dgrm.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_dgrm.h\n\nextern uint8_t proto_idx;\nint\t\t\tDatagram_Init (void);\nvoid\t\tDatagram_Listen (bool state);\nvoid\t\tDatagram_SearchForHosts (bool xmit);\nqsocket_t\t*Datagram_Connect (char *host);\nqsocket_t \t*Datagram_CheckNewConnections (void);\nint\t\t\tDatagram_GetMessage (qsocket_t *sock);\nint\t\t\tDatagram_SendMessage (qsocket_t *sock, sizebuf_t *data);\nint\t\t\tDatagram_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);\nbool\tDatagram_CanSendMessage (qsocket_t *sock);\nbool\tDatagram_CanSendUnreliableMessage (qsocket_t *sock);\nvoid\t\tDatagram_Close (qsocket_t *sock);\nvoid\t\tDatagram_Shutdown (void);\n"
  },
  {
    "path": "source/net_loop.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_loop.c\n\n#include \"quakedef.h\"\n#include \"net_loop.h\"\n\nbool\tlocalconnectpending = false;\nqsocket_t\t*loop_client = NULL;\nqsocket_t\t*loop_server = NULL;\n\nint Loop_Init (void)\n{\n\tif (cls.state == ca_dedicated)\n\t\treturn -1;\n\treturn 0;\n}\n\n\nvoid Loop_Shutdown (void)\n{\n}\n\n\nvoid Loop_Listen (bool state)\n{\n}\n\n\nvoid Loop_SearchForHosts (bool xmit)\n{\n\tif (!sv.active)\n\t\treturn;\n\n\thostCacheCount = 1;\n\tif (strcmp(hostname.string, \"UNNAMED\") == 0)\n\t\tstrcpy(hostcache[0].name, \"local\");\n\telse\n\t\tstrcpy(hostcache[0].name, hostname.string);\n\tstrcpy(hostcache[0].map, sv.name);\n\thostcache[0].users = net_activeconnections;\n\thostcache[0].maxusers = svs.maxclients;\n\thostcache[0].driver = net_driverlevel;\n\tstrcpy(hostcache[0].cname, \"local\");\n}\n\n\nqsocket_t *Loop_Connect (char *host)\n{\n\tif (strcmp(host,\"local\") != 0)\n\t\treturn NULL;\n\t\n\tlocalconnectpending = true;\n\n\tif (!loop_client)\n\t{\n\t\tif (!(loop_client = NET_NewQSocket ()))\n\t\t{\n\t\t\tCon_Printf(\"Loop_Connect: no qsocket available\\n\");\n\t\t\treturn NULL;\n\t\t}\n\t\tstrcpy (loop_client->address, \"localhost\");\n\t}\n\tloop_client->receiveMessageLength = 0;\n\tloop_client->sendMessageLength = 0;\n\tloop_client->canSend = true;\n\tloop_client->proquake_connection = MOD_PROQUAKE;\n\tloop_client->client_port = 0;\n\n\tif (!loop_server)\n\t{\n\t\tif (!(loop_server = NET_NewQSocket ()))\n\t\t{\n\t\t\tCon_Printf(\"Loop_Connect: no qsocket available\\n\");\n\t\t\treturn NULL;\n\t\t}\n\t\tstrcpy (loop_server->address, \"LOCAL\");\n\t}\n\tloop_server->receiveMessageLength = 0;\n\tloop_server->sendMessageLength = 0;\n\tloop_server->canSend = true;\n\tloop_server->proquake_connection = MOD_PROQUAKE;\n\tloop_server->client_port = 0;\n\n\tloop_client->driverdata = (void *)loop_server;\n\tloop_server->driverdata = (void *)loop_client;\n\t\n\treturn loop_client;\t\n}\n\n\nqsocket_t *Loop_CheckNewConnections (void)\n{\n\tif (!localconnectpending)\n\t\treturn NULL;\n\n\tlocalconnectpending = false;\n\tloop_server->sendMessageLength = 0;\n\tloop_server->receiveMessageLength = 0;\n\tloop_server->canSend = true;\n\tloop_client->sendMessageLength = 0;\n\tloop_client->receiveMessageLength = 0;\n\tloop_client->canSend = true;\n\treturn loop_server;\n}\n\n\nstatic int IntAlign(int value)\n{\n\treturn (value + (sizeof(int) - 1)) & (~(sizeof(int) - 1));\n}\n\n\nint Loop_GetMessage (qsocket_t *sock)\n{\n\tint\t\tret;\n\tint\t\tlength;\n\n\tif (sock->receiveMessageLength == 0)\n\t\treturn 0;\n\n\tret = sock->receiveMessage[0];\n\tlength = sock->receiveMessage[1] + (sock->receiveMessage[2] << 8);\n\t// alignment byte skipped here\n\tSZ_Clear (&net_message);\n\tSZ_Write (&net_message, &sock->receiveMessage[4], length);\n\n\tlength = IntAlign(length + 4);\n\tsock->receiveMessageLength -= length;\n\n\tif (sock->receiveMessageLength)\n\t\tmemcpy(sock->receiveMessage, &sock->receiveMessage[length], sock->receiveMessageLength);\n\n\tif (sock->driverdata && ret == 1)\n\t\t((qsocket_t *)sock->driverdata)->canSend = true;\n\n\treturn ret;\n}\n\n\nint Loop_SendMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tbyte *buffer;\n\tint  *bufferLength;\n\n\tif (!sock->driverdata)\n\t\treturn -1;\n\n\tbufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;\n\n\tif ((*bufferLength + data->cursize + 4) > NET_MAXMESSAGE)\n\t\tSys_Error(\"Loop_SendMessage: overflow\\n\");\n\n\tbuffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;\n\n\t// message type\n\t*buffer++ = 1;\n\n\t// length\n\t*buffer++ = data->cursize & 0xff;\n\t*buffer++ = data->cursize >> 8;\n\n\t// align\n\tbuffer++;\n\n\t// message\n\tmemcpy(buffer, data->data, data->cursize);\n\t*bufferLength = IntAlign(*bufferLength + data->cursize + 4);\n\n\tsock->canSend = false;\n\treturn 1;\n}\n\n\nint Loop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tbyte *buffer;\n\tint  *bufferLength;\n\n\tif (!sock->driverdata)\n\t\treturn -1;\n\n\tbufferLength = &((qsocket_t *)sock->driverdata)->receiveMessageLength;\n\n\tif ((*bufferLength + data->cursize + sizeof(byte) + sizeof(short)) > NET_MAXMESSAGE)\n\t\treturn 0;\n\n\tbuffer = ((qsocket_t *)sock->driverdata)->receiveMessage + *bufferLength;\n\n\t// message type\n\t*buffer++ = 2;\n\n\t// length\n\t*buffer++ = data->cursize & 0xff;\n\t*buffer++ = data->cursize >> 8;\n\n\t// align\n\tbuffer++;\n\n\t// message\n\tmemcpy(buffer, data->data, data->cursize);\n\t*bufferLength = IntAlign(*bufferLength + data->cursize + 4);\n\treturn 1;\n}\n\n\nbool Loop_CanSendMessage (qsocket_t *sock)\n{\n\tif (!sock->driverdata)\n\t\treturn false;\n\treturn sock->canSend;\n}\n\n\nbool Loop_CanSendUnreliableMessage (qsocket_t *sock)\n{\n\treturn true;\n}\n\n\nvoid Loop_Close (qsocket_t *sock)\n{\n\tif (sock->driverdata)\n\t\t((qsocket_t *)sock->driverdata)->driverdata = NULL;\n\tsock->receiveMessageLength = 0;\n\tsock->sendMessageLength = 0;\n\tsock->canSend = true;\n\tif (sock == loop_client)\n\t\tloop_client = NULL;\n\telse\n\t\tloop_server = NULL;\n}\n"
  },
  {
    "path": "source/net_loop.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_loop.h\n\nint\t\t\tLoop_Init (void);\nvoid\t\tLoop_Listen (bool state);\nvoid\t\tLoop_SearchForHosts (bool xmit);\nqsocket_t \t*Loop_Connect (char *host);\nqsocket_t \t*Loop_CheckNewConnections (void);\nint\t\t\tLoop_GetMessage (qsocket_t *sock);\nint\t\t\tLoop_SendMessage (qsocket_t *sock, sizebuf_t *data);\nint\t\t\tLoop_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data);\nbool\tLoop_CanSendMessage (qsocket_t *sock);\nbool\tLoop_CanSendUnreliableMessage (qsocket_t *sock);\nvoid\t\tLoop_Close (qsocket_t *sock);\nvoid\t\tLoop_Shutdown (void);\n"
  },
  {
    "path": "source/net_main.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_main.c\n\n#include \"quakedef.h\"\n#include \"net_vcr.h\"\n\nCVAR (net_messagetimeout, 300, CVAR_NONE)\nCVAR (hostname, \"UNNAMED\", CVAR_ARCHIVE)\n\nCVAR (pq_password, \"\", CVAR_NONE)\t// ProQuake 3 behaviour\n\nchar\tserver_name[MAX_QPATH];\n//----------------------------------------------\n\nqsocket_t\t*net_activeSockets = NULL;\nqsocket_t\t*net_freeSockets = NULL;\nint\t\t\tnet_numsockets = 0;\n\nbool\ttcpipAvailable = false;\n\nint\t\t\tnet_hostport;\nint\t\t\tDEFAULTnet_hostport = 26000;\n\nchar\t\tmy_tcpip_address[NET_NAMELEN];\n\nstatic bool\tlistening = false;\n\nbool\tslistInProgress = false;\nbool\tslistSilent = false;\nbool\tslistLocal = true;\nstatic double\tslistStartTime;\nstatic int\t\tslistLastShown;\n\nstatic void Slist_Send(void);\nstatic void Slist_Poll(void);\nPollProcedure\tslistSendProcedure = {NULL, 0.0, Slist_Send};\nPollProcedure\tslistPollProcedure = {NULL, 0.0, Slist_Poll};\n\n\nsizebuf_t\t\tnet_message;\nint\t\t\t\tnet_activeconnections = 0;\n\nint messagesSent = 0;\nint messagesReceived = 0;\nint unreliableMessagesSent = 0;\nint unreliableMessagesReceived = 0;\n\n#ifdef IDGODS\ncvar_t\tidgods = {\"idgods\", \"0\"};\n#endif\n\nint\tvcrFile = -1;\nbool recording = false;\n\n// these two macros are to make the code more readable\n#define sfunc\tnet_drivers[sock->driver]\n#define dfunc\tnet_drivers[net_driverlevel]\n\nint\tnet_driverlevel;\n\n\ndouble\t\t\tnet_time;\n\ndouble SetNetTime(void)\n{\n\tnet_time = Sys_FloatTime();\n\treturn net_time;\n}\n\n/*\n===================\nNET_NewQSocket\n\nCalled by drivers when a new communications endpoint is required\nThe sequence and buffer fields will be filled in properly\n===================\n*/\nqsocket_t *NET_NewQSocket (void)\n{\n\tqsocket_t\t*sock;\n\n\tif (net_freeSockets == NULL)\n\t\treturn NULL;\n\n\tif (net_activeconnections >= svs.maxclients)\n\t\treturn NULL;\n\n\t// get one from free list\n\tsock = net_freeSockets;\n\tnet_freeSockets = sock->next;\n\n\t// add it to active list\n\tsock->next = net_activeSockets;\n\tnet_activeSockets = sock;\n\n\tsock->disconnected = false;\n\tsock->connecttime = net_time;\n\tstrcpy (sock->address,\"UNSET ADDRESS\");\n\tsock->driver = net_driverlevel;\n\tsock->socket = 0;\n\tsock->driverdata = NULL;\n\tsock->canSend = true;\n\tsock->sendNext = false;\n\tsock->lastMessageTime = net_time;\n\tsock->ackSequence = 0;\n\tsock->sendSequence = 0;\n\tsock->unreliableSendSequence = 0;\n\tsock->sendMessageLength = 0;\n\tsock->receiveSequence = 0;\n\tsock->unreliableReceiveSequence = 0;\n\tsock->receiveMessageLength = 0;\n\n\treturn sock;\n}\n\n\nvoid NET_FreeQSocket(qsocket_t *sock)\n{\n\tqsocket_t\t*s;\n\n\t// remove it from active list\n\tif (sock == net_activeSockets)\n\t\tnet_activeSockets = net_activeSockets->next;\n\telse\n\t{\n\t\tfor (s = net_activeSockets; s; s = s->next)\n\t\t\tif (s->next == sock)\n\t\t\t{\n\t\t\t\ts->next = sock->next;\n\t\t\t\tbreak;\n\t\t\t}\n\t\tif (!s)\n\t\t\tSys_Error (\"NET_FreeQSocket: not active\\n\");\n\t}\n\n\t// add it to free list\n\tsock->next = net_freeSockets;\n\tnet_freeSockets = sock;\n\tsock->disconnected = true;\n}\n\n\nstatic void NET_Listen_f (void)\n{\n\tif (Cmd_Argc () != 2)\n\t{\n\t\tCon_Printf (\"\\\"listen\\\" is \\\"%u\\\"\\n\", listening ? 1 : 0);\n\t\treturn;\n\t}\n\n\tlistening = atoi(Cmd_Argv(1)) ? true : false;\n\n\tfor (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)\n\t{\n\t\tif (net_drivers[net_driverlevel].initialized == false)\n\t\t\tcontinue;\n\t\tdfunc.Listen (listening);\n\t}\n}\n\n\nstatic void MaxPlayers_f (void)\n{\n\tint \tn;\n\n\tif (Cmd_Argc () != 2)\n\t{\n\t\tCon_Printf (\"\\\"maxplayers\\\" is \\\"%u\\\"\\n\", svs.maxclients);\n\t\treturn;\n\t}\n\n\tif (sv.active)\n\t{\n\t\tCon_Printf (\"maxplayers can not be changed while a server is running.\\n\");\n\t\treturn;\n\t}\n\n\tn = atoi(Cmd_Argv(1));\n\tif (n < 1)\n\t\tn = 1;\n\tif (n > svs.maxclientslimit)\n\t{\n\t\tn = svs.maxclientslimit;\n\t\tCon_Printf (\"\\\"maxplayers\\\" set to \\\"%u\\\"\\n\", n);\n\t}\n\n\tif ((n == 1) && listening)\n\t\tCbuf_AddText (\"listen 0\\n\");\n\n\tif ((n > 1) && (!listening))\n\t\tCbuf_AddText (\"listen 1\\n\");\n\n\tsvs.maxclients = n;\n\tif (n == 1)\n\t\tCvar_Set (\"deathmatch\", \"0\");\n\telse\n\t\tCvar_Set (\"deathmatch\", \"1\");\n}\n\n\nstatic void NET_Port_f (void)\n{\n\tint \tn;\n\n\tif (Cmd_Argc () != 2)\n\t{\n\t\tCon_Printf (\"\\\"port\\\" is \\\"%u\\\"\\n\", net_hostport);\n\t\treturn;\n\t}\n\n\tn = atoi(Cmd_Argv(1));\n\tif (n < 1 || n > 65534)\n\t{\n\t\tCon_Printf (\"Bad value, must be between 1 and 65534\\n\");\n\t\treturn;\n\t}\n\n\tDEFAULTnet_hostport = n;\n\tnet_hostport = n;\n\n\tif (listening)\n\t{\n\t\t// force a change to the new port\n\t\tCbuf_AddText (\"listen 0\\n\");\n\t\tCbuf_AddText (\"listen 1\\n\");\n\t}\n}\n\n\nstatic void PrintSlistHeader(void)\n{\n\tCon_Printf(\"Server          Map             Users\\n\");\n\tCon_Printf(\"--------------- --------------- -----\\n\");\n\tslistLastShown = 0;\n}\n\n\nstatic void PrintSlist(void)\n{\n\tint n;\n\n\tfor (n = slistLastShown; n < hostCacheCount; n++)\n\t{\n\t\tif (hostcache[n].maxusers)\n\t\t\tCon_Printf(\"%-15.15s %-15.15s %2u/%2u\\n\", hostcache[n].name, hostcache[n].map, hostcache[n].users, hostcache[n].maxusers);\n\t\telse\n\t\t\tCon_Printf(\"%-15.15s %-15.15s\\n\", hostcache[n].name, hostcache[n].map);\n\t}\n\tslistLastShown = n;\n}\n\n\nstatic void PrintSlistTrailer(void)\n{\n\tif (hostCacheCount)\n\t\tCon_Printf(\"== end list ==\\n\\n\");\n\telse\n\t\tCon_Printf(\"No Quake servers found.\\n\\n\");\n}\n\n\nvoid NET_Slist_f (void)\n{\n\tif (slistInProgress)\n\t\treturn;\n\n\tif (! slistSilent)\n\t{\n\t\tCon_Printf(\"Looking for Quake servers...\\n\");\n\t\tPrintSlistHeader();\n\t}\n\n\tslistInProgress = true;\n\tslistStartTime = Sys_FloatTime();\n\n\tSchedulePollProcedure(&slistSendProcedure, 0.0);\n\tSchedulePollProcedure(&slistPollProcedure, 0.1);\n\n\thostCacheCount = 0;\n}\n\n\nstatic void Slist_Send(void)\n{\n\tfor (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)\n\t{\n\t\tif (!slistLocal && net_driverlevel == 0)\n\t\t\tcontinue;\n\t\tif (net_drivers[net_driverlevel].initialized == false)\n\t\t\tcontinue;\n\t\tdfunc.SearchForHosts (true);\n\t}\n\n\tif ((Sys_FloatTime() - slistStartTime) < 0.5)\n\t\tSchedulePollProcedure(&slistSendProcedure, 0.75);\n}\n\n\nstatic void Slist_Poll(void)\n{\n\tfor (net_driverlevel=0; net_driverlevel < net_numdrivers; net_driverlevel++)\n\t{\n\t\tif (!slistLocal && net_driverlevel == 0)\n\t\t\tcontinue;\n\t\tif (net_drivers[net_driverlevel].initialized == false)\n\t\t\tcontinue;\n\t\tdfunc.SearchForHosts (false);\n\t}\n\n\tif (! slistSilent)\n\t\tPrintSlist();\n\n\tif ((Sys_FloatTime() - slistStartTime) < 1.5)\n\t{\n\t\tSchedulePollProcedure(&slistPollProcedure, 0.1);\n\t\treturn;\n\t}\n\n\tif (! slistSilent)\n\t\tPrintSlistTrailer();\n\tslistInProgress = false;\n\tslistSilent = false;\n\tslistLocal = true;\n}\n\n\n/*\n===================\nNET_Connect\n===================\n*/\n\nint hostCacheCount = 0;\nhostcache_t hostcache[HOSTCACHESIZE];\n\nqsocket_t *NET_Connect (char *host)\n{\n\tqsocket_t\t\t*ret;\n\tint\t\t\t\tn;\n\tint\t\t\t\tnumdrivers = net_numdrivers;\n\n\tSetNetTime();\n\n\tif (host && *host == 0)\n\t\thost = NULL;\n\n\tif (host)\n\t{\n\t\tif (strcasecmp (host, \"local\") == 0)\n\t\t{\n\t\t\tnumdrivers = 1;\n\t\t\tgoto JustDoIt;\n\t\t}\n\n\t\tif (hostCacheCount)\n\t\t{\n\t\t\tfor (n = 0; n < hostCacheCount; n++)\n\t\t\t\tif (strcasecmp (host, hostcache[n].name) == 0)\n\t\t\t\t{\n\t\t\t\t\thost = hostcache[n].cname;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\tif (n < hostCacheCount)\n\t\t\t\tgoto JustDoIt;\n\t\t}\n\t}\n\n\tslistSilent = host ? true : false;\n\tNET_Slist_f ();\n\n\twhile(slistInProgress)\n\t\tNET_Poll();\n\n\tif (host == NULL)\n\t{\n\t\tif (hostCacheCount != 1)\n\t\t\treturn NULL;\n\t\thost = hostcache[0].cname;\n\t\tCon_Printf(\"Connecting to...\\n%s @ %s\\n\\n\", hostcache[0].name, host);\n\t}\n\n\tif (hostCacheCount)\n\t\tfor (n = 0; n < hostCacheCount; n++)\n\t\t\tif (strcasecmp (host, hostcache[n].name) == 0)\n\t\t\t{\n\t\t\t\thost = hostcache[n].cname;\n\t\t\t\tbreak;\n\t\t\t}\n\nJustDoIt:\n\tfor (net_driverlevel=0 ; net_driverlevel<numdrivers; net_driverlevel++)\n\t{\n\t\tif (net_drivers[net_driverlevel].initialized == false)\n\t\t\tcontinue;\n\t\tret = dfunc.Connect (host);\n\t\tif (ret)\n\t\t\treturn ret;\n\t}\n\n\tif (host)\n\t{\n\t\tCon_Printf(\"\\n\");\n\t\tPrintSlistHeader();\n\t\tPrintSlist();\n\t\tPrintSlistTrailer();\n\t}\n\t\n\treturn NULL;\n}\n\n\n/*\n===================\nNET_CheckNewConnections\n===================\n*/\n\nstruct\n{\n\tdouble\ttime;\n\tint\t\top;\n\tlong\tsession;\n} vcrConnect;\n\nqsocket_t *NET_CheckNewConnections (void)\n{\n\tqsocket_t\t*ret;\n\n\tSetNetTime();\n\n\tfor (net_driverlevel=0 ; net_driverlevel<net_numdrivers; net_driverlevel++)\n\t{\n\t\tif (net_drivers[net_driverlevel].initialized == false)\n\t\t\tcontinue;\n\t\tif (net_driverlevel && listening == false)\n\t\t\tcontinue;\n\t\tret = dfunc.CheckNewConnections ();\n\t\tif (ret)\n\t\t{\n\t\t\tif (recording)\n\t\t\t{\n\t\t\t\tvcrConnect.time = host_time;\n\t\t\t\tvcrConnect.op = VCR_OP_CONNECT;\n\t\t\t\tvcrConnect.session = (long)ret;\n\t\t\t\tSys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));\n\t\t\t\tSys_FileWrite (vcrFile, ret->address, NET_NAMELEN);\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t}\n\t\n\tif (recording)\n\t{\n\t\tvcrConnect.time = host_time;\n\t\tvcrConnect.op = VCR_OP_CONNECT;\n\t\tvcrConnect.session = 0;\n\t\tSys_FileWrite (vcrFile, &vcrConnect, sizeof(vcrConnect));\n\t}\n\n\treturn NULL;\n}\n\n/*\n===================\nNET_Close\n===================\n*/\nvoid NET_Close (qsocket_t *sock)\n{\n\tif (!sock)\n\t\treturn;\n\n\tif (sock->disconnected)\n\t\treturn;\n\n\tSetNetTime();\n\n\t// call the driver_Close function\n\tsfunc.Close (sock);\n\n\tNET_FreeQSocket(sock);\n}\n\n\n/*\n=================\nNET_GetMessage\n\nIf there is a complete message, return it in net_message\n\nreturns 0 if no data is waiting\nreturns 1 if a message was received\nreturns -1 if connection is invalid\n=================\n*/\n\nstruct\n{\n\tdouble\ttime;\n\tint\t\top;\n\tlong\tsession;\n\tint\t\tret;\n\tint\t\tlen;\n} vcrGetMessage;\n\nextern void PrintStats(qsocket_t *s);\n\nint\tNET_GetMessage (qsocket_t *sock)\n{\n\tint ret;\n\n\tif (!sock)\n\t\treturn -1;\n\n\tif (sock->disconnected)\n\t{\n\t\tCon_Printf(\"NET_GetMessage: disconnected socket\\n\");\n\t\treturn -1;\n\t}\n\n\tSetNetTime();\n\n\tret = sfunc.QGetMessage(sock);\n\n\t// see if this connection has timed out\n\tif (ret == 0 && sock->driver)\n\t{\n\t\tif (net_time - sock->lastMessageTime > net_messagetimeout.value)\n\t\t{\n\t\t\tNET_Close(sock);\n\t\t\treturn -1;\n\t\t}\n\t}\n\n\n\tif (ret > 0)\n\t{\n\t\tif (sock->driver)\n\t\t{\n\t\t\tsock->lastMessageTime = net_time;\n\t\t\tif (ret == 1)\n\t\t\t\tmessagesReceived++;\n\t\t\telse if (ret == 2)\n\t\t\t\tunreliableMessagesReceived++;\n\t\t}\n\n\t\tif (recording)\n\t\t{\n\t\t\tvcrGetMessage.time = host_time;\n\t\t\tvcrGetMessage.op = VCR_OP_GETMESSAGE;\n\t\t\tvcrGetMessage.session = (long)sock;\n\t\t\tvcrGetMessage.ret = ret;\n\t\t\tvcrGetMessage.len = net_message.cursize;\n\t\t\tSys_FileWrite (vcrFile, &vcrGetMessage, 24);\n\t\t\tSys_FileWrite (vcrFile, net_message.data, net_message.cursize);\n\t\t}\n\t}\n\telse\n\t{\n\t\tif (recording)\n\t\t{\n\t\t\tvcrGetMessage.time = host_time;\n\t\t\tvcrGetMessage.op = VCR_OP_GETMESSAGE;\n\t\t\tvcrGetMessage.session = (long)sock;\n\t\t\tvcrGetMessage.ret = ret;\n\t\t\tSys_FileWrite (vcrFile, &vcrGetMessage, 20);\n\t\t}\n\t}\n\n\treturn ret;\n}\n\n\n/*\n==================\nNET_SendMessage\n\nTry to send a complete length+message unit over the reliable stream.\nreturns 0 if the message cannot be delivered reliably, but the connection\n\t\tis still considered valid\nreturns 1 if the message was sent properly\nreturns -1 if the connection died\n==================\n*/\nstruct\n{\n\tdouble\ttime;\n\tint\t\top;\n\tlong\tsession;\n\tint\t\tr;\n} vcrSendMessage;\n\nint NET_SendMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tint\t\tr;\n\t\n\tif (!sock)\n\t\treturn -1;\n\n\tif (sock->disconnected)\n\t{\n\t\tCon_Printf(\"NET_SendMessage: disconnected socket\\n\");\n\t\treturn -1;\n\t}\n\n\tSetNetTime();\n\tr = sfunc.QSendMessage(sock, data);\n\tif (r == 1 && sock->driver)\n\t\tmessagesSent++;\n\n\tif (recording)\n\t{\n\t\tvcrSendMessage.time = host_time;\n\t\tvcrSendMessage.op = VCR_OP_SENDMESSAGE;\n\t\tvcrSendMessage.session = (long)sock;\n\t\tvcrSendMessage.r = r;\n\t\tSys_FileWrite (vcrFile, &vcrSendMessage, 20);\n\t}\n\t\n\treturn r;\n}\n\n\nint NET_SendUnreliableMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tint\t\tr;\n\t\n\tif (!sock)\n\t\treturn -1;\n\n\tif (sock->disconnected)\n\t{\n\t\tCon_Printf(\"NET_SendMessage: disconnected socket\\n\");\n\t\treturn -1;\n\t}\n\n\tSetNetTime();\n\tr = sfunc.SendUnreliableMessage(sock, data);\n\tif (r == 1 && sock->driver)\n\t\tunreliableMessagesSent++;\n\n\tif (recording)\n\t{\n\t\tvcrSendMessage.time = host_time;\n\t\tvcrSendMessage.op = VCR_OP_SENDMESSAGE;\n\t\tvcrSendMessage.session = (long)sock;\n\t\tvcrSendMessage.r = r;\n\t\tSys_FileWrite (vcrFile, &vcrSendMessage, 20);\n\t}\n\t\n\treturn r;\n}\n\n\n/*\n==================\nNET_CanSendMessage\n\nReturns true or false if the given qsocket can currently accept a\nmessage to be transmitted.\n==================\n*/\nbool NET_CanSendMessage (qsocket_t *sock)\n{\n\tint\t\tr;\n\t\n\tif (!sock)\n\t\treturn false;\n\n\tif (sock->disconnected)\n\t\treturn false;\n\n\tSetNetTime();\n\n\tr = sfunc.CanSendMessage(sock);\n\t\n\tif (recording)\n\t{\n\t\tvcrSendMessage.time = host_time;\n\t\tvcrSendMessage.op = VCR_OP_CANSENDMESSAGE;\n\t\tvcrSendMessage.session = (long)sock;\n\t\tvcrSendMessage.r = r;\n\t\tSys_FileWrite (vcrFile, &vcrSendMessage, 20);\n\t}\n\t\n\treturn r;\n}\n\n\nint NET_SendToAll(sizebuf_t *data, int blocktime)\n{\n\tdouble\t\tstart;\n\tint\t\t\ti;\n\tint\t\t\tcount = 0;\n\tbool\tstate1 [MAX_SCOREBOARD];\n\tbool\tstate2 [MAX_SCOREBOARD];\n\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t{\n\t\tif (!host_client->netconnection)\n\t\t\tcontinue;\n\t\tif (host_client->active)\n\t\t{\n\t\t\tif (host_client->netconnection->driver == 0)\n\t\t\t{\n\t\t\t\tNET_SendMessage(host_client->netconnection, data);\n\t\t\t\tstate1[i] = true;\n\t\t\t\tstate2[i] = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcount++;\n\t\t\tstate1[i] = false;\n\t\t\tstate2[i] = false;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstate1[i] = true;\n\t\t\tstate2[i] = true;\n\t\t}\n\t}\n\n\tstart = Sys_FloatTime();\n\twhile (count)\n\t{\n\t\tcount = 0;\n\t\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t\t{\n\t\t\tif (! state1[i])\n\t\t\t{\n\t\t\t\tif (NET_CanSendMessage (host_client->netconnection))\n\t\t\t\t{\n\t\t\t\t\tstate1[i] = true;\n\t\t\t\t\tNET_SendMessage(host_client->netconnection, data);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNET_GetMessage (host_client->netconnection);\n\t\t\t\t}\n\t\t\t\tcount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (! state2[i])\n\t\t\t{\n\t\t\t\tif (NET_CanSendMessage (host_client->netconnection))\n\t\t\t\t{\n\t\t\t\t\tstate2[i] = true;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tNET_GetMessage (host_client->netconnection);\n\t\t\t\t}\n\t\t\t\tcount++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\tif ((Sys_FloatTime() - start) > blocktime)\n\t\t\tbreak;\n\t}\n\treturn count;\n}\n\n\n//=============================================================================\n\n/*\n====================\nNET_Init\n====================\n*/\n\nvoid NET_Init (void)\n{\n\tint\t\t\ti;\n\tint\t\t\tcontrolSocket;\n\tqsocket_t\t*s;\n\n\tif (COM_CheckParm(\"-playback\"))\n\t{\n\t\tnet_numdrivers = 1;\n\t\tnet_drivers[0].Init = VCR_Init;\n\t}\n\n\tif (COM_CheckParm(\"-record\"))\n\t\trecording = true;\n\n\ti = COM_CheckParm (\"-port\");\n\tif (!i)\n\t\ti = COM_CheckParm (\"-udpport\");\n\tif (!i)\n\t\ti = COM_CheckParm (\"-ipxport\");\n\n\tif (i)\n\t{\n\t\tif (i < com_argc-1)\n\t\t\tDEFAULTnet_hostport = atoi (com_argv[i+1]);\n\t\telse\n\t\t\tSys_Error (\"NET_Init: you must specify a number after -port\");\n\t}\n\tnet_hostport = DEFAULTnet_hostport;\n\n\tif (COM_CheckParm(\"-listen\") || cls.state == ca_dedicated)\n\t\tlistening = true;\n\tnet_numsockets = svs.maxclientslimit;\n\tif (cls.state != ca_dedicated)\n\t\tnet_numsockets++;\n\n\tSetNetTime();\n\n\tfor (i = 0; i < net_numsockets; i++)\n\t{\n\t\ts = (qsocket_t *)Hunk_AllocName(sizeof(qsocket_t), \"qsocket\");\n\t\ts->next = net_freeSockets;\n\t\tnet_freeSockets = s;\n\t\ts->disconnected = true;\n\t}\n\n\t// allocate space for network message buffer\n\tSZ_Alloc (&net_message, NET_MAXMESSAGE);\n\n\tCvar_RegisterVariable (&net_messagetimeout);\n\tCvar_RegisterVariable (&hostname);\n\n#ifdef IDGODS\n\tCvar_RegisterVariable (&idgods);\n#endif\n\n\tCmd_AddCommand (\"slist\", NET_Slist_f);\n\tCmd_AddCommand (\"listen\", NET_Listen_f);\n\tCmd_AddCommand (\"maxplayers\", MaxPlayers_f);\n\tCmd_AddCommand (\"port\", NET_Port_f);\n\n\t// initialize all the drivers\n\tfor (net_driverlevel=0 ; net_driverlevel<net_numdrivers ; net_driverlevel++)\n\t\t{\n\t\tcontrolSocket = net_drivers[net_driverlevel].Init();\n\t\tif (controlSocket == -1)\n\t\t\tcontinue;\n\t\tnet_drivers[net_driverlevel].initialized = true;\n\t\tnet_drivers[net_driverlevel].controlSock = controlSocket;\n\t\tif (listening)\n\t\t\tnet_drivers[net_driverlevel].Listen (true);\n\t\t}\n\n\tif (*my_tcpip_address)\n\t\tCon_DPrintf(\"TCP/IP address %s\\n\", my_tcpip_address);\n}\n\n/*\n====================\nNET_Shutdown\n====================\n*/\n\nvoid\t\tNET_Shutdown (void)\n{\n\tqsocket_t\t*sock;\n\n\tSetNetTime();\n\n\tfor (sock = net_activeSockets; sock; sock = sock->next)\n\t\tNET_Close(sock);\n\n//\n// shutdown the drivers\n//\n\tfor (net_driverlevel = 0; net_driverlevel < net_numdrivers; net_driverlevel++)\n\t{\n\t\tif (net_drivers[net_driverlevel].initialized == true)\n\t\t{\n\t\t\tnet_drivers[net_driverlevel].Shutdown ();\n\t\t\tnet_drivers[net_driverlevel].initialized = false;\n\t\t}\n\t}\n\n\tif (vcrFile != -1)\n\t{\n\t\tCon_Printf (\"Closing vcrfile.\\n\");\n\t\tSys_FileClose(vcrFile);\n\t}\n}\n\n\nstatic PollProcedure *pollProcedureList = NULL;\n\nvoid NET_Poll(void)\n{\n\tPollProcedure *pp;\n\n\tSetNetTime();\n\n\tfor (pp = pollProcedureList; pp; pp = pp->next)\n\t{\n\t\tif (pp->nextTime > net_time)\n\t\t\tbreak;\n\t\tpollProcedureList = pp->next;\n\t\tpp->procedure(pp->arg);\n\t}\n}\n\n\nvoid SchedulePollProcedure(PollProcedure *proc, double timeOffset)\n{\n\tPollProcedure *pp, *prev;\n\n\tproc->nextTime = Sys_FloatTime() + timeOffset;\n\tfor (pp = pollProcedureList, prev = NULL; pp; pp = pp->next)\n\t{\n\t\tif (pp->nextTime >= proc->nextTime)\n\t\t\tbreak;\n\t\tprev = pp;\n\t}\n\n\tif (prev == NULL)\n\t{\n\t\tproc->next = pollProcedureList;\n\t\tpollProcedureList = proc;\n\t\treturn;\n\t}\n\n\tproc->next = pp;\n\tprev->next = proc;\n}\n\n\n#ifdef IDGODS\n#define IDNET\t0xc0f62800\n\nbool IsID(struct qsockaddr *addr)\n{\n\tif (idgods.value == 0.0)\n\t\treturn false;\n\n\tif (addr->sa_family != 2)\n\t\treturn false;\n\n\tif ((BigLong(*(int *)&addr->sa_data[2]) & 0xffffff00) == IDNET)\n\t\treturn true;\n\treturn false;\n}\n#endif\n"
  },
  {
    "path": "source/net_none.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include \"quakedef.h\"\n\n#include \"net_loop.h\"\n\nnet_driver_t net_drivers[MAX_NET_DRIVERS] =\n{\n\t{\n\t\"Loopback\",\n\tfalse,\n\tLoop_Init,\n\tLoop_Listen,\n\tLoop_SearchForHosts,\n\tLoop_Connect,\n\tLoop_CheckNewConnections,\n\tLoop_GetMessage,\n\tLoop_SendMessage,\n\tLoop_SendUnreliableMessage,\n\tLoop_CanSendMessage,\n\tLoop_CanSendUnreliableMessage,\n\tLoop_Close,\n\tLoop_Shutdown\n\t}\n};\nint net_numdrivers = 1;\n\nnet_landriver_t\tnet_landrivers[MAX_NET_DRIVERS];\nint net_numlandrivers = 0;\n"
  },
  {
    "path": "source/net_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#include \"quakedef.h\"\n#include \"net_loop.h\"\n#include \"net_dgrm.h\"\n\nnet_driver_t net_drivers[MAX_NET_DRIVERS] =\n{\n\t{\n\t\"Loopback\",\n\tfalse,\n\tLoop_Init,\n\tLoop_Listen,\n\tLoop_SearchForHosts,\n\tLoop_Connect,\n\tLoop_CheckNewConnections,\n\tLoop_GetMessage,\n\tLoop_SendMessage,\n\tLoop_SendUnreliableMessage,\n\tLoop_CanSendMessage,\n\tLoop_CanSendUnreliableMessage,\n\tLoop_Close,\n\tLoop_Shutdown\n\t}\n\t,\n\t{\n\t\"Datagram\",\n\tfalse,\n\tDatagram_Init,\n\tDatagram_Listen,\n\tDatagram_SearchForHosts,\n\tDatagram_Connect,\n\tDatagram_CheckNewConnections,\n\tDatagram_GetMessage,\n\tDatagram_SendMessage,\n\tDatagram_SendUnreliableMessage,\n\tDatagram_CanSendMessage,\n\tDatagram_CanSendUnreliableMessage,\n\tDatagram_Close,\n\tDatagram_Shutdown\n\t}\n};\n\nint net_numdrivers = 2;\n\n#include \"net_udp.h\"\n#include \"net_adhoc.h\"\n\nnet_landriver_t\tnet_landrivers[MAX_NET_DRIVERS] =\n{\n\t{\n\t\"UDP\",\n\tfalse,\n\t0,\n\tUDP_Init,\n\tUDP_Shutdown,\n\tUDP_Listen,\n\tUDP_OpenSocket,\n\tUDP_CloseSocket,\n\tUDP_Connect,\n\tUDP_CheckNewConnections,\n\tUDP_Read,\n\tUDP_Write,\n\tUDP_Broadcast,\n\tUDP_AddrToString,\n\tUDP_StringToAddr,\n\tUDP_GetSocketAddr,\n\tUDP_GetNameFromAddr,\n\tUDP_GetAddrFromName,\n\tUDP_AddrCompare,\n\tUDP_GetSocketPort,\n\tUDP_SetSocketPort\n\t},\n\t{\n\t\"AdHoc\",\n\tfalse,\n\t0,\n\tAdHoc_Init,\n\tAdHoc_Shutdown,\n\tAdHoc_Listen,\n\tAdHoc_OpenSocket,\n\tAdHoc_CloseSocket,\n\tAdHoc_Connect,\n\tAdHoc_CheckNewConnections,\n\tAdHoc_Read,\n\tAdHoc_Write,\n\tAdHoc_Broadcast,\n\tAdHoc_AddrToString,\n\tAdHoc_StringToAddr,\n\tAdHoc_GetSocketAddr,\n\tAdHoc_GetNameFromAddr,\n\tAdHoc_GetAddrFromName,\n\tAdHoc_AddrCompare,\n\tAdHoc_GetSocketPort,\n\tAdHoc_SetSocketPort\n\t}\n};\n\nint net_numlandrivers = 2;\n"
  },
  {
    "path": "source/net_udp.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_udp.h\n\nint  UDP_Init (void);\nvoid UDP_Shutdown (void);\nvoid UDP_Listen (bool state);\nint  UDP_OpenSocket (int port);\nint  UDP_CloseSocket (int socket);\nint  UDP_Connect (int socket, struct qsockaddr *addr);\nint  UDP_CheckNewConnections (void);\nint  UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr);\nint  UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr);\nint  UDP_Broadcast (int socket, byte *buf, int len);\nchar *UDP_AddrToString (struct qsockaddr *addr);\nint  UDP_StringToAddr (char *string, struct qsockaddr *addr);\nint  UDP_GetSocketAddr (int socket, struct qsockaddr *addr);\nint  UDP_GetNameFromAddr (struct qsockaddr *addr, char *name);\nint  UDP_GetAddrFromName (char *name, struct qsockaddr *addr);\nint  UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2);\nint  UDP_GetSocketPort (struct qsockaddr *addr);\nint  UDP_SetSocketPort (struct qsockaddr *addr, int port);\n"
  },
  {
    "path": "source/net_udp_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_udp.c\n\n#include \"quakedef.h\"\n#include \"net_udp.h\"\n\n#include <sys/types.h>\n#include <vitasdk.h>\n#include <errno.h>\n\n#ifdef __sun__\n#include <sys/filio.h>\n#endif\n\n#ifdef NeXT\n#include <libc.h>\n#endif\n\nextern cvar_t hostname;\nextern void Log (const char *format, ...);\n\n#define MAX_NAME 512\nstruct hostent{\n  char  *h_name;         /* official (cannonical) name of host               */\n  char **h_aliases;      /* pointer to array of pointers of alias names      */\n  int    h_addrtype;     /* host address type: AF_INET                       */\n  int    h_length;       /* length of address: 4                             */\n  char **h_addr_list;    /* pointer to array of pointers with IPv4 addresses */\n};\n#define h_addr h_addr_list[0]\n\n// Since using standard sceNet structs seems to cause problems, let's re-implement linux-like interface\n#define AF_INET SCE_NET_AF_INET\n#define SOCK_DGRAM SCE_NET_SOCK_DGRAM\n#define IPPROTO_UDP SCE_NET_IPPROTO_UDP\n#define SOL_SOCKET SCE_NET_SOL_SOCKET\n#define MSG_PEEK SCE_NET_MSG_PEEK\n#define INADDR_BROADCAST SCE_NET_INADDR_BROADCAST\n#define SO_BROADCAST SCE_NET_SO_BROADCAST\n#define INADDR_ANY SCE_NET_INADDR_ANY\n#define SO_NBIO SCE_NET_SO_NBIO\n\nstruct in_addr {\n    unsigned long s_addr;  // load with inet_aton()\n};\n\nstruct sockaddr_in {\n    short            sin_family;   // e.g. AF_INET\n    unsigned short   sin_port;     // e.g. htons(3490)\n    struct in_addr   sin_addr;     // see struct in_addr, below\n    char             sin_zero[8];  // zero this if you want to\n};\n\nstruct sockaddr {\n    unsigned short    sa_family;    // address family, AF_xxx\n    char              sa_data[14];  // 14 bytes of protocol address\n};\n\ninline int convertSceNetSockaddrIn(struct SceNetSockaddrIn* src, struct sockaddr_in* dst){\n\tif (dst == NULL || src == NULL) return -1;\n\tdst->sin_family = src->sin_family;\n\tdst->sin_port = src->sin_port;\n\tdst->sin_addr.s_addr = src->sin_addr.s_addr;\n\treturn 0;\n}\n\ninline int convertSockaddrIn(struct SceNetSockaddrIn* dst, const struct sockaddr_in* src){\n\tif (dst == NULL || src == NULL) return -1;\n\tdst->sin_family = src->sin_family;\n\tdst->sin_port = src->sin_port;\n\tdst->sin_addr.s_addr = src->sin_addr.s_addr;\n\treturn 0;\n}\n\ninline int convertSceNetSockaddr(struct SceNetSockaddr* src, struct sockaddr* dst){\n\tif (dst == NULL || src == NULL) return -1;\n\tdst->sa_family = src->sa_family;\n\tmemcpy(dst->sa_data,src->sa_data,14);\n\treturn 0;\n}\n\ninline int convertSockaddr(struct SceNetSockaddr* dst, const struct sockaddr* src){\n\tif (dst == NULL || src == NULL) return -1;\n\tdst->sa_family = src->sa_family;\n\tmemcpy(dst->sa_data,src->sa_data,14);\n\treturn 0;\n}\n\ninline int socket(int domain, int type, int protocol){\n\treturn sceNetSocket(\"Socket\", domain, type, protocol);\n}\n\ninline int recvfrom(int sockfd, void* buf, long len, int flags, struct sockaddr* src_addr, unsigned int* addrlen){\n\tstruct SceNetSockaddr tmp;\n\tint res = sceNetRecvfrom(sockfd, buf, len, flags, &tmp, addrlen);\n\tif (src_addr != NULL) convertSceNetSockaddr(&tmp, src_addr);\n\treturn res;\n}\n\ninline int getsockname(int sockfd, struct sockaddr *addr, unsigned int *addrlen){\n\tstruct SceNetSockaddr tmp;\n\tconvertSockaddr(&tmp, addr);\n\tint res = sceNetGetsockname(sockfd, &tmp, addrlen);\n\tconvertSceNetSockaddr(&tmp, addr);\n\treturn res;\n}\n\ninline int bind(int sockfd, const struct sockaddr* addr, unsigned int addrlen){\n\tstruct SceNetSockaddr tmp;\n\tconvertSockaddr(&tmp, addr);\n\treturn sceNetBind(sockfd, &tmp, addrlen);\n}\n\ninline int close(int sockfd){\n\treturn sceNetSocketClose(sockfd);\n}\n\ninline int setsockopt(int sockfd, int level, int optname, const void *optval, unsigned int optlen){\n\treturn sceNetSetsockopt(sockfd, level, optname, optval, optlen);\n}\n\ninline unsigned int sendto(int sockfd, const void *buf, unsigned int len, int flags, const struct sockaddr *dest_addr, unsigned int addrlen){\n\tstruct SceNetSockaddr tmp;\n\tconvertSockaddr(&tmp, dest_addr);\n\treturn sceNetSendto(sockfd, buf, len, flags, &tmp, addrlen);\n}\n\n// Copy-pasted from xyz code\nstatic struct hostent *gethostbyname(const char *name)\n{\n    static struct hostent ent;\n    static char sname[MAX_NAME] = \"\";\n    static struct SceNetInAddr saddr = { 0 };\n    static char *addrlist[2] = { (char *) &saddr, NULL };\n\n    int rid;\n    int err;\n    rid = sceNetResolverCreate(\"resolver\", NULL, 0);\n    if(rid < 0) {\n        return NULL;\n    }\n\n    err = sceNetResolverStartNtoa(rid, name, &saddr, 0, 0, 0);\n    sceNetResolverDestroy(rid);\n    if(err < 0) {\n        return NULL;\n    }\n\n    ent.h_name = sname;\n    ent.h_aliases = 0;\n    ent.h_addrtype = SCE_NET_AF_INET;\n    ent.h_length = sizeof(struct SceNetInAddr);\n    ent.h_addr_list = addrlist;\n    ent.h_addr = addrlist[0];\n\n    return &ent;\n}\n\nstatic int net_acceptsocket = -1;\t\t// socket for fielding new connections\nstatic int net_controlsocket;\nstatic int net_broadcastsocket = 0;\nstatic struct qsockaddr broadcastaddr;\n\nstatic unsigned long myAddr;\n\n#include \"net_udp.h\"\n\n//=============================================================================\nstatic void *net_memory = NULL;\n#define NET_INIT_SIZE 1*1024*1024\n\nint UDP_Init (void)\n{\n\tLog(\"UDP_Init called...\");\n\tstruct hostent *local;\n\tchar\tbuff[15];\n\tstruct qsockaddr addr;\n\tchar *colon;\n\tSceNetInitParam initparam;\n\t\n\tif (COM_CheckParm (\"-noudp\"))\n\t\treturn -1;\n\t\n\t// Start SceNet & SceNetCtl\n\tint ret = sceNetShowNetstat();\n\tif (ret == SCE_NET_ERROR_ENOTINIT) {\n\t\tnet_memory = malloc(NET_INIT_SIZE);\n\n\t\tinitparam.memory = net_memory;\n\t\tinitparam.size = NET_INIT_SIZE;\n\t\tinitparam.flags = 0;\n\n\t\tret = sceNetInit(&initparam);\n\t\tif (ret < 0) return -1;\n\t\t\n\t\tret = sceNetCtlInit();\n\t\tif (ret < 0){\n\t\t\tsceNetTerm();\n\t\t\tfree(net_memory);\n\t\t\treturn -1;\n\t\t}\n\t}\t\n\t\n\t// Getting IP address\n\tSceNetCtlInfo info;\n\tsceNetCtlInetGetInfo(SCE_NETCTL_INFO_GET_IP_ADDRESS, &info);\n\tsceNetInetPton(SCE_NET_AF_INET, info.ip_address, &myAddr);\n\t\n\t// if the quake hostname isn't set, set it to player nickname\n\tif (!strcmp(hostname.string, \"UNNAMED\"))\n\t{\n\t\tSceAppUtilInitParam init_param;\n\t\tSceAppUtilBootParam boot_param;\n\t\tmemset(&init_param, 0, sizeof(SceAppUtilInitParam));\n\t\tmemset(&boot_param, 0, sizeof(SceAppUtilBootParam));\n\t\tsceAppUtilInit(&init_param, &boot_param);\n\t\tchar nick[SCE_SYSTEM_PARAM_USERNAME_MAXSIZE];\n\t\tsceAppUtilSystemParamGetString(SCE_SYSTEM_PARAM_ID_USERNAME, nick, SCE_SYSTEM_PARAM_USERNAME_MAXSIZE);\n\t\tCvar_Set (\"hostname\", nick);\n\t}\n\n\tif ((net_controlsocket = UDP_OpenSocket (0)) == -1)\n\t\tSys_Error(\"UDP_Init: Unable to open control socket\\n\");\n\n\t((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET;\n\t((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST;\n\t((struct sockaddr_in *)&broadcastaddr)->sin_port = sceNetHtons(net_hostport);\n\n\tUDP_GetSocketAddr (net_controlsocket, &addr);\n\tstrcpy(my_tcpip_address,  UDP_AddrToString (&addr));\n\n\tcolon = strrchr (my_tcpip_address, ':');\n\tif (colon)\n\t\t*colon = 0;\n\t\n\tCon_Printf(\"UDP Initialized as IP %s\\n\", my_tcpip_address);\n\ttcpipAvailable = true;\n\n\treturn net_controlsocket;\n}\n\n//=============================================================================\n\nvoid UDP_Shutdown (void)\n{\n\tLog(\"UDP_Shutdown\");\n\tUDP_Listen (false);\n\tUDP_CloseSocket (net_controlsocket);\n\t//sceNetCtlTerm();\n\t//sceNetTerm();\n\t//free(net_memory);\n}\n\n//=============================================================================\n\nvoid UDP_Listen (bool state)\n{\n\tLog(\"UDP_Listen\");\n\t// enable listening\n\tif (state)\n\t{\n\t\tif (net_acceptsocket != -1)\n\t\t\treturn;\n\t\tif ((net_acceptsocket = UDP_OpenSocket (net_hostport)) == -1)\n\t\t\tSys_Error (\"UDP_Listen: Unable to open accept socket\\n\");\n\t\treturn;\n\t}\n\n\t// disable listening\n\tif (net_acceptsocket == -1)\n\t\treturn;\n\tUDP_CloseSocket (net_acceptsocket);\n\tnet_acceptsocket = -1;\n}\n\n//=============================================================================\n\nint UDP_OpenSocket (int port)\n{\n\tLog(\"UDP_OpenSocket(%ld)\",port);\n\tint newsocket;\n\tstruct sockaddr_in address;\n\tuint32_t _true = true;\n\n\tif ((newsocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)\n\t\treturn -1;\n\n\tif (setsockopt(newsocket, SOL_SOCKET, SO_NBIO, (char *)&_true, sizeof(uint32_t)) == -1)\n\t\tgoto ErrorReturn;\n\n\tmemset(&address, 0, sizeof(struct sockaddr_in)); // JPG 1.05 - fix by JDC\n\taddress.sin_family = AF_INET;\n\taddress.sin_addr.s_addr = myAddr;\n\taddress.sin_port = sceNetHtons(port);\n\tif( bind(newsocket, (void*)&address, sizeof(address)) == -1)\n\t\tgoto ErrorReturn;\n\n\treturn newsocket;\n\nErrorReturn:\n\tclose(newsocket);\n\treturn -1;\n}\n\n//=============================================================================\n\nint UDP_CloseSocket (int socket)\n{\n\tLog(\"UDP_CloseSocket\");\n\tif (socket == net_broadcastsocket)\n\t\tnet_broadcastsocket = 0;\n\treturn close(socket);\n}\n\n\n//=============================================================================\n/*\n============\nPartialIPAddress\n\nthis lets you type only as much of the net address as required, using\nthe local network components to fill in the rest\n============\n*/\nstatic int PartialIPAddress (char *in, struct qsockaddr *hostaddr)\n{\n\tchar buff[256];\n\tchar *b;\n\tint addr;\n\tint num;\n\tint mask;\n\tint run;\n\tint port;\n\n\tbuff[0] = '.';\n\tb = buff;\n\tstrcpy(buff+1, in);\n\tif (buff[1] == '.')\n\t\tb++;\n\n\taddr = 0;\n\tmask=-1;\n\twhile (*b == '.')\n\t{\n\t\tb++;\n\t\tnum = 0;\n\t\trun = 0;\n\t\twhile (!( *b < '0' || *b > '9'))\n\t\t{\n\t\t  num = num*10 + *b++ - '0';\n\t\t  if (++run > 3)\n\t\t  \treturn -1;\n\t\t}\n\t\tif ((*b < '0' || *b > '9') && *b != '.' && *b != ':' && *b != 0)\n\t\t\treturn -1;\n\t\tif (num < 0 || num > 255)\n\t\t\treturn -1;\n\t\tmask<<=8;\n\t\taddr = (addr<<8) + num;\n\t}\n\n\tif (*b++ == ':')\n\t\tport = atoi(b);\n\telse\n\t\tport = net_hostport;\n\t\n\tLog(\"PartialIPAddress(%s): port: %ld\",in,port);\n\thostaddr->sa_family = SCE_NET_AF_INET;\n\t((struct sockaddr_in *)hostaddr)->sin_port = sceNetHtons((short)port);\n\t((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & sceNetHtonl(mask)) | sceNetHtonl(addr);\n\n\treturn 0;\n}\n//=============================================================================\n\nint UDP_Connect (int socket, struct qsockaddr *addr)\n{\n\tLog(\"UDP_Connect\");\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_CheckNewConnections (void)\n{\n\tLog(\"UDP_CheckNewConnections\");\n\tchar buf[4096];\n\t\n\tif (net_acceptsocket == -1)\n\t\treturn -1;\n\n\tif (recvfrom(net_acceptsocket, buf, sizeof(buf), MSG_PEEK, NULL, NULL) >= 0)\n\t\treturn net_acceptsocket;\n\n\treturn -1;\n}\n\n//=============================================================================\n\nint UDP_Read (int socket, byte *buf, int len, struct qsockaddr *addr)\n{\n\tint addrlen = sizeof (struct qsockaddr);\n\tint ret;\n\t\n\tret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen);\n\tLog(\"UDP_Read returned %ld\",ret);\n\tif (ret == SCE_NET_ERROR_EAGAIN || ret == SCE_NET_ERROR_ECONNREFUSED)\n\t\treturn 0;\n\telse if (ret < 0)\n\t\treturn -1;\n\treturn ret;\n}\n\n//=============================================================================\n\nint UDP_MakeSocketBroadcastCapable (int socket)\n{\n\tint\t\t\t\ti = 1;\n\tLog(\"UDP_MakeSocketBroadcastCapable\");\n\t// make this socket broadcast capable\n\tif (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0)\n\t\treturn -1;\n\tnet_broadcastsocket = socket;\n\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_Broadcast (int socket, byte *buf, int len)\n{\n\tLog(\"UDP_Broadcast\");\n\tint ret;\n\n\tif (socket != net_broadcastsocket)\n\t{\n\t\tif (net_broadcastsocket != 0)\n\t\t\tSys_Error(\"Attempted to use multiple broadcasts sockets\\n\");\n\t\tret = UDP_MakeSocketBroadcastCapable (socket);\n\t\tif (ret == -1)\n\t\t{\n\t\t\tCon_Printf(\"Unable to make socket broadcast capable\\n\");\n\t\t\treturn ret;\n\t\t}\n\t}\n\n\treturn UDP_Write (socket, buf, len, &broadcastaddr);\n}\n\n//=============================================================================\n\nint UDP_Write (int socket, byte *buf, int len, struct qsockaddr *addr)\n{\n\tint ret;\n\n\tret = sendto(socket, buf, len, 0, (struct sockaddr *)addr, sizeof(struct qsockaddr));\n\tLog(\"UDP_Write returned %ld\",ret);\n\tif (ret == SCE_NET_ERROR_EAGAIN)\n\t\treturn 0;\n\telse if (ret < 0)\n\t\treturn -1;\n\treturn ret;\n}\n\n//=============================================================================\n\nchar *UDP_AddrToString (struct qsockaddr *addr)\n{\n\tstatic char buffer[22];\n\tint haddr;\n\n\thaddr = sceNetNtohl(((struct sockaddr_in *)addr)->sin_addr.s_addr);\n\tsprintf(buffer, \"%d.%d.%d.%d:%d\", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, sceNetNtohs(((struct sockaddr_in *)addr)->sin_port));\n\tLog(\"UDP_AddrToString returned %s\",buffer);\n\treturn buffer;\n}\n\n//=============================================================================\n\nint UDP_StringToAddr (char *string, struct qsockaddr *addr)\n{\n\tLog(\"UDP_StringToAddr(%s)\",string);\n\tint ha1, ha2, ha3, ha4, hp;\n\tint ipaddr;\n\n\tsscanf(string, \"%d.%d.%d.%d:%d\", &ha1, &ha2, &ha3, &ha4, &hp);\n\tipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4;\n\n\taddr->sa_family = AF_INET;\n\t((struct sockaddr_in *)addr)->sin_addr.s_addr = sceNetHtonl(ipaddr);\n\t((struct sockaddr_in *)addr)->sin_port = sceNetHtons(hp);\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_GetSocketAddr (int socket, struct qsockaddr *addr)\n{\n\tLog(\"UDP_GetSocketAddr\");\n\tint addrlen = sizeof(struct qsockaddr);\n\tunsigned int a, tmp;\n\n\tmemset(addr, 0, sizeof(struct qsockaddr));\n\tint ret = getsockname(socket, (struct sockaddr *)addr, &addrlen);\n\tLog(\"getsockname returned %ld\", ret);\n\ta = ((struct sockaddr_in *)addr)->sin_addr.s_addr;\n\tsceNetInetPton(SCE_NET_AF_INET, \"127.0.0.1\", &tmp);\n\tif (a == 0 || a == tmp)\n\t\t((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr;\n\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_GetNameFromAddr (struct qsockaddr *addr, char *name)\n{\n\tstrcpy (name, UDP_AddrToString (addr));\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_GetAddrFromName(char *name, struct qsockaddr *addr)\n{\n\tLog(\"UDP_GetAddrFromName(%s)\",name);\n\tstruct hostent *hostentry;\n\n\tif (name[0] >= '0' && name[0] <= '9')\n\t\treturn PartialIPAddress (name, addr);\n\n\thostentry = gethostbyname (name);\n\tif (!hostentry)\n\t\treturn -1;\n\n\taddr->sa_family = SCE_NET_AF_INET;\n\t((struct sockaddr_in *)addr)->sin_port = sceNetHtons(net_hostport);\n\t((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0];\n\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_AddrCompare (struct qsockaddr *addr1, struct qsockaddr *addr2)\n{\n\tif (addr1->sa_family != addr2->sa_family){\n\t\tLog(\"UDP_AddrCompare returned -1 (1st case)\");\n\t\treturn -1;\n\t}\n\t\n\tif (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr){\n\t\tLog(\"UDP_AddrCompare returned -1 (2nd case)\");\n\t\treturn -1;\n\t}\n\t\n\tif (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port){\n\t\tLog(\"UDP_AddrCompare returned 1\");\n\t\treturn 1;\n\t}\n\t\n\tLog(\"UDP_AddrCompare returned 0\");\n\treturn 0;\n}\n\n//=============================================================================\n\nint UDP_GetSocketPort (struct qsockaddr *addr)\n{\n\tLog(\"UDP_GetSocketPort\");\n\treturn sceNetNtohs(((struct sockaddr_in *)addr)->sin_port);\n}\n\n\nint UDP_SetSocketPort (struct qsockaddr *addr, int port)\n{\n\tLog(\"UDP_SetSocketPort\");\n\t((struct sockaddr_in *)addr)->sin_port = sceNetHtons(port);\n\treturn 0;\n}\n\n//=============================================================================\n"
  },
  {
    "path": "source/net_vcr.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_vcr.c\n\n#include \"quakedef.h\"\n#include \"net_vcr.h\"\n\nextern int vcrFile;\n\n// This is the playback portion of the VCR.  It reads the file produced\n// by the recorder and plays it back to the host.  The recording contains\n// everything necessary (events, timestamps, and data) to duplicate the game\n// from the viewpoint of everything above the network layer.\n\nstatic struct\n{\n\tdouble\ttime;\n\tint\t\top;\n\tlong\tsession;\n}\tnext;\n\nint VCR_Init (void)\n{\n\tnet_drivers[0].Init = VCR_Init;\n\n\tnet_drivers[0].SearchForHosts = VCR_SearchForHosts;\n\tnet_drivers[0].Connect = VCR_Connect;\n\tnet_drivers[0].CheckNewConnections = VCR_CheckNewConnections;\n\tnet_drivers[0].QGetMessage = VCR_GetMessage;\n\tnet_drivers[0].QSendMessage = VCR_SendMessage;\n\tnet_drivers[0].CanSendMessage = VCR_CanSendMessage;\n\tnet_drivers[0].Close = VCR_Close;\n\tnet_drivers[0].Shutdown = VCR_Shutdown;\n\n\tSys_FileRead(vcrFile, &next, sizeof(next));\n\treturn 0;\n}\n\nvoid VCR_ReadNext (void)\n{\n\tif (Sys_FileRead(vcrFile, &next, sizeof(next)) == 0)\n\t{\n\t\tnext.op = 255;\n\t\tSys_Error (\"=== END OF PLAYBACK===\\n\");\n\t}\n\tif (next.op < 1 || next.op > VCR_MAX_MESSAGE)\n\t\tSys_Error (\"VCR_ReadNext: bad op\");\n}\n\n\nvoid VCR_Listen (bool state)\n{\n}\n\n\nvoid VCR_Shutdown (void)\n{\n}\n\n\nint VCR_GetMessage (qsocket_t *sock)\n{\n\tint\tret;\n\t\n\tif (host_time != next.time || next.op != VCR_OP_GETMESSAGE || next.session != *(long *)(&sock->driverdata))\n\t\tSys_Error (\"VCR missmatch\");\n\n\tSys_FileRead(vcrFile, &ret, sizeof(int));\n\tif (ret != 1)\n\t{\n\t\tVCR_ReadNext ();\n\t\treturn ret;\n\t}\n\n\tSys_FileRead(vcrFile, &net_message.cursize, sizeof(int));\n\tSys_FileRead(vcrFile, net_message.data, net_message.cursize);\n\n\tVCR_ReadNext ();\n\n\treturn 1;\n}\n\n\nint VCR_SendMessage (qsocket_t *sock, sizebuf_t *data)\n{\n\tint\tret;\n\n\tif (host_time != next.time || next.op != VCR_OP_SENDMESSAGE || next.session != *(long *)(&sock->driverdata))\n\t\tSys_Error (\"VCR missmatch\");\n\n\tSys_FileRead(vcrFile, &ret, sizeof(int));\n\n\tVCR_ReadNext ();\n\n\treturn ret;\n}\n\n\nbool VCR_CanSendMessage (qsocket_t *sock)\n{\n\tbool\tret;\n\n\tif (host_time != next.time || next.op != VCR_OP_CANSENDMESSAGE || next.session != *(long *)(&sock->driverdata))\n\t\tSys_Error (\"VCR missmatch\");\n\n\tSys_FileRead(vcrFile, &ret, sizeof(int));\n\n\tVCR_ReadNext ();\n\n\treturn ret;\n}\n\n\nvoid VCR_Close (qsocket_t *sock)\n{\n}\n\n\nvoid VCR_SearchForHosts (bool xmit)\n{\n}\n\n\nqsocket_t *VCR_Connect (char *host)\n{\n\treturn NULL;\n}\n\n\nqsocket_t *VCR_CheckNewConnections (void)\n{\n\tqsocket_t\t*sock;\n\n\tif (host_time != next.time || next.op != VCR_OP_CONNECT)\n\t\tSys_Error (\"VCR missmatch\");\n\n\tif (!next.session)\n\t{\n\t\tVCR_ReadNext ();\n\t\treturn NULL;\n\t}\n\n\tsock = NET_NewQSocket ();\n\t*(long *)(&sock->driverdata) = next.session;\n\n\tSys_FileRead (vcrFile, sock->address, NET_NAMELEN);\n\tVCR_ReadNext ();\n\n\treturn sock;\n}\n"
  },
  {
    "path": "source/net_vcr.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// net_vcr.h\n\n#define VCR_OP_CONNECT\t\t\t\t\t1\n#define VCR_OP_GETMESSAGE\t\t\t\t2\n#define VCR_OP_SENDMESSAGE\t\t\t\t3\n#define VCR_OP_CANSENDMESSAGE\t\t\t4\n#define VCR_MAX_MESSAGE\t\t\t\t\t4\n\nint\t\t\tVCR_Init (void);\nvoid\t\tVCR_Listen (bool state);\nvoid\t\tVCR_SearchForHosts (bool xmit);\nqsocket_t \t*VCR_Connect (char *host);\nqsocket_t \t*VCR_CheckNewConnections (void);\nint\t\t\tVCR_GetMessage (qsocket_t *sock);\nint\t\t\tVCR_SendMessage (qsocket_t *sock, sizebuf_t *data);\nbool\tVCR_CanSendMessage (qsocket_t *sock);\nvoid\t\tVCR_Close (qsocket_t *sock);\nvoid\t\tVCR_Shutdown (void);\n"
  },
  {
    "path": "source/nonintel.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//\n// nonintel.c: code for non-Intel processors only\n//\n\n#include \"quakedef.h\"\n#include \"r_local.h\"\n#include \"d_local.h\"\n\n#if\t!id386\n\n/*\n================\nR_Surf8Patch\n================\n*/\nvoid R_Surf8Patch ()\n{\n\t// we only patch code on Intel\n}\n\n\n/*\n================\nR_Surf16Patch\n================\n*/\nvoid R_Surf16Patch ()\n{\n\t// we only patch code on Intel\n}\n\n\n/*\n================\nR_SurfacePatch\n================\n*/\nvoid R_SurfacePatch (void)\n{\n\t// we only patch code on Intel\n}\n\n\n#endif\t// !id386\n\n"
  },
  {
    "path": "source/pr_cmds.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n\n#define\tRETURN_EDICT(e) (((int *)pr_globals)[OFS_RETURN] = EDICT_TO_PROG(e))\n\n#define PR_MAX_TEMPSTRING 2048\t// 2001-10-25 Enhanced temp string handling by Maddes\nchar\tpr_varstring_temp[PR_MAX_TEMPSTRING];\t// 2001-10-25 Enhanced temp string handling by Maddes\n\n// 2001-10-20 Extension System by LordHavoc  start\nchar *pr_extensions[] =\n{\n\t\"DP_CON_SET\",\n\t\"DP_CON_SETA\",\n\t\"DP_EF_BLUE\",\n\t\"DP_EF_NODRAW\",\n\t\"DP_EF_RED\",\n\t\"DP_ENT_ALPHA\",\n\t\"DP_GFX_EXTERNALTEXTURES\",\n\t\"DP_GFX_EXTERNALTEXTURES_PERMAPTEXTURES\",\n\t\"DP_HALFLIFE_MAP\",\n\t\"DP_LITSUPPORT\",\n\t\"DP_QC_ASINACOSATANATAN2TAN\",\n\t\"DP_QC_COPYENTITY\",\n\t\"DP_QC_CVAR_STRING\",\n\t\"DP_QC_EDICT_NUM\",\n\t\"DP_QC_ETOS\",\n\t\"DP_QC_FINDCHAIN\",\n\t\"DP_QC_FINDCHAINFLOAT\",\n\t\"DP_QC_MINMAXBOUND\",\n\t\"DP_QC_NUM_FOR_EDICT\",\n\t\"DP_QC_RANDOMVEC\",\n\t\"DP_QC_SINCOSSQRTPOW\",\n\t\"DP_QC_TRACEBOX\",\n\t\"DP_SND_FAKETRACKS\",\n\t\"DP_SV_MODELFLAGS_AS_EFFECTS\",\n\t\"DP_SV_NODRAWTOCLIENT\",\n\t\"DP_SV_DRAWONLYTOCLIENT\",\n\t\"EXT_BITSHIFT\",\n\t\"FRIK_FILE\"\n};\n\nint pr_numextensions = sizeof(pr_extensions)/sizeof(pr_extensions[0]);\n\nbool extension_find(char *name)\n{\n\tint\ti;\n\n\tfor (i=0; i < pr_numextensions; i++)\n\t{\n\t\tif (!strcasecmp(pr_extensions[i], name))\n\t\t\treturn true;\n\t}\n\treturn false;\n}\n\n/*\n=================\nPF_extension_find\nreturns true if the extension is supported by the server\nfloat extension_find(string name)\n=================\n*/\nvoid PF_extension_find (void)\n{\n\tG_FLOAT(OFS_RETURN) = extension_find(G_STRING(OFS_PARM0));\n}\n// 2001-10-20 Extension System by LordHavoc  end\n\n/*\n===============================================================================\n\nBUILT-IN FUNCTIONS\n\n===============================================================================\n*/\n\nchar *PF_VarString (int\tfirst)\n{\n\tint\t\ti;\n\t// 2001-10-25 Enhanced temp string handling by Maddes  start\n\tint\t\tmaxlen;\n\tchar\t*add;\n\n\tpr_varstring_temp[0] = 0;\n\tfor (i=first ; i < pr_argc ; i++)\n\t{\n\t\tmaxlen = PR_MAX_TEMPSTRING - strlen(pr_varstring_temp) - 1;\t// -1 is EndOfString\n\t\tadd = G_STRING((OFS_PARM0+i*3));\n\t\tif (maxlen > strlen(add))\n\t\t{\n\t\t\tstrcat (pr_varstring_temp, add);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrncat (pr_varstring_temp, add, maxlen);\n\t\t\tpr_varstring_temp[PR_MAX_TEMPSTRING-1] = 0;\n\t\t\tbreak;\t// can stop here\n\t\t}\n\t}\n\n\treturn pr_varstring_temp;\n\t// 2001-10-25 Enhanced temp string handling by Maddes  end\n}\n\n\n/*\n=================\nPF_errror\n\nThis is a TERMINAL error, which will kill off the entire server.\nDumps self.\n\nerror(value)\n=================\n*/\nvoid PF_error(void)\n{\n\tchar\t*s;\n\tedict_t\t*ed;\n\n\ts = PF_VarString(0);\n\tCon_Printf(\"======SERVER ERROR in %s:\\n%s\\n\"\n\t\t, pr_strings + pr_xfunction->s_name, s);\n\ted = PROG_TO_EDICT(pr_global_struct->self);\n\tED_Print(ed);\n\n\tHost_Error(\"Program error\");\n}\n\n/*\n=================\nPF_objerror\n\nDumps out self, then an error message.  The program is aborted and self is\nremoved, but the level can continue.\n\nobjerror(value)\n=================\n*/\nvoid PF_objerror(void)\n{\n\tchar\t*s;\n\tedict_t\t*ed;\n\n\ts = PF_VarString(0);\n\tCon_Printf(\"======OBJECT ERROR in %s:\\n%s\\n\"\n\t\t, pr_strings + pr_xfunction->s_name, s);\n\ted = PROG_TO_EDICT(pr_global_struct->self);\n\tED_Print(ed);\n\tED_Free(ed);\n\n\tHost_Error(\"Program error\");\n}\n\n\n\n/*\n==============\nPF_makevectors\n\nWrites new values for v_forward, v_up, and v_right based on angles\nmakevectors(vector)\n==============\n*/\nvoid PF_makevectors(void)\n{\n\tAngleVectors(G_VECTOR(OFS_PARM0), pr_global_struct->v_forward, pr_global_struct->v_right, pr_global_struct->v_up);\n}\n\n/*\n=================\nPF_setorigin\n\nThis is the only valid way to move an object without using the physics of the world (setting velocity and waiting).  Directly changing origin will not set internal links correctly, so clipping would be messed up.  This should be called when an object is spawned, and then only if it is teleported.\n\nsetorigin (entity, origin)\n=================\n*/\nvoid PF_setorigin(void)\n{\n\tedict_t\t*e;\n\tfloat\t*org;\n\n\te = G_EDICT(OFS_PARM0);\n\torg = G_VECTOR(OFS_PARM1);\n\tVectorCopy(org, e->v.origin);\n\tSV_LinkEdict(e, false);\n}\n\nvoid PF_copyentity(void)\n{\n\tedict_t *in, *out;\n\tin = G_EDICT(OFS_PARM0);\n\tout = G_EDICT(OFS_PARM1);\n\tmemcpy(out, in, pr_edict_size);\n}\n\n\nvoid SetMinMaxSize(edict_t *e, float *min, float *max, bool rotate)\n{\n\tfloat\t*angles;\n\tvec3_t\trmin, rmax;\n\tfloat\tbounds[2][3];\n\tfloat\txvector[2], yvector[2];\n\tfloat\ta;\n\tvec3_t\tbase, transformed;\n\tint\t\ti, j, k, l;\n\n\tfor (i = 0; i<3; i++)\n\t\tif (min[i] > max[i])\n\t\t\tPR_RunError(\"backwards mins/maxs\");\n\n\trotate = false;\t\t// FIXME: implement rotation properly again\n\n\tif (!rotate)\n\t{\n\t\tVectorCopy(min, rmin);\n\t\tVectorCopy(max, rmax);\n\t}\n\telse\n\t{\n\t\t// find min / max for rotations\n\t\tangles = e->v.angles;\n\n\t\ta = angles[1] / 180 * M_PI;\n\t\tfloat ca = cosf(a);\n\t\tfloat sa = sinf(a);\n\t\t\n\t\txvector[0] = ca;\n\t\txvector[1] = sa;\n\t\tyvector[0] = -sa;\n\t\tyvector[1] = ca;\n\n\t\tVectorCopy(min, bounds[0]);\n\t\tVectorCopy(max, bounds[1]);\n\n\t\trmin[0] = rmin[1] = rmin[2] = 9999;\n\t\trmax[0] = rmax[1] = rmax[2] = -9999;\n\n\t\tfor (i = 0; i <= 1; i++)\n\t\t{\n\t\t\tbase[0] = bounds[i][0];\n\t\t\tfor (j = 0; j <= 1; j++)\n\t\t\t{\n\t\t\t\tbase[1] = bounds[j][1];\n\t\t\t\tfor (k = 0; k <= 1; k++)\n\t\t\t\t{\n\t\t\t\t\tbase[2] = bounds[k][2];\n\n\t\t\t\t\t// transform the point\n\t\t\t\t\ttransformed[0] = xvector[0] * base[0] + yvector[0] * base[1];\n\t\t\t\t\ttransformed[1] = xvector[1] * base[0] + yvector[1] * base[1];\n\t\t\t\t\ttransformed[2] = base[2];\n\n\t\t\t\t\tfor (l = 0; l<3; l++)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (transformed[l] < rmin[l])\n\t\t\t\t\t\t\trmin[l] = transformed[l];\n\t\t\t\t\t\tif (transformed[l] > rmax[l])\n\t\t\t\t\t\t\trmax[l] = transformed[l];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// set derived values\n\tVectorCopy(rmin, e->v.mins);\n\tVectorCopy(rmax, e->v.maxs);\n\tVectorSubtract(max, min, e->v.size);\n\n\tSV_LinkEdict(e, false);\n}\n\n/*\n=================\nPF_setsize\n\nthe size box is rotated by the current angle\n\nsetsize (entity, minvector, maxvector)\n=================\n*/\nvoid PF_setsize(void)\n{\n\tedict_t\t*e;\n\tfloat\t*min, *max;\n\n\te = G_EDICT(OFS_PARM0);\n\tmin = G_VECTOR(OFS_PARM1);\n\tmax = G_VECTOR(OFS_PARM2);\n\tSetMinMaxSize(e, min, max, false);\n}\n\n\n/*\n=================\nPF_setmodel\n\nsetmodel(entity, model)\n=================\n*/\nvoid PF_setmodel(void)\n{\n\tedict_t\t*e;\n\tchar\t*m, **check;\n\tmodel_t\t*mod;\n\tint\t\ti;\n\n\te = G_EDICT(OFS_PARM0);\n\tm = G_STRING(OFS_PARM1);\n\n\t// check to see if model was properly precached\n\tfor (i = 0, check = sv.model_precache; *check; i++, check++)\n\t\tif (!strcmp(*check, m))\n\t\t\tbreak;\n\n\tif (!*check)\n\t\tPR_RunError(\"no precache: %s\\n\", m);\n\n\n\te->v.model = m - pr_strings;\n\te->v.modelindex = i; //SV_ModelIndex (m);\n\n\tmod = sv.models[(int)e->v.modelindex];  // Mod_ForName (m, true);\n\n\tif (mod)\n\t\tSetMinMaxSize(e, mod->mins, mod->maxs, true);\n\telse\n\t\tSetMinMaxSize(e, vec3_origin, vec3_origin, true);\n}\n\n/*\n=================\nPF_bprint\n\nbroadcast print to everyone on server\n\nbprint(value)\n=================\n*/\nvoid PF_bprint(void)\n{\n\tchar\t\t*s;\n\n\ts = PF_VarString(0);\n\tSV_BroadcastPrintf(\"%s\", s);\n}\n\n/*\n=================\nPF_sprint\n\nsingle print to a specific client\n\nsprint(clientent, value)\n=================\n*/\nvoid PF_sprint(void)\n{\n\tchar\t\t*s;\n\tclient_t\t*client;\n\tint\t\t\tentnum;\n\n\tentnum = G_EDICTNUM(OFS_PARM0);\n\ts = PF_VarString(1);\n\n\tif (entnum < 1 || entnum > svs.maxclients)\n\t{\n\t\tCon_Printf(\"tried to sprint to a non-client\\n\");\n\t\treturn;\n\t}\n\n\tclient = &svs.clients[entnum - 1];\n\n\tMSG_WriteChar(&client->message, svc_print);\n\tMSG_WriteString(&client->message, s);\n}\n\n\n/*\n=================\nPF_centerprint\n\nsingle print to a specific client\n\ncenterprint(clientent, value)\n=================\n*/\nvoid PF_centerprint(void)\n{\n\tchar\t\t*s;\n\tclient_t\t*client;\n\tint\t\t\tentnum;\n\n\tentnum = G_EDICTNUM(OFS_PARM0);\n\ts = PF_VarString(1);\n\n\tif (entnum < 1 || entnum > svs.maxclients)\n\t{\n\t\tCon_Printf(\"tried to sprint to a non-client\\n\");\n\t\treturn;\n\t}\n\n\tclient = &svs.clients[entnum - 1];\n\n\tMSG_WriteChar(&client->message, svc_centerprint);\n\tMSG_WriteString(&client->message, s);\n}\n\n\n/*\n=================\nPF_normalize\n\nvector normalize(vector)\n=================\n*/\nvoid PF_normalize(void)\n{\n\tfloat\t*value1;\n\tvec3_t\tnewvalue;\n\tfloat\tnew;\n\n\tvalue1 = G_VECTOR(OFS_PARM0);\n\n\tnew = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] * value1[2];\n\tnew = sqrt(new);\n\n\tif (new == 0)\n\t\tnewvalue[0] = newvalue[1] = newvalue[2] = 0;\n\telse\n\t{\n\t\tnew = 1 / new;\n\t\tnewvalue[0] = value1[0] * new;\n\t\tnewvalue[1] = value1[1] * new;\n\t\tnewvalue[2] = value1[2] * new;\n\t}\n\n\tVectorCopy(newvalue, G_VECTOR(OFS_RETURN));\n}\n\n/*\n=================\nPF_vlen\n\nscalar vlen(vector)\n=================\n*/\nvoid PF_vlen(void)\n{\n\tfloat\t*value1;\n\tfloat\tnew;\n\n\tvalue1 = G_VECTOR(OFS_PARM0);\n\n\tnew = value1[0] * value1[0] + value1[1] * value1[1] + value1[2] * value1[2];\n\tnew = sqrt(new);\n\n\tG_FLOAT(OFS_RETURN) = new;\n}\n\n/*\n=================\nPF_vectoyaw\n\nfloat vectoyaw(vector)\n=================\n*/\nvoid PF_vectoyaw(void)\n{\n\tfloat\t*value1;\n\tfloat\tyaw;\n\n\tvalue1 = G_VECTOR(OFS_PARM0);\n\n\tif (value1[1] == 0 && value1[0] == 0)\n\t\tyaw = 0;\n\telse\n\t{\n\t\tyaw = (int)(atan2(value1[1], value1[0]) * 180 / M_PI);\n\t\tif (yaw < 0)\n\t\t\tyaw += 360;\n\t}\n\n\tG_FLOAT(OFS_RETURN) = yaw;\n}\n\n\n/*\n=================\nPF_vectoangles\n\nvector vectoangles(vector)\n=================\n*/\nvoid PF_vectoangles(void)\n{\n\tfloat\t*value1;\n\tfloat\tforward;\n\tfloat\tyaw, pitch;\n\n\tvalue1 = G_VECTOR(OFS_PARM0);\n\n\tif (value1[1] == 0 && value1[0] == 0)\n\t{\n\t\tyaw = 0;\n\t\tif (value1[2] > 0)\n\t\t\tpitch = 90;\n\t\telse\n\t\t\tpitch = 270;\n\t}\n\telse\n\t{\n\t\tyaw = (int)(atan2(value1[1], value1[0]) * 180 / M_PI);\n\t\tif (yaw < 0)\n\t\t\tyaw += 360;\n\n\t\tforward = sqrt(value1[0] * value1[0] + value1[1] * value1[1]);\n\t\tpitch = (int)(atan2(value1[2], forward) * 180 / M_PI);\n\t\tif (pitch < 0)\n\t\t\tpitch += 360;\n\t}\n\n\tG_FLOAT(OFS_RETURN + 0) = pitch;\n\tG_FLOAT(OFS_RETURN + 1) = yaw;\n\tG_FLOAT(OFS_RETURN + 2) = 0;\n}\n\n/*\n=================\nPF_Random\n\nReturns a number from 0<= num < 1\n\nrandom()\n=================\n*/\nvoid PF_random(void)\n{\n\tfloat\t\tnum;\n\n\tnum = (rand() & 0x7fff) / ((float)0x7fff);\n\n\tG_FLOAT(OFS_RETURN) = num;\n}\n\n/*\n=================\nPF_particle\n\nparticle(origin, color, count)\n=================\n*/\nvoid PF_particle(void)\n{\n\tfloat\t\t*org, *dir;\n\tfloat\t\tcolor;\n\tfloat\t\tcount;\n\n\torg = G_VECTOR(OFS_PARM0);\n\tdir = G_VECTOR(OFS_PARM1);\n\tcolor = G_FLOAT(OFS_PARM2);\n\tcount = G_FLOAT(OFS_PARM3);\n\tSV_StartParticle(org, dir, color, count);\n}\n\n\n/*\n=================\nPF_ambientsound\n\n=================\n*/\nvoid PF_ambientsound(void)\n{\n\tchar\t\t**check;\n\tchar\t\t*samp;\n\tfloat\t\t*pos;\n\tfloat \t\tvol, attenuation;\n\tint\t\t\ti, soundnum;\n\n\tpos = G_VECTOR(OFS_PARM0);\n\tsamp = G_STRING(OFS_PARM1);\n\tvol = G_FLOAT(OFS_PARM2);\n\tattenuation = G_FLOAT(OFS_PARM3);\n\n\t// check to see if samp was properly precached\n\tfor (soundnum = 0, check = sv.sound_precache; *check; check++, soundnum++)\n\t\tif (!strcmp(*check, samp))\n\t\t\tbreak;\n\n\tif (!*check)\n\t{\n\t\tCon_Printf(\"no precache: %s\\n\", samp);\n\t\treturn;\n\t}\n\n\t// add an svc_spawnambient command to the level signon packet\n\n\tMSG_WriteByte(&sv.signon, svc_spawnstaticsound);\n\tfor (i = 0; i<3; i++)\n\t\tMSG_WriteCoord(&sv.signon, pos[i]);\n\n\tMSG_WriteByte(&sv.signon, soundnum);\n\n\tMSG_WriteByte(&sv.signon, vol * 255);\n\tMSG_WriteByte(&sv.signon, attenuation * 64);\n\n}\n\n/*\n=================\nPF_sound\n\nEach entity can have eight independant sound sources, like voice,\nweapon, feet, etc.\n\nChannel 0 is an auto-allocate channel, the others override anything\nalready running on that entity/channel pair.\n\nAn attenuation of 0 will play full volume everywhere in the level.\nLarger attenuations will drop off.\n\n=================\n*/\nvoid PF_sound(void)\n{\n\tchar\t\t*sample;\n\tint\t\t\tchannel;\n\tedict_t\t\t*entity;\n\tint \t\tvolume;\n\tfloat attenuation;\n\n\tentity = G_EDICT(OFS_PARM0);\n\tchannel = G_FLOAT(OFS_PARM1);\n\tsample = G_STRING(OFS_PARM2);\n\tvolume = G_FLOAT(OFS_PARM3) * 255;\n\tattenuation = G_FLOAT(OFS_PARM4);\n\n\tif (volume < 0 || volume > 255)\n\t\tSys_Error(\"SV_StartSound: volume = %i\", volume);\n\n\tif (attenuation < 0 || attenuation > 4)\n\t\tSys_Error(\"SV_StartSound: attenuation = %f\", attenuation);\n\n\tif (channel < 0 || channel > 7)\n\t\tSys_Error(\"SV_StartSound: channel = %i\", channel);\n\n\tSV_StartSound(entity, channel, sample, volume, attenuation);\n}\n\n/*\n=================\nPF_break\n\nbreak()\n=================\n*/\nvoid PF_break(void)\n{\n\tCon_Printf(\"break statement\\n\");\n\t*(int *)-4 = 0;\t// dump to debugger\n\t\t\t\t\t//\tPR_RunError (\"break statement\");\n}\n\n/*\n=================\nPF_traceline\n\nUsed for use tracing and shot targeting\nTraces are blocked by bbox and exact bsp entityes, and also slide box entities\nif the tryents flag is set.\n\ntraceline (vector1, vector2, tryents)\n=================\n*/\nvoid PF_traceline(void)\n{\n\tfloat\t*v1, *v2;\n\ttrace_t\ttrace;\n\tint\t\tnomonsters;\n\tedict_t\t*ent;\n\n\tv1 = G_VECTOR(OFS_PARM0);\n\tv2 = G_VECTOR(OFS_PARM1);\n\tnomonsters = G_FLOAT(OFS_PARM2);\n\tent = G_EDICT(OFS_PARM3);\n\n\ttrace = SV_Move(v1, vec3_origin, vec3_origin, v2, nomonsters, ent);\n\n\tpr_global_struct->trace_allsolid = trace.allsolid;\n\tpr_global_struct->trace_startsolid = trace.startsolid;\n\tpr_global_struct->trace_fraction = trace.fraction;\n\tpr_global_struct->trace_inwater = trace.inwater;\n\tpr_global_struct->trace_inopen = trace.inopen;\n\tVectorCopy(trace.endpos, pr_global_struct->trace_endpos);\n\tVectorCopy(trace.plane.normal, pr_global_struct->trace_plane_normal);\n\tpr_global_struct->trace_plane_dist = trace.plane.dist;\n\tif (trace.ent)\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);\n\telse\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);\n}\n\nvoid PF_tracebox (void)\n{\n\tfloat   *v1, *v2, *mins, *maxs;\n\ttrace_t   trace;\n\tint      nomonsters;\n\tedict_t   *ent;\n\n\tv1 = G_VECTOR(OFS_PARM0);\n\tmins = G_VECTOR(OFS_PARM1);\n\tmaxs = G_VECTOR(OFS_PARM2);\n\tv2 = G_VECTOR(OFS_PARM3);\n\tnomonsters = G_FLOAT(OFS_PARM4);\n\tent = G_EDICT(OFS_PARM5);\n\n\ttrace = SV_Move (v1, mins, maxs, v2, nomonsters, ent);\n\n\tpr_global_struct->trace_allsolid = trace.allsolid;\n\tpr_global_struct->trace_startsolid = trace.startsolid;\n\tpr_global_struct->trace_fraction = trace.fraction;\n\tpr_global_struct->trace_inwater = trace.inwater;\n\tpr_global_struct->trace_inopen = trace.inopen;\n\tVectorCopy (trace.endpos, pr_global_struct->trace_endpos);\n\tVectorCopy (trace.plane.normal, pr_global_struct->trace_plane_normal);\n\tpr_global_struct->trace_plane_dist =  trace.plane.dist;   \n\tif (trace.ent)\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);\n\telse\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);\n}\n\n\n#ifdef QUAKE2\nextern trace_t SV_Trace_Toss(edict_t *ent, edict_t *ignore);\n\nvoid PF_TraceToss(void)\n{\n\ttrace_t\ttrace;\n\tedict_t\t*ent;\n\tedict_t\t*ignore;\n\n\tent = G_EDICT(OFS_PARM0);\n\tignore = G_EDICT(OFS_PARM1);\n\n\ttrace = SV_Trace_Toss(ent, ignore);\n\n\tpr_global_struct->trace_allsolid = trace.allsolid;\n\tpr_global_struct->trace_startsolid = trace.startsolid;\n\tpr_global_struct->trace_fraction = trace.fraction;\n\tpr_global_struct->trace_inwater = trace.inwater;\n\tpr_global_struct->trace_inopen = trace.inopen;\n\tVectorCopy(trace.endpos, pr_global_struct->trace_endpos);\n\tVectorCopy(trace.plane.normal, pr_global_struct->trace_plane_normal);\n\tpr_global_struct->trace_plane_dist = trace.plane.dist;\n\tif (trace.ent)\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(trace.ent);\n\telse\n\t\tpr_global_struct->trace_ent = EDICT_TO_PROG(sv.edicts);\n}\n#endif\n\n\n/*\n=================\nPF_checkpos\n\nReturns true if the given entity can move to the given position from it's\ncurrent position by walking or rolling.\nFIXME: make work...\nscalar checkpos (entity, vector)\n=================\n*/\nvoid PF_checkpos(void)\n{\n}\n\n//============================================================================\n\nbyte\tcheckpvs[MAX_MAP_LEAFS / 8];\n\nint PF_newcheckclient(int check)\n{\n\tint\t\ti;\n\tbyte\t*pvs;\n\tedict_t\t*ent;\n\tmleaf_t\t*leaf;\n\tvec3_t\torg;\n\n\t// cycle to the next one\n\n\tif (check < 1)\n\t\tcheck = 1;\n\tif (check > svs.maxclients)\n\t\tcheck = svs.maxclients;\n\n\tif (check == svs.maxclients)\n\t\ti = 1;\n\telse\n\t\ti = check + 1;\n\n\tfor (; ; i++)\n\t{\n\t\tif (i == svs.maxclients + 1)\n\t\t\ti = 1;\n\n\t\tent = EDICT_NUM(i);\n\n\t\tif (i == check)\n\t\t\tbreak;\t// didn't find anything else\n\n\t\tif (ent->free)\n\t\t\tcontinue;\n\t\tif (ent->v.health <= 0)\n\t\t\tcontinue;\n\t\tif ((int)ent->v.flags & FL_NOTARGET)\n\t\t\tcontinue;\n\n\t\t// anything that is a client, or has a client as an enemy\n\t\tbreak;\n\t}\n\n\t// get the PVS for the entity\n\tVectorAdd(ent->v.origin, ent->v.view_ofs, org);\n\tleaf = Mod_PointInLeaf(org, sv.worldmodel);\n\tpvs = Mod_LeafPVS(leaf, sv.worldmodel);\n\tmemcpy(checkpvs, pvs, (sv.worldmodel->numleafs + 7) >> 3);\n\n\treturn i;\n}\n\n/*\n=================\nPF_checkclient\n\nReturns a client (or object that has a client enemy) that would be a\nvalid target.\n\nIf there are more than one valid options, they are cycled each frame\n\nIf (self.origin + self.viewofs) is not in the PVS of the current target,\nit is not returned at all.\n\nname checkclient ()\n=================\n*/\n#define\tMAX_CHECK\t16\nint c_invis, c_notvis;\nvoid PF_checkclient(void)\n{\n\tedict_t\t*ent, *self;\n\tmleaf_t\t*leaf;\n\tint\t\tl;\n\tvec3_t\tview;\n\n\t// find a new check if on a new frame\n\tif (sv.time - sv.lastchecktime >= 0.1)\n\t{\n\t\tsv.lastcheck = PF_newcheckclient(sv.lastcheck);\n\t\tsv.lastchecktime = sv.time;\n\t}\n\n\t// return check if it might be visible\t\n\tent = EDICT_NUM(sv.lastcheck);\n\tif (ent->free || ent->v.health <= 0)\n\t{\n\t\tRETURN_EDICT(sv.edicts);\n\t\treturn;\n\t}\n\n\t// if current entity can't possibly see the check entity, return 0\n\tself = PROG_TO_EDICT(pr_global_struct->self);\n\tVectorAdd(self->v.origin, self->v.view_ofs, view);\n\tleaf = Mod_PointInLeaf(view, sv.worldmodel);\n\tl = (leaf - sv.worldmodel->leafs) - 1;\n\tif ((l<0) || !(checkpvs[l >> 3] & (1 << (l & 7))))\n\t{\n\t\tc_notvis++;\n\t\tRETURN_EDICT(sv.edicts);\n\t\treturn;\n\t}\n\n\t// might be able to see it\n\tc_invis++;\n\tRETURN_EDICT(ent);\n}\n\n//============================================================================\n\n\n/*\n=================\nPF_stuffcmd\n\nSends text over to the client's execution buffer\n\nstuffcmd (clientent, value)\n=================\n*/\nvoid PF_stuffcmd(void)\n{\n\tint\t\tentnum;\n\tchar\t*str;\n\tclient_t\t*old;\n\n\tentnum = G_EDICTNUM(OFS_PARM0);\n\tif (entnum < 1 || entnum > svs.maxclients)\n\t\tPR_RunError(\"Parm 0 not a client\");\n\tstr = G_STRING(OFS_PARM1);\n\n\told = host_client;\n\thost_client = &svs.clients[entnum - 1];\n\tHost_ClientCommands(\"%s\", str);\n\thost_client = old;\n}\n\n/*\n=================\nPF_localcmd\n\nSends text over to the client's execution buffer\n\nlocalcmd (string)\n=================\n*/\nvoid PF_localcmd(void)\n{\n\tchar\t*str;\n\n\tstr = G_STRING(OFS_PARM0);\n\tCbuf_AddText(str);\n}\n\n/*\n=================\nPF_cvar\n\nfloat cvar (string)\n=================\n*/\nvoid PF_cvar(void)\n{\n\tchar\t*str;\n\n\tstr = G_STRING(OFS_PARM0);\n\n\tG_FLOAT(OFS_RETURN) = Cvar_VariableValue(str);\n}\n\n/*\n=================\nPF_cvar_set\n\nfloat cvar (string)\n=================\n*/\nvoid PF_cvar_set(void)\n{\n\tchar\t*var, *val;\n\n\tvar = G_STRING(OFS_PARM0);\n\tval = G_STRING(OFS_PARM1);\n\n\tCvar_Set(var, val);\n}\n\n/*\n=================\nPF_findradius\n\nReturns a chain of entities that have origins within a spherical area\n\nfindradius (origin, radius)\n=================\n*/\nvoid PF_findradius(void)\n{\n\tedict_t\t*ent, *chain;\n\tfloat\trad;\n\tfloat\t*org;\n\tvec3_t\teorg;\n\tint\t\ti, j;\n\n\tchain = (edict_t *)sv.edicts;\n\n\torg = G_VECTOR(OFS_PARM0);\n\trad = G_FLOAT(OFS_PARM1);\n\n\tent = NEXT_EDICT(sv.edicts);\n\tfor (i = 1; i<sv.num_edicts; i++, ent = NEXT_EDICT(ent))\n\t{\n\t\tif (ent->free)\n\t\t\tcontinue;\n\t\tif (ent->v.solid == SOLID_NOT)\n\t\t\tcontinue;\n\t\tfor (j = 0; j<3; j++)\n\t\t\teorg[j] = org[j] - (ent->v.origin[j] + (ent->v.mins[j] + ent->v.maxs[j])*0.5);\n\t\tif (Length(eorg) > rad)\n\t\t\tcontinue;\n\n\t\tent->v.chain = EDICT_TO_PROG(chain);\n\t\tchain = ent;\n\t}\n\n\tRETURN_EDICT(chain);\n}\n\n\n/*\n=========\nPF_dprint\n=========\n*/\nvoid PF_dprint(void)\n{\n\tCon_DPrintf(\"%s\", PF_VarString(0));\n}\n\nchar\tpr_string_temp[PR_MAX_TEMPSTRING];\n\nvoid PF_ftos(void)\n{\n\tfloat\tv;\n\tv = G_FLOAT(OFS_PARM0);\n\n\tif (v == (int)v)\n\t\tsprintf(pr_string_temp, \"%d\", (int)v);\n\telse\n\t\tsprintf(pr_string_temp, \"%5.1f\", v);\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\nvoid PF_fabs(void)\n{\n\tfloat\tv;\n\tv = G_FLOAT(OFS_PARM0);\n\tG_FLOAT(OFS_RETURN) = fabs(v);\n}\n\nvoid PF_vtos(void)\n{\n\tsprintf(pr_string_temp, \"'%5.1f %5.1f %5.1f'\", G_VECTOR(OFS_PARM0)[0], G_VECTOR(OFS_PARM0)[1], G_VECTOR(OFS_PARM0)[2]);\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\nvoid PF_etos(void)\n{\n\tsprintf(pr_string_temp, \"entity %i\", G_EDICTNUM(OFS_PARM0));\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\nvoid PF_Spawn(void)\n{\n\tedict_t\t*ed;\n\ted = ED_Alloc();\n\tRETURN_EDICT(ed);\n}\n\nvoid PF_Remove(void)\n{\n\tedict_t\t*ed;\n\n\ted = G_EDICT(OFS_PARM0);\n\tED_Free(ed);\n}\n\n\n// entity (entity start, .string field, string match) find = #5;\nvoid PF_Find(void)\n{\n\tint\t\te;\n\tint\t\tf;\n\tchar\t*s, *t;\n\tedict_t\t*ed;\n\n\te = G_EDICTNUM(OFS_PARM0);\n\tf = G_INT(OFS_PARM1);\n\ts = G_STRING(OFS_PARM2);\n\tif (!s)\n\t\tPR_RunError(\"PF_Find: bad search string\");\n\n\tfor (e++; e < sv.num_edicts; e++)\n\t{\n\t\ted = EDICT_NUM(e);\n\t\tif (ed->free)\n\t\t\tcontinue;\n\t\tt = E_STRING(ed, f);\n\t\tif (!t)\n\t\t\tcontinue;\n\t\tif (!strcmp(t, s))\n\t\t{\n\t\t\tRETURN_EDICT(ed);\n\t\t\treturn;\n\t\t}\n\t}\n\n\tRETURN_EDICT(sv.edicts);\n}\n\nvoid PR_CheckEmptyString(char *s)\n{\n\tif (s[0] <= ' ')\n\t\tPR_RunError(\"Bad string\");\n}\n\nvoid PF_precache_file(void)\n{\t// precache_file is only used to copy files with qcc, it does nothing\n\tG_INT(OFS_RETURN) = G_INT(OFS_PARM0);\n}\n\nvoid PF_precache_sound(void)\n{\n\tchar\t*s;\n\tint\t\ti;\n\n\tif (sv.state != ss_loading)\n\t\tPR_RunError(\"PF_Precache_*: Precache can only be done in spawn functions\");\n\n\ts = G_STRING(OFS_PARM0);\n\tG_INT(OFS_RETURN) = G_INT(OFS_PARM0);\n\tPR_CheckEmptyString(s);\n\n\tfor (i = 0; i<MAX_SOUNDS; i++)\n\t{\n\t\tif (!sv.sound_precache[i])\n\t\t{\n\t\t\tsv.sound_precache[i] = s;\n\t\t\treturn;\n\t\t}\n\t\tif (!strcmp(sv.sound_precache[i], s))\n\t\t\treturn;\n\t}\n\tPR_RunError(\"PF_precache_sound: overflow\");\n}\n\nvoid PF_precache_model(void)\n{\n\tchar\t*s;\n\tint\t\ti;\n\n\tif (sv.state != ss_loading)\n\t\tPR_RunError(\"PF_Precache_*: Precache can only be done in spawn functions\");\n\n\ts = G_STRING(OFS_PARM0);\n\tG_INT(OFS_RETURN) = G_INT(OFS_PARM0);\n\tPR_CheckEmptyString(s);\n\n\tfor (i = 0; i<MAX_MODELS; i++)\n\t{\n\t\tif (!sv.model_precache[i])\n\t\t{\n\t\t\tsv.model_precache[i] = s;\n\t\t\tsv.models[i] = Mod_ForName(s, true);\n\t\t\treturn;\n\t\t}\n\t\tif (!strcmp(sv.model_precache[i], s))\n\t\t\treturn;\n\t}\n\tPR_RunError(\"PF_precache_model: overflow\");\n}\n\n\nvoid PF_coredump(void)\n{\n\tED_PrintEdicts();\n}\n\nvoid PF_traceon(void)\n{\n\tpr_trace = true;\n}\n\nvoid PF_traceoff(void)\n{\n\tpr_trace = false;\n}\n\nvoid PF_eprint(void)\n{\n\tED_PrintNum(G_EDICTNUM(OFS_PARM0));\n}\n\n/*\n===============\nPF_walkmove\n\nfloat(float yaw, float dist) walkmove\n===============\n*/\nvoid PF_walkmove(void)\n{\n\tedict_t\t*ent;\n\tfloat\tyaw, dist;\n\tvec3_t\tmove;\n\tdfunction_t\t*oldf;\n\tint \toldself;\n\n\tent = PROG_TO_EDICT(pr_global_struct->self);\n\tyaw = G_FLOAT(OFS_PARM0);\n\tdist = G_FLOAT(OFS_PARM1);\n\n\tif (!((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM)))\n\t{\n\t\tG_FLOAT(OFS_RETURN) = 0;\n\t\treturn;\n\t}\n\n\tyaw = yaw*M_PI * 2 / 360;\n\n\tmove[0] = cosf(yaw)*dist;\n\tmove[1] = sinf(yaw)*dist;\n\tmove[2] = 0;\n\n\t// save program state, because SV_movestep may call other progs\n\toldf = pr_xfunction;\n\toldself = pr_global_struct->self;\n\n\tG_FLOAT(OFS_RETURN) = SV_movestep(ent, move, true);\n\n\n\t// restore program state\n\tpr_xfunction = oldf;\n\tpr_global_struct->self = oldself;\n}\n\n/*\n===============\nPF_droptofloor\n\nvoid() droptofloor\n===============\n*/\nvoid PF_droptofloor(void)\n{\n\tedict_t\t\t*ent;\n\tvec3_t\t\tend;\n\ttrace_t\t\ttrace;\n\n\tent = PROG_TO_EDICT(pr_global_struct->self);\n\n\tVectorCopy(ent->v.origin, end);\n\tend[2] -= 256;\n\n\ttrace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);\n\n\tif (trace.fraction == 1 || trace.allsolid)\n\t\tG_FLOAT(OFS_RETURN) = 0;\n\telse\n\t{\n\t\tVectorCopy(trace.endpos, ent->v.origin);\n\t\tSV_LinkEdict(ent, false);\n\t\tent->v.flags = (int)ent->v.flags | FL_ONGROUND;\n\t\tent->v.groundentity = EDICT_TO_PROG(trace.ent);\n\t\tG_FLOAT(OFS_RETURN) = 1;\n\t}\n}\n\n/*\n===============\nPF_lightstyle\n\nvoid(float style, string value) lightstyle\n===============\n*/\nvoid PF_lightstyle(void)\n{\n\tint\t\tstyle;\n\tchar\t*val;\n\tclient_t\t*client;\n\tint\t\t\tj;\n\n\tstyle = G_FLOAT(OFS_PARM0);\n\tval = G_STRING(OFS_PARM1);\n\n\t// change the string in sv\n\tsv.lightstyles[style] = val;\n\n\t// send message to all clients on this server\n\tif (sv.state != ss_active)\n\t\treturn;\n\n\tfor (j = 0, client = svs.clients; j<svs.maxclients; j++, client++)\n\t\tif (client->active || client->spawned)\n\t\t{\n\t\t\tMSG_WriteChar(&client->message, svc_lightstyle);\n\t\t\tMSG_WriteChar(&client->message, style);\n\t\t\tMSG_WriteString(&client->message, val);\n\t\t}\n}\n\nvoid PF_rint(void)\n{\n\tfloat\tf;\n\tf = G_FLOAT(OFS_PARM0);\n\tif (f > 0)\n\t\tG_FLOAT(OFS_RETURN) = (int)(f + 0.5);\n\telse\n\t\tG_FLOAT(OFS_RETURN) = (int)(f - 0.5);\n}\nvoid PF_floor(void)\n{\n\tG_FLOAT(OFS_RETURN) = floor(G_FLOAT(OFS_PARM0));\n}\nvoid PF_ceil(void)\n{\n\tG_FLOAT(OFS_RETURN) = ceil(G_FLOAT(OFS_PARM0));\n}\n\n\n/*\n=============\nPF_checkbottom\n=============\n*/\nvoid PF_checkbottom(void)\n{\n\tedict_t\t*ent;\n\n\tent = G_EDICT(OFS_PARM0);\n\n\tG_FLOAT(OFS_RETURN) = SV_CheckBottom(ent);\n}\n\n/*\n=============\nPF_pointcontents\n=============\n*/\nvoid PF_pointcontents(void)\n{\n\tfloat\t*v;\n\n\tv = G_VECTOR(OFS_PARM0);\n\n\tG_FLOAT(OFS_RETURN) = SV_PointContents(v);\n}\n\n/*\n=============\nPF_nextent\n\nentity nextent(entity)\n=============\n*/\nvoid PF_nextent(void)\n{\n\tint\t\ti;\n\tedict_t\t*ent;\n\n\ti = G_EDICTNUM(OFS_PARM0);\n\twhile (1)\n\t{\n\t\ti++;\n\t\tif (i == sv.num_edicts)\n\t\t{\n\t\t\tRETURN_EDICT(sv.edicts);\n\t\t\treturn;\n\t\t}\n\t\tent = EDICT_NUM(i);\n\t\tif (!ent->free)\n\t\t{\n\t\t\tRETURN_EDICT(ent);\n\t\t\treturn;\n\t\t}\n\t}\n}\n\n/*\n=============\nPF_aim\n\nPick a vector for the player to shoot along\nvector aim(entity, missilespeed)\n=============\n*/\nCVAR (sv_aim, 0.93, CVAR_NONE)\nvoid PF_aim(void)\n{\n\tedict_t\t*ent, *check, *bestent;\n\tvec3_t\tstart, dir, end, bestdir;\n\tint\t\ti, j;\n\ttrace_t\ttr;\n\tfloat\tdist, bestdist;\n\tfloat\tspeed;\n\n\tent = G_EDICT(OFS_PARM0);\n\tspeed = G_FLOAT(OFS_PARM1);\n\n\tVectorCopy(ent->v.origin, start);\n\tstart[2] += 20;\n\n\t// try sending a trace straight\n\tVectorCopy(pr_global_struct->v_forward, dir);\n\tVectorMA(start, 2048, dir, end);\n\ttr = SV_Move(start, vec3_origin, vec3_origin, end, false, ent);\n\tif (tr.ent && tr.ent->v.takedamage == DAMAGE_AIM\n\t\t&& (!teamplay.value || ent->v.team <= 0 || ent->v.team != tr.ent->v.team))\n\t{\n\t\tVectorCopy(pr_global_struct->v_forward, G_VECTOR(OFS_RETURN));\n\t\treturn;\n\t}\n\n\n\t// try all possible entities\n\tVectorCopy(dir, bestdir);\n\tbestdist = sv_aim.value;\n\tbestent = NULL;\n\n\tcheck = NEXT_EDICT(sv.edicts);\n\tfor (i = 1; i<sv.num_edicts; i++, check = NEXT_EDICT(check))\n\t{\n\t\tif (check->v.takedamage != DAMAGE_AIM)\n\t\t\tcontinue;\n\t\tif (check == ent)\n\t\t\tcontinue;\n\t\tif (teamplay.value && ent->v.team > 0 && ent->v.team == check->v.team)\n\t\t\tcontinue;\t// don't aim at teammate\n\t\tfor (j = 0; j<3; j++)\n\t\t\tend[j] = check->v.origin[j]\n\t\t\t+ 0.5*(check->v.mins[j] + check->v.maxs[j]);\n\t\tVectorSubtract(end, start, dir);\n\t\tVectorNormalize(dir);\n\t\tdist = DotProduct(dir, pr_global_struct->v_forward);\n\t\tif (dist < bestdist)\n\t\t\tcontinue;\t// to far to turn\n\t\ttr = SV_Move(start, vec3_origin, vec3_origin, end, false, ent);\n\t\tif (tr.ent == check)\n\t\t{\t// can shoot at this one\n\t\t\tbestdist = dist;\n\t\t\tbestent = check;\n\t\t}\n\t}\n\n\tif (bestent)\n\t{\n\t\tVectorSubtract(bestent->v.origin, ent->v.origin, dir);\n\t\tdist = DotProduct(dir, pr_global_struct->v_forward);\n\t\tVectorScale(pr_global_struct->v_forward, dist, end);\n\t\tend[2] = dir[2];\n\t\tVectorNormalize(end);\n\t\tVectorCopy(end, G_VECTOR(OFS_RETURN));\n\t}\n\telse\n\t{\n\t\tVectorCopy(bestdir, G_VECTOR(OFS_RETURN));\n\t}\n}\n\n/*\n==============\nPF_changeyaw\n\nThis was a major timewaster in progs, so it was converted to C\n==============\n*/\nvoid PF_changeyaw(void)\n{\n\tedict_t\t\t*ent;\n\tfloat\t\tideal, current, move, speed;\n\n\tent = PROG_TO_EDICT(pr_global_struct->self);\n\tcurrent = anglemod(ent->v.angles[1]);\n\tideal = ent->v.ideal_yaw;\n\tspeed = ent->v.yaw_speed;\n\n\tif (current == ideal)\n\t\treturn;\n\tmove = ideal - current;\n\tif (ideal > current)\n\t{\n\t\tif (move >= 180)\n\t\t\tmove = move - 360;\n\t}\n\telse\n\t{\n\t\tif (move <= -180)\n\t\t\tmove = move + 360;\n\t}\n\tif (move > 0)\n\t{\n\t\tif (move > speed)\n\t\t\tmove = speed;\n\t}\n\telse\n\t{\n\t\tif (move < -speed)\n\t\t\tmove = -speed;\n\t}\n\n\tent->v.angles[1] = anglemod(current + move);\n}\n\n#ifdef QUAKE2\n/*\n==============\nPF_changepitch\n==============\n*/\nvoid PF_changepitch(void)\n{\n\tedict_t\t\t*ent;\n\tfloat\t\tideal, current, move, speed;\n\n\tent = G_EDICT(OFS_PARM0);\n\tcurrent = anglemod(ent->v.angles[0]);\n\tideal = ent->v.idealpitch;\n\tspeed = ent->v.pitch_speed;\n\n\tif (current == ideal)\n\t\treturn;\n\tmove = ideal - current;\n\tif (ideal > current)\n\t{\n\t\tif (move >= 180)\n\t\t\tmove = move - 360;\n\t}\n\telse\n\t{\n\t\tif (move <= -180)\n\t\t\tmove = move + 360;\n\t}\n\tif (move > 0)\n\t{\n\t\tif (move > speed)\n\t\t\tmove = speed;\n\t}\n\telse\n\t{\n\t\tif (move < -speed)\n\t\t\tmove = -speed;\n\t}\n\n\tent->v.angles[0] = anglemod(current + move);\n}\n#endif\n\n/*\n===============================================================================\n\nMESSAGE WRITING\n\n===============================================================================\n*/\n\n#define\tMSG_BROADCAST\t0\t\t// unreliable to all\n#define\tMSG_ONE\t\t\t1\t\t// reliable to one (msg_entity)\n#define\tMSG_ALL\t\t\t2\t\t// reliable to all\n#define\tMSG_INIT\t\t3\t\t// write to the init string\n\nsizebuf_t *WriteDest(void)\n{\n\tint\t\tentnum;\n\tint\t\tdest;\n\tedict_t\t*ent;\n\n\tdest = G_FLOAT(OFS_PARM0);\n\tswitch (dest)\n\t{\n\tcase MSG_BROADCAST:\n\t\treturn &sv.datagram;\n\n\tcase MSG_ONE:\n\t\tent = PROG_TO_EDICT(pr_global_struct->msg_entity);\n\t\tentnum = NUM_FOR_EDICT(ent);\n\t\tif (entnum < 1 || entnum > svs.maxclients)\n\t\t\tPR_RunError(\"WriteDest: not a client\");\n\t\treturn &svs.clients[entnum - 1].message;\n\n\tcase MSG_ALL:\n\t\treturn &sv.reliable_datagram;\n\n\tcase MSG_INIT:\n\t\treturn &sv.signon;\n\n\tdefault:\n\t\tPR_RunError(\"WriteDest: bad destination\");\n\t\tbreak;\n\t}\n\n\treturn NULL;\n}\n\nvoid PF_WriteByte(void)\n{\n\tMSG_WriteByte(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteChar(void)\n{\n\tMSG_WriteChar(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteShort(void)\n{\n\tMSG_WriteShort(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteLong(void)\n{\n\tMSG_WriteLong(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteAngle(void)\n{\n\tMSG_WriteAngle(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteCoord(void)\n{\n\tMSG_WriteCoord(WriteDest(), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_WriteString(void)\n{\n\tMSG_WriteString(WriteDest(), G_STRING(OFS_PARM1));\n}\n\n\nvoid PF_WriteEntity(void)\n{\n\tMSG_WriteShort(WriteDest(), G_EDICTNUM(OFS_PARM1));\n}\n\n//=============================================================================\n\nint SV_ModelIndex(char *name);\n\nvoid PF_makestatic(void)\n{\n\tedict_t\t*ent;\n\tint\t\ti;\n\n\tent = G_EDICT(OFS_PARM0);\n\n\tMSG_WriteByte(&sv.signon, svc_spawnstatic);\n\n\tMSG_WriteByte(&sv.signon, SV_ModelIndex(pr_strings + ent->v.model));\n\n\tMSG_WriteByte(&sv.signon, ent->v.frame);\n\tMSG_WriteByte(&sv.signon, ent->v.colormap);\n\tMSG_WriteByte(&sv.signon, ent->v.skin);\n\tfor (i = 0; i<3; i++)\n\t{\n\t\tMSG_WriteCoord(&sv.signon, ent->v.origin[i]);\n\t\tMSG_WriteAngle(&sv.signon, ent->v.angles[i]);\n\t}\n\n\t// throw the entity away now\n\tED_Free(ent);\n}\n\n//=============================================================================\n\n/*\n==============\nPF_setspawnparms\n==============\n*/\nvoid PF_setspawnparms(void)\n{\n\tedict_t\t*ent;\n\tint\t\ti;\n\tclient_t\t*client;\n\n\tent = G_EDICT(OFS_PARM0);\n\ti = NUM_FOR_EDICT(ent);\n\tif (i < 1 || i > svs.maxclients)\n\t\tPR_RunError(\"Entity is not a client\");\n\n\t// copy spawn parms out of the client_t\n\tclient = svs.clients + (i - 1);\n\n\tfor (i = 0; i< NUM_SPAWN_PARMS; i++)\n\t\t(&pr_global_struct->parm1)[i] = client->spawn_parms[i];\n}\n\n/*\n==============\nPF_changelevel\n==============\n*/\nvoid PF_changelevel(void)\n{\n#ifdef QUAKE2\n\tchar\t*s1, *s2;\n\n\tif (svs.changelevel_issued)\n\t\treturn;\n\tsvs.changelevel_issued = true;\n\n\ts1 = G_STRING(OFS_PARM0);\n\ts2 = G_STRING(OFS_PARM1);\n\n\tif ((int)pr_global_struct->serverflags & (SFL_NEW_UNIT | SFL_NEW_EPISODE))\n\t\tCbuf_AddText(va(\"changelevel %s %s\\n\", s1, s2));\n\telse\n\t\tCbuf_AddText(va(\"changelevel2 %s %s\\n\", s1, s2));\n#else\n\tchar\t*s;\n\n\t// make sure we don't issue two changelevels\n\tif (svs.changelevel_issued)\n\t\treturn;\n\tsvs.changelevel_issued = true;\n\n\ts = G_STRING(OFS_PARM0);\n\tCbuf_AddText(va(\"changelevel %s\\n\", s));\n#endif\n}\n\n\n#ifdef QUAKE2\n\n#define\tCONTENT_WATER\t-3\n#define CONTENT_SLIME\t-4\n#define CONTENT_LAVA\t-5\n\n#define FL_IMMUNE_WATER\t131072\n#define\tFL_IMMUNE_SLIME\t262144\n#define FL_IMMUNE_LAVA\t524288\n\n#define\tCHAN_VOICE\t2\n#define\tCHAN_BODY\t4\n\n#define\tATTN_NORM\t1\n\nvoid PF_WaterMove(void)\n{\n\tedict_t\t\t*self;\n\tint\t\t\tflags;\n\tint\t\t\twaterlevel;\n\tint\t\t\twatertype;\n\tfloat\t\tdrownlevel;\n\tfloat\t\tdamage = 0.0;\n\n\tself = PROG_TO_EDICT(pr_global_struct->self);\n\n\tif (self->v.movetype == MOVETYPE_NOCLIP)\n\t{\n\t\tself->v.air_finished = sv.time + 12;\n\t\tG_FLOAT(OFS_RETURN) = damage;\n\t\treturn;\n\t}\n\n\tif (self->v.health < 0)\n\t{\n\t\tG_FLOAT(OFS_RETURN) = damage;\n\t\treturn;\n\t}\n\n\tif (self->v.deadflag == DEAD_NO)\n\t\tdrownlevel = 3;\n\telse\n\t\tdrownlevel = 1;\n\n\tflags = (int)self->v.flags;\n\twaterlevel = (int)self->v.waterlevel;\n\twatertype = (int)self->v.watertype;\n\n\tif (!(flags & (FL_IMMUNE_WATER + FL_GODMODE)))\n\t\tif (((flags & FL_SWIM) && (waterlevel < drownlevel)) || (waterlevel >= drownlevel))\n\t\t{\n\t\t\tif (self->v.air_finished < sv.time)\n\t\t\t\tif (self->v.pain_finished < sv.time)\n\t\t\t\t{\n\t\t\t\t\tself->v.dmg = self->v.dmg + 2;\n\t\t\t\t\tif (self->v.dmg > 15)\n\t\t\t\t\t\tself->v.dmg = 10;\n\t\t\t\t\t//\t\t\t\t\tT_Damage (self, world, world, self.dmg, 0, FALSE);\n\t\t\t\t\tdamage = self->v.dmg;\n\t\t\t\t\tself->v.pain_finished = sv.time + 1.0;\n\t\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (self->v.air_finished < sv.time)\n\t\t\t\t//\t\t\t\tsound (self, CHAN_VOICE, \"player/gasp2.wav\", 1, ATTN_NORM);\n\t\t\t\tSV_StartSound(self, CHAN_VOICE, \"player/gasp2.wav\", 255, ATTN_NORM);\n\t\t\telse if (self->v.air_finished < sv.time + 9)\n\t\t\t\t//\t\t\t\tsound (self, CHAN_VOICE, \"player/gasp1.wav\", 1, ATTN_NORM);\n\t\t\t\tSV_StartSound(self, CHAN_VOICE, \"player/gasp1.wav\", 255, ATTN_NORM);\n\t\t\tself->v.air_finished = sv.time + 12.0;\n\t\t\tself->v.dmg = 2;\n\t\t}\n\n\tif (!waterlevel)\n\t{\n\t\tif (flags & FL_INWATER)\n\t\t{\n\t\t\t// play leave water sound\n\t\t\t//\t\t\tsound (self, CHAN_BODY, \"misc/outwater.wav\", 1, ATTN_NORM);\n\t\t\tSV_StartSound(self, CHAN_BODY, \"misc/outwater.wav\", 255, ATTN_NORM);\n\t\t\tself->v.flags = (float)(flags &~FL_INWATER);\n\t\t}\n\t\tself->v.air_finished = sv.time + 12.0;\n\t\tG_FLOAT(OFS_RETURN) = damage;\n\t\treturn;\n\t}\n\n\tif (watertype == CONTENT_LAVA)\n\t{\t// do damage\n\t\tif (!(flags & (FL_IMMUNE_LAVA + FL_GODMODE)))\n\t\t\tif (self->v.dmgtime < sv.time)\n\t\t\t{\n\t\t\t\tif (self->v.radsuit_finished < sv.time)\n\t\t\t\t\tself->v.dmgtime = sv.time + 0.2;\n\t\t\t\telse\n\t\t\t\t\tself->v.dmgtime = sv.time + 1.0;\n\t\t\t\t//\t\t\t\tT_Damage (self, world, world, 10*self.waterlevel, 0, TRUE);\n\t\t\t\tdamage = (float)(10 * waterlevel);\n\t\t\t}\n\t}\n\telse if (watertype == CONTENT_SLIME)\n\t{\t// do damage\n\t\tif (!(flags & (FL_IMMUNE_SLIME + FL_GODMODE)))\n\t\t\tif (self->v.dmgtime < sv.time && self->v.radsuit_finished < sv.time)\n\t\t\t{\n\t\t\t\tself->v.dmgtime = sv.time + 1.0;\n\t\t\t\t//\t\t\t\tT_Damage (self, world, world, 4*self.waterlevel, 0, TRUE);\n\t\t\t\tdamage = (float)(4 * waterlevel);\n\t\t\t}\n\t}\n\n\tif (!(flags & FL_INWATER))\n\t{\n\n\t\t// player enter water sound\n\t\tif (watertype == CONTENT_LAVA)\n\t\t\t//\t\t\tsound (self, CHAN_BODY, \"player/inlava.wav\", 1, ATTN_NORM);\n\t\t\tSV_StartSound(self, CHAN_BODY, \"player/inlava.wav\", 255, ATTN_NORM);\n\t\tif (watertype == CONTENT_WATER)\n\t\t\t//\t\t\tsound (self, CHAN_BODY, \"player/inh2o.wav\", 1, ATTN_NORM);\n\t\t\tSV_StartSound(self, CHAN_BODY, \"player/inh2o.wav\", 255, ATTN_NORM);\n\t\tif (watertype == CONTENT_SLIME)\n\t\t\t//\t\t\tsound (self, CHAN_BODY, \"player/slimbrn2.wav\", 1, ATTN_NORM);\n\t\t\tSV_StartSound(self, CHAN_BODY, \"player/slimbrn2.wav\", 255, ATTN_NORM);\n\n\t\tself->v.flags = (float)(flags | FL_INWATER);\n\t\tself->v.dmgtime = 0;\n\t}\n\n\tif (!(flags & FL_WATERJUMP))\n\t{\n\t\t//\t\tself.velocity = self.velocity - 0.8*self.waterlevel*frametime*self.velocity;\n\t\tVectorMA(self->v.velocity, -0.8 * self->v.waterlevel * host_frametime, self->v.velocity, self->v.velocity);\n\t}\n\n\tG_FLOAT(OFS_RETURN) = damage;\n}\n#endif\n\nvoid PF_sin(void)\n{\n\tG_FLOAT(OFS_RETURN) = sinf(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_cos(void)\n{\n\tG_FLOAT(OFS_RETURN) = cosf(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_sqrt(void)\n{\n\tG_FLOAT(OFS_RETURN) = sqrt(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_asin(void)\n{\n\tG_FLOAT(OFS_RETURN) = asin(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_acos(void)\n{\n\tG_FLOAT(OFS_RETURN) = acos(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_atan(void)\n{\n\tG_FLOAT(OFS_RETURN) = atan(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_atan2(void)\n{\n\tG_FLOAT(OFS_RETURN) = atan2(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));\n}\n\nvoid PF_tan(void)\n{\n\tG_FLOAT(OFS_RETURN) = tan(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_randomvec(void)\n{\n\tvec3_t temp;\n\tVectorRandom(temp);\n\tVectorCopy(temp, G_VECTOR(OFS_RETURN));\n}\n\n/*\n=================\nPF_min\nReturns the minimum of two or more supplied floats\nfloat min(float f1, float f2, ...)\n=================\n*/\nvoid PF_min (void)\n{\n\t// LordHavoc: 3+ argument enhancement suggested by FrikaC\n\tif (pr_argc == 2)\n\t\tG_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));\n\telse if (pr_argc >= 3)\n\t{\n\t\tint i;\n\t\tfloat f = G_FLOAT(OFS_PARM0);\n\t\tfor (i = 1;i < pr_argc;i++)\n\t\t\tif (G_FLOAT((OFS_PARM0+i*3)) < f)\n\t\t\t\tf = G_FLOAT((OFS_PARM0+i*3));\n\t\tG_FLOAT(OFS_RETURN) = f;\n\t}\n\telse\n\t\tPR_RunError(\"min: must supply at least 2 floats\\n\");\n}\n\n/*\n=================\nPF_max\nReturns the maximum of two or more supplied floats\nfloat max(float f1, float f2, ...)\n=================\n*/\nvoid PF_max (void)\n{\n\t// LordHavoc: 3+ argument enhancement suggested by FrikaC\n\tif (pr_argc == 2)\n\t\tG_FLOAT(OFS_RETURN) = max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));\n\telse if (pr_argc >= 3)\n\t{\n\t\tint i;\n\t\tfloat f = G_FLOAT(OFS_PARM0);\n\t\tfor (i = 1;i < pr_argc;i++)\n\t\t\tif (G_FLOAT((OFS_PARM0+i*3)) > f)\n\t\t\t\tf = G_FLOAT((OFS_PARM0+i*3));\n\t\tG_FLOAT(OFS_RETURN) = f;\n\t}\n\telse\n\t\tPR_RunError(\"max: must supply at least 2 floats\\n\");\n}\n\n/*\n=================\nPF_bound\nReturns number bounded by supplied range\nfloat bound(float min, float f, float max)\n=================\n*/\nvoid PF_bound (void)\n{\n\tG_FLOAT(OFS_RETURN) = min(G_FLOAT(OFS_PARM2), max(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1)));\n}\n\n/*\n=================\nPF_pow\nReturns base raised to power exp (base^exp)\nfloat pow(float base, float exp)\n=================\n*/\nvoid PF_pow(void)\n{\n\tG_FLOAT(OFS_RETURN) = pow(G_FLOAT(OFS_PARM0), G_FLOAT(OFS_PARM1));\n}\n\n// chained search for strings in entity fields\n// entity(.string field, string match) findchain = #402;\nvoid PF_findchain (void)\n{\n\tint\t\ti;\n\tint\t\tf;\n\tchar\t*s, *t;\n\tedict_t\t*ent, *chain;\n\n\tchain = (edict_t *)sv.edicts;\n\n\tf = G_INT(OFS_PARM0);\n\ts = G_STRING(OFS_PARM1);\n\tif (!s || !s[0])\n\t{\n\t\tRETURN_EDICT(sv.edicts);\n\t\treturn;\n\t}\n\n\tent = NEXT_EDICT(sv.edicts);\n\tfor (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))\n\t{\n\t\tif (ent->free)\n\t\t\tcontinue;\n\t\tt = E_STRING(ent,f);\n\t\tif (!t)\n\t\t\tcontinue;\n\t\tif (strcmp(t,s))\n\t\t\tcontinue;\n\n\t\tent->v.chain = EDICT_TO_PROG(chain);\n\t\tchain = ent;\n\t}\n\n\tRETURN_EDICT(chain);\n}\n\n// LordHavoc: chained search for float, int, and entity reference fields\n// entity(.string field, float match) findchainfloat = #403;\nvoid PF_findchainfloat (void)\n{\n\tint\t\ti;\n\tint\t\tf;\n\tfloat\ts;\n\tedict_t\t*ent, *chain;\n\n\tchain = (edict_t *)sv.edicts;\n\n\tf = G_INT(OFS_PARM0);\n\ts = G_FLOAT(OFS_PARM1);\n\n\tent = NEXT_EDICT(sv.edicts);\n\tfor (i = 1;i < sv.num_edicts;i++, ent = NEXT_EDICT(ent))\n\t{\n\t\tif (ent->free)\n\t\t\tcontinue;\n\t\tif (E_FLOAT(ent,f) != s)\n\t\t\tcontinue;\n\n\t\tent->v.chain = EDICT_TO_PROG(chain);\n\t\tchain = ent;\n\t}\n\n\tRETURN_EDICT(chain);\n}\n\nvoid PF_log(void)\n{\n\tG_FLOAT(OFS_RETURN) = log(G_FLOAT(OFS_PARM0));\n}\n\nvoid PF_bitshift(void)\n{\n\tint n1 = (int)fabs(G_FLOAT(OFS_PARM0));\n\tint n2 = (int)G_FLOAT(OFS_PARM1);\n\tif (!n1)\n\t\tG_FLOAT(OFS_RETURN) = n1;\n\telse\n\t\tif (n2 < 0)\n\t\t\tG_FLOAT(OFS_RETURN) = (n1 >> -n2);\n\t\telse\n\t\t\tG_FLOAT(OFS_RETURN) = (n1 << n2);\n}\n\nvoid PF_Fixme(void)\n{\n\tPR_RunError(\"unimplemented bulitin\");\n}\n\n// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes  start\n/*\n=================\nPF_strzone\nstring strzone (string)\n=================\n*/\nvoid PF_strzone (void)\n{\n\tchar *m, *p;\n\tm = G_STRING(OFS_PARM0);\n\tp = Z_Malloc(strlen(m) + 1);\n\tstrcpy(p, m);\n\t\n\tG_INT(OFS_RETURN) = p - pr_strings;\n}\n\n/*\n=================\nPF_strunzone\nstring strunzone (string)\n=================\n*/\nvoid PF_strunzone (void)\n{\n\tZ_Free(G_STRING(OFS_PARM0));\n\tG_INT(OFS_PARM0) = OFS_NULL; // empty the def\n};\n\n/*\n=================\nPF_strlen\nfloat strlen (string)\n=================\n*/\nvoid PF_strlen (void)\n{\n\tchar *p = G_STRING(OFS_PARM0);\n\tG_FLOAT(OFS_RETURN) = strlen(p);\n}\n\n/*\n=================\nPF_strcat\nstring strcat (string, string)\n=================\n*/\nvoid PF_strcat (void)\n{\n\tchar *s1, *s2;\n\tint\t\tmaxlen;\t// 2001-10-25 Enhanced temp string handling by Maddes\n\n\ts1 = G_STRING(OFS_PARM0);\n\ts2 = PF_VarString(1);\n\n// 2001-10-25 Enhanced temp string handling by Maddes  start\n\tpr_string_temp[0] = 0;\n\tif (strlen(s1) < PR_MAX_TEMPSTRING)\n\t{\n\t\tstrcpy(pr_string_temp, s1);\n\t}\n\telse\n\t{\n\t\tstrncpy(pr_string_temp, s1, PR_MAX_TEMPSTRING);\n\t\tpr_string_temp[PR_MAX_TEMPSTRING-1] = 0;\n\t}\n\n\tmaxlen = PR_MAX_TEMPSTRING - strlen(pr_string_temp) - 1;\t// -1 is EndOfString\n\tif (maxlen > 0)\n\t{\n\t\tif (maxlen > strlen(s2))\n\t\t{\n\t\t\tstrcat (pr_string_temp, s2);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tstrncat (pr_string_temp, s2, maxlen);\n\t\t\tpr_string_temp[PR_MAX_TEMPSTRING-1] = 0;\n\t\t}\n\t}\n// 2001-10-25 Enhanced temp string handling by Maddes  end\n\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\n/*\n=================\nPF_substring\nstring substring (string, float, float)\n=================\n*/\nvoid PF_substring (void)\n{\n\tint\t\toffset, length;\n\tint\t\tmaxoffset;\t\t// 2001-10-25 Enhanced temp string handling by Maddes\n\tchar\t*p;\n\n\tp = G_STRING(OFS_PARM0);\n\toffset = (int)G_FLOAT(OFS_PARM1); // for some reason, Quake doesn't like G_INT\n\tlength = (int)G_FLOAT(OFS_PARM2);\n\n\t// cap values\n\tmaxoffset = strlen(p);\n\tif (offset > maxoffset)\n\t{\n\t\toffset = maxoffset;\n\t}\n\tif (offset < 0)\n\t\toffset = 0;\n// 2001-10-25 Enhanced temp string handling by Maddes  start\n\tif (length >= PR_MAX_TEMPSTRING)\n\t\tlength = PR_MAX_TEMPSTRING-1;\n// 2001-10-25 Enhanced temp string handling by Maddes  end\n\tif (length < 0)\n\t\tlength = 0;\n\n\tp += offset;\n\tstrncpy(pr_string_temp, p, length);\n\tpr_string_temp[length]=0;\n\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\n/*\n=================\nPF_stof\nfloat stof (string)\n=================\n*/\n// thanks Zoid, taken from QuakeWorld\nvoid PF_stof (void)\n{\n\tchar\t*s;\n\t\n\ts = G_STRING(OFS_PARM0);\n\tG_FLOAT(OFS_RETURN) = atof(s);\n}\n\n/*\n=================\nPF_stov\nvector stov (string)\n=================\n*/\nvoid PF_stov (void)\n{\n\tchar *v;\n\tint i;\n\tvec3_t d;\n\n\tv = G_STRING(OFS_PARM0);\n\n\tfor (i=0; i<3; i++)\n\t{\n\t\twhile(v && (v[0] == ' ' || v[0] == '\\'')) //skip unneeded data\n\t\t\tv++;\n\t\td[i] = atof(v);\n\t\twhile (v && v[0] != ' ') // skip to next space\n\t\t\tv++;\n\t}\n\tVectorCopy (d, G_VECTOR(OFS_RETURN));\n}\n// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes  end\n\n// 2001-09-20 QuakeC file access by FrikaC/Maddes  start\n/*\n=================\nPF_fopen\nfloat fopen (string,float)\n=================\n*/\nvoid PF_fopen (void)\n{\n\tchar *p = G_STRING(OFS_PARM0);\n\tchar *ftemp;\n\tint fmode = G_FLOAT(OFS_PARM1);\n\tint h = 0, fsize = 0;\n\n\tswitch (fmode)\n\t{\n\t\tcase 0: // read\n\t\t\tSys_FileOpenRead (va(\"%s/%s\",com_gamedir, p), &h);\n\t\t\tG_FLOAT(OFS_RETURN) = (float) h;\n\t\t\treturn;\n\t\tcase 1: // append -- this is nasty\n\t\t\t// copy whole file into the zone\n\t\t\tfsize = Sys_FileOpenRead(va(\"%s/%s\",com_gamedir, p), &h);\n\t\t\tif (h == -1)\n\t\t\t{\n\t\t\t\th = Sys_FileOpenWrite(va(\"%s/%s\",com_gamedir, p));\n\t\t\t\tG_FLOAT(OFS_RETURN) = (float) h;\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tftemp = Z_Malloc(fsize + 1);\n\t\t\tSys_FileRead(h, ftemp, fsize);\n\t\t\tSys_FileClose(h);\n\t\t\t// spit it back out\n\t\t\th = Sys_FileOpenWrite(va(\"%s/%s\",com_gamedir, p));\n\t\t\tSys_FileWrite(h, ftemp, fsize);\n\t\t\tZ_Free(ftemp); // free it from memory\n\t\t\tG_FLOAT(OFS_RETURN) = (float) h;  // return still open handle\n\t\t\treturn;\n\t\tdefault: // write\n\t\t\th = Sys_FileOpenWrite (va(\"%s/%s\", com_gamedir, p));\n\t\t\tG_FLOAT(OFS_RETURN) = (float) h;\n\t\t\treturn;\n\t}\n}\n\n/*\n=================\nPF_fclose\nvoid fclose (float)\n=================\n*/\nvoid PF_fclose (void)\n{\n\tint h = (int)G_FLOAT(OFS_PARM0);\n\tSys_FileClose(h);\n}\n\n/*\n=================\nPF_fgets\nstring fgets (float)\n=================\n*/\nvoid PF_fgets (void)\n{\n\t// reads one line (up to a \\n) into a string\n\tint\t\th;\n\tint\t\ti;\n\tint\t\tcount;\n\tchar\tbuffer;\n\n\th = (int)G_FLOAT(OFS_PARM0);\n\t\n\tcount = Sys_FileRead(h, &buffer, 1);\n\tif (count && buffer == '\\r')\t// carriage return\n\t{\n\t\tcount = Sys_FileRead(h, &buffer, 1);\t// skip\n\t}\n\tif (!count)\t// EndOfFile\n\t{\n\t\tG_INT(OFS_RETURN) = OFS_NULL;\t// void string\n\t\treturn;\n\t}\n\n\ti = 0;\n\twhile (count && buffer != '\\n')\n\t{\n\t\tif (i < PR_MAX_TEMPSTRING-1)\t// no place for character in temp string\n\t\t{\n\t\t\tpr_string_temp[i++] = buffer;\n\t\t}\n\n\t\t// read next character\n\t\tcount = Sys_FileRead(h, &buffer, 1);\n\t\tif (count && buffer == '\\r')\t// carriage return\n\t\t{\n\t\t\tcount = Sys_FileRead(h, &buffer, 1);\t// skip\n\t\t}\n\t};\n\tpr_string_temp[i] = 0;\n\n\tG_INT(OFS_RETURN) = pr_string_temp - pr_strings;\n}\n\n/*\n=================\nPF_fputs\nvoid fputs (float,string)\n=================\n*/\nvoid PF_fputs (void)\n{\n\t// writes to file, like bprint\n\tfloat handle = G_FLOAT(OFS_PARM0);\n\tchar *str = PF_VarString(1);\n\tSys_FileWrite (handle, str, strlen(str));\n}\n// 2001-09-20 QuakeC file access by FrikaC/Maddes  end\n\n// 2001-09-16 New BuiltIn Function: cmd_find() by Maddes  start\n/*\n=================\nPF_cmd_find\nfloat cmd_find (string)\n=================\n*/\nvoid PF_cmd_find (void)\n{\n\tchar\t*cmdname;\n\tfloat\tresult;\n\n\tcmdname = G_STRING(OFS_PARM0);\n\tresult = Cmd_Exists (cmdname);\n\tG_FLOAT(OFS_RETURN) = result;\n}\n// 2001-09-16 New BuiltIn Function: cmd_find() by Maddes  end\n\n// 2001-09-16 New BuiltIn Function: cvar_find() by Maddes  start\n/*\n=================\nPF_cvar_find\nfloat cvar_find (string)\n=================\n*/\nvoid PF_cvar_find (void)\n{\n\tchar\t*varname;\n\tfloat\tresult;\n\n\tvarname = G_STRING(OFS_PARM0);\n\tresult = 0;\n\tif (Cvar_FindVar (varname))\n\t{\n\t\tresult = 1;\n\t}\n\tG_FLOAT(OFS_RETURN) = result;\n}\n// 2001-09-16 New BuiltIn Function: cvar_find() by Maddes  end\n\n// 2001-09-16 New BuiltIn Function: cvar_string() by Maddes  start\n/*\n=================\nPF_cvar_string\nstring cvar_string (string)\n=================\n*/\nvoid PF_cvar_string (void)\n{\n\tchar\t*varname;\n\tcvar_t\t*var;\n\tvarname = G_STRING(OFS_PARM0);\n\tvar = Cvar_FindVar (varname);\n\tif (!var)\n\t{\n\t\tCon_DPrintf (\"Cvar_String: variable \\\"%s\\\" not found\\n\", varname);\t// 2001-09-09 Made 'Cvar not found' a developer message by Maddes\n\t\tG_INT(OFS_RETURN) = OFS_NULL;\n\t}\n\telse\n\t{\n\t\tG_INT(OFS_RETURN) = var->string - pr_strings;\n\t}\n}\n// 2001-09-16 New BuiltIn Function: cvar_string() by Maddes  end\n\n// 2001-09-16 New BuiltIn Function: WriteFloat() by Maddes  start\n/*\nPF_WriteFloat\nvoid (float to, float f) WriteFloat\n*/\nvoid PF_WriteFloat (void)\n{\n\tMSG_WriteFloat (WriteDest(), G_FLOAT(OFS_PARM1));\n}\n// 2001-09-16 New BuiltIn Function: WriteFloat() by Maddes  end\n\n// 2001-09-25 New BuiltIn Function: etof() by Maddes  start\n/*\n=================\nPF_etof\nfloat etof (entity)\n=================\n*/\nvoid PF_etof (void)\n{\n\tG_FLOAT(OFS_RETURN) = G_EDICTNUM(OFS_PARM0);\n}\n// 2001-09-25 New BuiltIn Function: etof() by Maddes  end\n\n// 2001-09-25 New BuiltIn Function: ftoe() by Maddes  start\n/*\n=================\nPF_ftoe\nentity ftoe (float)\n=================\n*/\nvoid PF_ftoe (void)\n{\n\tedict_t\t\t*e;\n\te = EDICT_NUM(G_FLOAT(OFS_PARM0));\n\tRETURN_EDICT(e);\n}\n// 2001-09-25 New BuiltIn Function: ftoe() by Maddes  end\n\nbuiltin_t *pr_builtins;\nint pr_numbuiltins;\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\n// for builtin function definitions see Quake Standards Group at http://www.quakesrc.org/\n\n/*\n=================\nPF_builtin_find\nfloat builtin_find (string)\n=================\n*/\nvoid PF_builtin_find (void)\n{\n\tint\t\tj;\n\tfloat\tfuncno;\n\tchar\t*funcname;\n\n\tfuncno = 0;\n\tfuncname = G_STRING(OFS_PARM0);\n\n\t// search function name\n\tfor ( j=1 ; j < pr_ebfs_numbuiltins ; j++)\n\t{\n\t\tif ((pr_ebfs_builtins[j].funcname) && (!(strcasecmp(funcname,pr_ebfs_builtins[j].funcname))))\n\t\t{\n\t\t\tbreak;\t// found\n\t\t}\n\t}\n\n\tif (j < pr_ebfs_numbuiltins)\n\t{\n\t\tfuncno = pr_ebfs_builtins[j].funcno;\n\t}\n\n\tG_FLOAT(OFS_RETURN) = funcno;\n\n}\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\nebfs_builtin_t pr_ebfs_builtins[] = {\n\t{   0, NULL, PF_Fixme },\t\t// has to be first entry as it is needed for initialization in PR_LoadProgs()\n\t{   1, \"makevectors\", PF_makevectors },\t// void(entity e)\tmakevectors \t\t= #1;\n\t{   2, \"setorigin\", PF_setorigin },\t\t// void(entity e, vector o) setorigin\t= #2;\n\t{   3, \"setmodel\", PF_setmodel },\t\t// void(entity e, string m) setmodel\t= #3;\n\t{   4, \"setsize\", PF_setsize },\t\t\t// void(entity e, vector min, vector max) setsize = #4;\n//\t{   5, \"fixme\", PF_Fixme },\t\t\t\t// void(entity e, vector min, vector max) setabssize = #5;\n\t{   6, \"break\", PF_break },\t\t\t\t// void() break\t\t\t\t\t\t= #6;\n\t{   7, \"random\", PF_random },\t\t\t// float() random\t\t\t\t\t\t= #7;\n\t{   8, \"sound\", PF_sound },\t\t\t\t// void(entity e, float chan, string samp) sound = #8;\n\t{   9, \"normalize\", PF_normalize },\t\t// vector(vector v) normalize\t\t\t= #9;\n\t{  10, \"error\", PF_error },\t\t\t\t// void(string e) error\t\t\t\t= #10;\n\t{  11, \"objerror\", PF_objerror },\t\t// void(string e) objerror\t\t\t\t= #11;\n\t{  12, \"vlen\", PF_vlen },\t\t\t\t// float(vector v) vlen\t\t\t\t= #12;\n\t{  13, \"vectoyaw\", PF_vectoyaw },\t\t// float(vector v) vectoyaw\t\t= #13;\n\t{  14, \"spawn\", PF_Spawn },\t\t\t\t// entity() spawn\t\t\t\t\t\t= #14;\n\t{  15, \"remove\", PF_Remove },\t\t\t// void(entity e) remove\t\t\t\t= #15;\n\t{  16, \"traceline\", PF_traceline },\t\t// float(vector v1, vector v2, float tryents) traceline = #16;\n\t{  17, \"checkclient\", PF_checkclient },\t// entity() clientlist\t\t\t\t\t= #17;\n\t{  18, \"find\", PF_Find },\t\t\t\t// entity(entity start, .string fld, string match) find = #18;\n\t{  19, \"precache_sound\", PF_precache_sound },\t// void(string s) precache_sound\t\t= #19;\n\t{  20, \"precache_model\", PF_precache_model },\t// void(string s) precache_model\t\t= #20;\n\t{  21, \"stuffcmd\", PF_stuffcmd },\t\t// void(entity client, string s)stuffcmd = #21;\n\t{  22, \"findradius\", PF_findradius },\t// entity(vector org, float rad) findradius = #22;\n\t{  23, \"bprint\", PF_bprint },\t\t\t// void(string s) bprint\t\t\t\t= #23;\n\t{  24, \"sprint\", PF_sprint },\t\t\t// void(entity client, string s) sprint = #24;\n\t{  25, \"dprint\", PF_dprint },\t\t\t// void(string s) dprint\t\t\t\t= #25;\n\t{  26, \"ftos\", PF_ftos },\t\t\t\t// void(string s) ftos\t\t\t\t= #26;\n\t{  27, \"vtos\", PF_vtos },\t\t\t\t// void(string s) vtos\t\t\t\t= #27;\n\t{  28, \"coredump\", PF_coredump },\n\t{  29, \"traceon\", PF_traceon },\n\t{  30, \"traceoff\", PF_traceoff },\n\t{  31, \"eprint\", PF_eprint },\t\t\t// void(entity e) debug print an entire entity\n\t{  32, \"walkmove\", PF_walkmove },\t\t// float(float yaw, float dist) walkmove\n\t{  34, \"droptofloor\", PF_droptofloor },\n\t{  35, \"lightstyle\", PF_lightstyle },\n\t{  36, \"rint\", PF_rint },\n\t{  37, \"floor\", PF_floor },\n\t{  38, \"ceil\", PF_ceil },\n\t{  40, \"checkbottom\", PF_checkbottom },\n\t{  41, \"pointcontents\", PF_pointcontents },\n\t{  43, \"fabs\", PF_fabs },\n\t{  44, \"aim\", PF_aim },\n\t{  45, \"cvar\", PF_cvar },\n\t{  46, \"localcmd\", PF_localcmd },\n\t{  47, \"nextent\", PF_nextent },\n\t{  48, \"particle\", PF_particle },\n\t{  49, \"ChangeYaw\", PF_changeyaw },\n\t{  51, \"vectoangles\", PF_vectoangles },\n\t{  52, \"WriteByte\", PF_WriteByte },\n\t{  53, \"WriteChar\", PF_WriteChar },\n\t{  54, \"WriteShort\", PF_WriteShort },\n\t{  55, \"WriteLong\", PF_WriteLong },\n\t{  56, \"WriteCoord\", PF_WriteCoord },\n\t{  57, \"WriteAngle\", PF_WriteAngle },\n\t{  58, \"WriteString\", PF_WriteString },\n\t{  59, \"WriteEntity\", PF_WriteEntity },\n\t{  60, \"sin\", PF_sin },\n\t{  61, \"cos\", PF_cos },\n\t{  62, \"sqrt\", PF_sqrt },\n#ifdef QUAKE2\n\t{  63, \"changepitch\", PF_changepitch },\n\t{  64, \"TraceToss\", PF_TraceToss },\n#endif\n\t{  65, \"etos\", PF_etos },\n#ifdef QUAKE2\n\t{  66, \"WaterMove\", PF_WaterMove },\n#endif\n\t{  67, \"movetogoal\", SV_MoveToGoal },\n\t{  68, \"precache_file\", PF_precache_file },\n\t{  69, \"makestatic\", PF_makestatic },\n\t{  70, \"changelevel\", PF_changelevel },\n\t{  72, \"cvar_set\", PF_cvar_set },\n\t{  73, \"centerprint\", PF_centerprint },\n\t{  74, \"ambientsound\", PF_ambientsound },\n\t{  75, \"precache_model2\", PF_precache_model },\n\t{  76, \"precache_sound2\", PF_precache_sound },\t// precache_sound2 is different only for qcc\n\t{  77, \"precache_file2\", PF_precache_file },\n\t{  78, \"setspawnparms\", PF_setspawnparms },\n\t{  81, \"stof\", PF_stof },\t// 2001-09-20 QuakeC string manipulation by FrikaC/Maddes\n\t{  90, \"tracebox\", PF_tracebox},\n\t{  91, \"randomvec\", PF_randomvec},\n\t{  94, \"min\", PF_min},\n\t{  95, \"max\", PF_max},\n\t{  96, \"bound\", PF_bound},\n\t{  97, \"pow\", PF_pow },\n\t{ PR_DEFAULT_FUNCNO_EXTENSION_FIND, \"extension_find\", PF_extension_find },\t// 2001-10-20 Extension System by Lord Havoc/Maddes\n\t{ PR_DEFAULT_FUNCNO_BUILTIN_FIND, \"builtin_find\", PF_builtin_find },\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes\n\t{ 101, \"cmd_find\", PF_cmd_find },\t\t// 2001-09-16 New BuiltIn Function: cmd_find() by Maddes\n\t{ 102, \"cvar_find\", PF_cvar_find },\t\t// 2001-09-16 New BuiltIn Function: cvar_find() by Maddes\n\t{ 107, \"WriteFloat\", PF_WriteFloat },\t// 2001-09-16 New BuiltIn Function: WriteFloat() by Maddes\n\t{ 110, \"fopen\", PF_fopen },\n\t{ 111, \"fclose\", PF_fclose },\n\t{ 112, \"fgets\", PF_fgets },\n\t{ 113, \"fputs\", PF_fputs },\n\t{ 114, \"strlen\", PF_strlen },\n\t{ 115, \"strcat\", PF_strcat },\n\t{ 116, \"substring\", PF_substring },\n\t{ 117, \"stov\", PF_stov },\n\t{ 118, \"strzone\", PF_strzone },\n\t{ 119, \"strunzone\", PF_strunzone },\n\t{ 218, \"bitshift\", PF_bitshift },\n\t{ 400, \"copyentity\", PF_copyentity },\n\t{ 402, \"findchain\", PF_findchain },\n\t{ 403, \"findchainfloat\", PF_findchainfloat },\n\t{ 448, \"cvar_string\", PF_cvar_string },\t// 2001-09-16 New BuiltIn Function: cvar_string() by Maddes\n\t{ 459, \"ftoe\", PF_ftoe },\t// 2001-09-25 New BuiltIn Function: ftoe() by Maddes\n\t{ 471, \"asin\", PF_asin },\n\t{ 472, \"acos\", PF_acos },\n\t{ 473, \"atan\", PF_atan },\n\t{ 474, \"atan2\", PF_atan2 },\n\t{ 475, \"tan\", PF_tan },\n\t{ 512, \"etof\", PF_etof },\t// 2001-09-25 New BuiltIn Function: etof() by Maddes\n\t{ 532, \"log\", PF_log }\n};\n\nint pr_ebfs_numbuiltins = sizeof(pr_ebfs_builtins)/sizeof(pr_ebfs_builtins[0]);\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end"
  },
  {
    "path": "source/pr_comp.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// this file is shared by quake and qcc\n\ntypedef int\tfunc_t;\ntypedef int\tstring_t;\n\ntypedef enum {ev_void, ev_string, ev_float, ev_vector, ev_entity, ev_field, ev_function, ev_pointer} etype_t;\n\n\n#define\tOFS_NULL\t\t0\n#define\tOFS_RETURN\t\t1\n#define\tOFS_PARM0\t\t4\t\t// leave 3 ofs for each parm to hold vectors\n#define\tOFS_PARM1\t\t7\n#define\tOFS_PARM2\t\t10\n#define\tOFS_PARM3\t\t13\n#define\tOFS_PARM4\t\t16\n#define\tOFS_PARM5\t\t19\n#define\tOFS_PARM6\t\t22\n#define\tOFS_PARM7\t\t25\n#define\tRESERVED_OFS\t28\n\n\nenum {\n\tOP_DONE,\n\tOP_MUL_F,\n\tOP_MUL_V,\n\tOP_MUL_FV,\n\tOP_MUL_VF,\n\tOP_DIV_F,\n\tOP_ADD_F,\n\tOP_ADD_V,\n\tOP_SUB_F,\n\tOP_SUB_V,\n\t\n\tOP_EQ_F,\n\tOP_EQ_V,\n\tOP_EQ_S,\n\tOP_EQ_E,\n\tOP_EQ_FNC,\n\t\n\tOP_NE_F,\n\tOP_NE_V,\n\tOP_NE_S,\n\tOP_NE_E,\n\tOP_NE_FNC,\n\t\n\tOP_LE,\n\tOP_GE,\n\tOP_LT,\n\tOP_GT,\n\n\tOP_LOAD_F,\n\tOP_LOAD_V,\n\tOP_LOAD_S,\n\tOP_LOAD_ENT,\n\tOP_LOAD_FLD,\n\tOP_LOAD_FNC,\n\n\tOP_ADDRESS,\n\n\tOP_STORE_F,\n\tOP_STORE_V,\n\tOP_STORE_S,\n\tOP_STORE_ENT,\n\tOP_STORE_FLD,\n\tOP_STORE_FNC,\n\n\tOP_STOREP_F,\n\tOP_STOREP_V,\n\tOP_STOREP_S,\n\tOP_STOREP_ENT,\n\tOP_STOREP_FLD,\n\tOP_STOREP_FNC,\n\n\tOP_RETURN,\n\tOP_NOT_F,\n\tOP_NOT_V,\n\tOP_NOT_S,\n\tOP_NOT_ENT,\n\tOP_NOT_FNC,\n\tOP_IF,\n\tOP_IFNOT,\n\tOP_CALL0,\n\tOP_CALL1,\n\tOP_CALL2,\n\tOP_CALL3,\n\tOP_CALL4,\n\tOP_CALL5,\n\tOP_CALL6,\n\tOP_CALL7,\n\tOP_CALL8,\n\tOP_STATE,\n\tOP_GOTO,\n\tOP_AND,\n\tOP_OR,\n\t\n\tOP_BITAND,\n\tOP_BITOR\n};\n\n\ntypedef struct statement_s\n{\n\tunsigned short\top;\n\tunsigned short\ta,b,c;\n} dstatement_t;\n\ntypedef struct\n{\n\tunsigned short\ttype;\t\t// if DEF_SAVEGLOBGAL bit is set\n\t\t\t\t\t\t\t\t// the variable needs to be saved in savegames\n\tunsigned short\tofs;\n\tint\t\t\ts_name;\n} ddef_t;\n#define\tDEF_SAVEGLOBAL\t(1<<15)\n\n#define\tMAX_PARMS\t8\n\ntypedef struct\n{\n\tint\t\tfirst_statement;\t// negative numbers are builtins\n\tint\t\tparm_start;\n\tint\t\tlocals;\t\t\t\t// total ints of parms + locals\n\t\n\tint\t\tprofile;\t\t// runtime\n\t\n\tint\t\ts_name;\n\tint\t\ts_file;\t\t\t// source file defined in\n\t\n\tint\t\tnumparms;\n\tbyte\tparm_size[MAX_PARMS];\n} dfunction_t;\n\n\n#define\tPROG_VERSION\t6\ntypedef struct\n{\n\tint\t\tversion;\n\tint\t\tcrc;\t\t\t// check of header file\n\t\n\tint\t\tofs_statements;\n\tint\t\tnumstatements;\t// statement 0 is an error\n\n\tint\t\tofs_globaldefs;\n\tint\t\tnumglobaldefs;\n\t\n\tint\t\tofs_fielddefs;\n\tint\t\tnumfielddefs;\n\t\n\tint\t\tofs_functions;\n\tint\t\tnumfunctions;\t// function 0 is an empty\n\t\n\tint\t\tofs_strings;\n\tint\t\tnumstrings;\t\t// first string is a null string\n\n\tint\t\tofs_globals;\n\tint\t\tnumglobals;\n\t\n\tint\t\tentityfields;\n} dprograms_t;\n\n"
  },
  {
    "path": "source/pr_edict.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sv_edict.c -- entity dictionary\n\n#include \"quakedef.h\"\n\ndprograms_t\t\t*progs;\ndfunction_t\t\t*pr_functions;\nchar\t\t\t*pr_strings;\nddef_t\t\t\t*pr_fielddefs;\nddef_t\t\t\t*pr_globaldefs;\ndstatement_t\t*pr_statements;\nglobalvars_t\t*pr_global_struct;\nfloat\t\t\t*pr_globals;\t\t\t// same as pr_global_struct\nint\t\t\t\tpr_edict_size;\t// in bytes\n\nunsigned short\t\tpr_crc;\n\nint\t\ttype_size[8] = {1,sizeof(string_t)/4,1,3,1,1,sizeof(func_t)/4,sizeof(void *)/4};\n\nddef_t *ED_FieldAtOfs (int ofs);\nbool\tED_ParseEpair (void *base, ddef_t *key, char *s);\n\ncvar_t\tnomonsters = {\"nomonsters\", \"0\"};\ncvar_t\tgamecfg = {\"gamecfg\", \"0\"};\ncvar_t\tscratch1 = {\"scratch1\", \"0\"};\ncvar_t\tscratch2 = {\"scratch2\", \"0\"};\ncvar_t\tscratch3 = {\"scratch3\", \"0\"};\ncvar_t\tscratch4 = {\"scratch4\", \"0\"};\ncvar_t\tsavedgamecfg = {\"savedgamecfg\", \"0\", true};\ncvar_t\tsaved1 = {\"saved1\", \"0\", true};\ncvar_t\tsaved2 = {\"saved2\", \"0\", true};\ncvar_t\tsaved3 = {\"saved3\", \"0\", true};\ncvar_t\tsaved4 = {\"saved4\", \"0\", true};\ncvar_t\tpr_checkextension = {\"pr_checkextension\", \"0\", false, false};\t// 2001-10-20 Extension System by LordHavoc (DP compatibility)\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\ncvar_t\tpr_builtin_find = {\"pr_builtin_find\", \"0\", false, false};\ncvar_t\tpr_builtin_remap = {\"pr_builtin_remap\", \"0\", false, false};\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\n#define\tMAX_FIELD_LEN\t64\n#define GEFV_CACHESIZE\t2\n\ntypedef struct {\n\tddef_t\t*pcache;\n\tchar\tfield[MAX_FIELD_LEN];\n} gefv_cache;\n\nstatic gefv_cache\tgefvCache[GEFV_CACHESIZE] = {{NULL, \"\"}, {NULL, \"\"}};\n\nint eval_alpha;\nint eval_renderamt;\nint eval_nodrawtoclient;\nint eval_drawonlytoclient;\n\nddef_t *ED_FindField (char *name);\ndfunction_t *ED_FindFunction (char *name);\n\nint FindFieldOffset (char *field)\n{\n\tddef_t   *d;\n\n\tif (!(d = ED_FindField(field)))\n\t\treturn 0;\n\n\treturn d->ofs*4;\n}\n\ndfunction_t *EndFrameQC;\nvoid FindEdictFieldOffsets (void)\n{\n\teval_alpha = FindFieldOffset (\"alpha\");\n\teval_renderamt = FindFieldOffset (\"renderamt\");\n\teval_nodrawtoclient = FindFieldOffset(\"nodrawtoclient\");\n\teval_drawonlytoclient = FindFieldOffset(\"drawonlytoclient\");\n\t\n\tEndFrameQC = ED_FindFunction (\"EndFrame\");\n}\n\n/*\n=================\nED_ClearEdict\n\nSets everything to NULL\n=================\n*/\nvoid ED_ClearEdict (edict_t *e)\n{\n\tmemset (&e->v, 0, progs->entityfields * 4);\n\te->free = false;\n}\n\n/*\n=================\nED_Alloc\n\nEither finds a free edict, or allocates a new one.\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*/\nedict_t *ED_Alloc (void)\n{\n\tint\t\t\ti;\n\tedict_t\t\t*e;\n\n\tfor ( i=svs.maxclients+1 ; i<sv.num_edicts ; i++)\n\t{\n\t\te = EDICT_NUM(i);\n\t\t// the first couple seconds of server time can involve a lot of\n\t\t// freeing and allocating, so relax the replacement policy\n\t\tif (e->free && ( e->freetime < 2 || sv.time - e->freetime > 0.5 ) )\n\t\t{\n\t\t\tED_ClearEdict (e);\n\t\t\treturn e;\n\t\t}\n\t}\n\t\n\tif (i == MAX_EDICTS)\n\t\tSys_Error (\"ED_Alloc: no free edicts\");\n\t\t\n\tsv.num_edicts++;\n\te = EDICT_NUM(i);\n\tED_ClearEdict (e);\n\n\treturn e;\n}\n\n/*\n=================\nED_Free\n\nMarks the edict as free\nFIXME: walk all entities and NULL out references to this entity\n=================\n*/\nvoid ED_Free (edict_t *ed)\n{\n\tSV_UnlinkEdict (ed);\t\t// unlink from world bsp\n\n\ted->free = true;\n\ted->v.model = 0;\n\ted->v.takedamage = 0;\n\ted->v.modelindex = 0;\n\ted->v.colormap = 0;\n\ted->v.skin = 0;\n\ted->v.frame = 0;\n\tVectorCopy (vec3_origin, ed->v.origin);\n\tVectorCopy (vec3_origin, ed->v.angles);\n\ted->v.nextthink = -1;\n\ted->v.solid = 0;\n\t\n\ted->freetime = sv.time;\n}\n\n//===========================================================================\n\n/*\n============\nED_GlobalAtOfs\n============\n*/\nddef_t *ED_GlobalAtOfs (int ofs)\n{\n\tddef_t\t\t*def;\n\tint\t\t\ti;\n\t\n\tfor (i=0 ; i<progs->numglobaldefs ; i++)\n\t{\n\t\tdef = &pr_globaldefs[i];\n\t\tif (def->ofs == ofs)\n\t\t\treturn def;\n\t}\n\treturn NULL;\n}\n\n/*\n============\nED_FieldAtOfs\n============\n*/\nddef_t *ED_FieldAtOfs (int ofs)\n{\n\tddef_t\t\t*def;\n\tint\t\t\ti;\n\t\n\tfor (i=0 ; i<progs->numfielddefs ; i++)\n\t{\n\t\tdef = &pr_fielddefs[i];\n\t\tif (def->ofs == ofs)\n\t\t\treturn def;\n\t}\n\treturn NULL;\n}\n\n/*\n============\nED_FindField\n============\n*/\nddef_t *ED_FindField (char *name)\n{\n\tddef_t\t\t*def;\n\tint\t\t\ti;\n\t\n\tfor (i=0 ; i<progs->numfielddefs ; i++)\n\t{\n\t\tdef = &pr_fielddefs[i];\n\t\tif (!strcmp(pr_strings + def->s_name,name) )\n\t\t\treturn def;\n\t}\n\treturn NULL;\n}\n\n\n/*\n============\nED_FindGlobal\n============\n*/\nddef_t *ED_FindGlobal (char *name)\n{\n\tddef_t\t\t*def;\n\tint\t\t\ti;\n\t\n\tfor (i=0 ; i<progs->numglobaldefs ; i++)\n\t{\n\t\tdef = &pr_globaldefs[i];\n\t\tif (!strcmp(pr_strings + def->s_name,name) )\n\t\t\treturn def;\n\t}\n\treturn NULL;\n}\n\n\n/*\n============\nED_FindFunction\n============\n*/\ndfunction_t *ED_FindFunction (char *name)\n{\n\tdfunction_t\t\t*func;\n\tint\t\t\t\ti;\n\t\n\tfor (i=0 ; i<progs->numfunctions ; i++)\n\t{\n\t\tfunc = &pr_functions[i];\n\t\tif (!strcmp(pr_strings + func->s_name,name) )\n\t\t\treturn func;\n\t}\n\treturn NULL;\n}\n\n\neval_t *GetEdictFieldValue(edict_t *ed, char *field)\n{\n\tddef_t\t\t\t*def = NULL;\n\tint\t\t\t\ti;\n\tstatic int\t\trep = 0;\n\n\tfor (i=0 ; i<GEFV_CACHESIZE ; i++)\n\t{\n\t\tif (!strcmp(field, gefvCache[i].field))\n\t\t{\n\t\t\tdef = gefvCache[i].pcache;\n\t\t\tgoto Done;\n\t\t}\n\t}\n\n\tdef = ED_FindField (field);\n\n\tif (strlen(field) < MAX_FIELD_LEN)\n\t{\n\t\tgefvCache[rep].pcache = def;\n\t\tstrcpy (gefvCache[rep].field, field);\n\t\trep ^= 1;\n\t}\n\nDone:\n\tif (!def)\n\t\treturn NULL;\n\n\treturn (eval_t *)((char *)&ed->v + def->ofs*4);\n}\n\n\n/*\n============\nPR_ValueString\n\nReturns a string describing *data in a type specific manner\n=============\n*/\nchar *PR_ValueString (etype_t type, eval_t *val)\n{\n\tstatic char\tline[256];\n\tddef_t\t\t*def;\n\tdfunction_t\t*f;\n\t\n\ttype &= ~DEF_SAVEGLOBAL;\n\n\tswitch (type)\n\t{\n\tcase ev_string:\n\t\tsprintf (line, \"%s\", pr_strings + val->string);\n\t\tbreak;\n\tcase ev_entity:\t\n\t\tsprintf (line, \"entity %i\", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)) );\n\t\tbreak;\n\tcase ev_function:\n\t\tf = pr_functions + val->function;\n\t\tsprintf (line, \"%s()\", pr_strings + f->s_name);\n\t\tbreak;\n\tcase ev_field:\n\t\tdef = ED_FieldAtOfs ( val->_int );\n\t\tsprintf (line, \".%s\", pr_strings + def->s_name);\n\t\tbreak;\n\tcase ev_void:\n\t\tsprintf (line, \"void\");\n\t\tbreak;\n\tcase ev_float:\n\t\tsprintf (line, \"%5.1f\", val->_float);\n\t\tbreak;\n\tcase ev_vector:\n\t\tsprintf (line, \"'%5.1f %5.1f %5.1f'\", val->vector[0], val->vector[1], val->vector[2]);\n\t\tbreak;\n\tcase ev_pointer:\n\t\tsprintf (line, \"pointer\");\n\t\tbreak;\n\tdefault:\n\t\tsprintf (line, \"bad type %i\", type);\n\t\tbreak;\n\t}\n\t\n\treturn line;\n}\n\n/*\n============\nPR_UglyValueString\n\nReturns a string describing *data in a type specific manner\nEasier to parse than PR_ValueString\n=============\n*/\nchar *PR_UglyValueString (etype_t type, eval_t *val)\n{\n\tstatic char\tline[256];\n\tddef_t\t\t*def;\n\tdfunction_t\t*f;\n\t\n\ttype &= ~DEF_SAVEGLOBAL;\n\n\tswitch (type)\n\t{\n\tcase ev_string:\n\t\tsprintf (line, \"%s\", pr_strings + val->string);\n\t\tbreak;\n\tcase ev_entity:\t\n\t\tsprintf (line, \"%i\", NUM_FOR_EDICT(PROG_TO_EDICT(val->edict)));\n\t\tbreak;\n\tcase ev_function:\n\t\tf = pr_functions + val->function;\n\t\tsprintf (line, \"%s\", pr_strings + f->s_name);\n\t\tbreak;\n\tcase ev_field:\n\t\tdef = ED_FieldAtOfs ( val->_int );\n\t\tsprintf (line, \"%s\", pr_strings + def->s_name);\n\t\tbreak;\n\tcase ev_void:\n\t\tsprintf (line, \"void\");\n\t\tbreak;\n\tcase ev_float:\n\t\tsprintf (line, \"%f\", val->_float);\n\t\tbreak;\n\tcase ev_vector:\n\t\tsprintf (line, \"%f %f %f\", val->vector[0], val->vector[1], val->vector[2]);\n\t\tbreak;\n\tdefault:\n\t\tsprintf (line, \"bad type %i\", type);\n\t\tbreak;\n\t}\n\t\n\treturn line;\n}\n\n/*\n============\nPR_GlobalString\n\nReturns a string with a description and the contents of a global,\npadded to 20 field width\n============\n*/\nchar *PR_GlobalString (int ofs)\n{\n\tchar\t*s;\n\tint\t\ti;\n\tddef_t\t*def;\n\tvoid\t*val;\n\tstatic char\tline[128];\n\t\n\tval = (void *)&pr_globals[ofs];\n\tdef = ED_GlobalAtOfs(ofs);\n\tif (!def)\n\t\tsprintf (line,\"%i(?)\", ofs);\n\telse\n\t{\n\t\ts = PR_ValueString (def->type, val);\n\t\tsprintf (line,\"%i(%s)%s\", ofs, pr_strings + def->s_name, s);\n\t}\n\t\n\ti = strlen(line);\n\tfor ( ; i<20 ; i++)\n\t\tstrcat (line,\" \");\n\tstrcat (line,\" \");\n\t\t\n\treturn line;\n}\n\nchar *PR_GlobalStringNoContents (int ofs)\n{\n\tint\t\ti;\n\tddef_t\t*def;\n\tstatic char\tline[128];\n\t\n\tdef = ED_GlobalAtOfs(ofs);\n\tif (!def)\n\t\tsprintf (line,\"%i(?)\", ofs);\n\telse\n\t\tsprintf (line,\"%i(%s)\", ofs, pr_strings + def->s_name);\n\t\n\ti = strlen(line);\n\tfor ( ; i<20 ; i++)\n\t\tstrcat (line,\" \");\n\tstrcat (line,\" \");\n\t\t\n\treturn line;\n}\n\n\n/*\n=============\nED_Print\n\nFor debugging\n=============\n*/\nvoid ED_Print (edict_t *ed)\n{\n\tint\t\tl;\n\tddef_t\t*d;\n\tint\t\t*v;\n\tint\t\ti, j;\n\tchar\t*name;\n\tint\t\ttype;\n\n\tif (ed->free)\n\t{\n\t\tCon_Printf (\"FREE\\n\");\n\t\treturn;\n\t}\n\n\tCon_Printf(\"\\nEDICT %i:\\n\", NUM_FOR_EDICT(ed));\n\tfor (i=1 ; i<progs->numfielddefs ; i++)\n\t{\n\t\td = &pr_fielddefs[i];\n\t\tname = pr_strings + d->s_name;\n\t\tif (name[strlen(name)-2] == '_')\n\t\t\tcontinue;\t// skip _x, _y, _z vars\n\t\t\t\n\t\tv = (int *)((char *)&ed->v + d->ofs*4);\n\n\t// if the value is still all 0, skip the field\n\t\ttype = d->type & ~DEF_SAVEGLOBAL;\n\t\t\n\t\tfor (j=0 ; j<type_size[type] ; j++)\n\t\t\tif (v[j])\n\t\t\t\tbreak;\n\t\tif (j == type_size[type])\n\t\t\tcontinue;\n\t\n\t\tCon_Printf (\"%s\",name);\n\t\tl = strlen (name);\n\t\twhile (l++ < 15)\n\t\t\tCon_Printf (\" \");\n\n\t\tCon_Printf (\"%s\\n\", PR_ValueString(d->type, (eval_t *)v));\t\t\n\t}\n}\n\n/*\n=============\nED_Write\n\nFor savegames\n=============\n*/\nvoid ED_Write (FILE *f, edict_t *ed)\n{\n\tddef_t\t*d;\n\tint\t\t*v;\n\tint\t\ti, j;\n\tchar\t*name;\n\tint\t\ttype;\n\n\tfprintf (f, \"{\\n\");\n\n\tif (ed->free)\n\t{\n\t\tfprintf (f, \"}\\n\");\n\t\treturn;\n\t}\n\t\n\tfor (i=1 ; i<progs->numfielddefs ; i++)\n\t{\n\t\td = &pr_fielddefs[i];\n\t\tname = pr_strings + d->s_name;\n\t\tif (name[strlen(name)-2] == '_')\n\t\t\tcontinue;\t// skip _x, _y, _z vars\n\t\t\t\n\t\tv = (int *)((char *)&ed->v + d->ofs*4);\n\n\t// if the value is still all 0, skip the field\n\t\ttype = d->type & ~DEF_SAVEGLOBAL;\n\t\tfor (j=0 ; j<type_size[type] ; j++)\n\t\t\tif (v[j])\n\t\t\t\tbreak;\n\t\tif (j == type_size[type])\n\t\t\tcontinue;\n\t\n\t\tfprintf (f,\"\\\"%s\\\" \",name);\n\t\tfprintf (f,\"\\\"%s\\\"\\n\", PR_UglyValueString(d->type, (eval_t *)v));\t\t\n\t}\n\n\tfprintf (f, \"}\\n\");\n}\n\nvoid ED_PrintNum (int ent)\n{\n\tED_Print (EDICT_NUM(ent));\n}\n\n/*\n=============\nED_PrintEdicts\n\nFor debugging, prints all the entities in the current server\n=============\n*/\nvoid ED_PrintEdicts (void)\n{\n\tint\t\ti;\n\t\n\tCon_Printf (\"%i entities\\n\", sv.num_edicts);\n\tfor (i=0 ; i<sv.num_edicts ; i++)\n\t\tED_PrintNum (i);\n}\n\n/*\n=============\nED_PrintEdict_f\n\nFor debugging, prints a single edicy\n=============\n*/\nvoid ED_PrintEdict_f (void)\n{\n\tint\t\ti;\n\t\n\ti = atoi (Cmd_Argv(1));\n\tif (i >= sv.num_edicts)\n\t{\n\t\tCon_Printf(\"Bad edict number\\n\");\n\t\treturn;\n\t}\n\tED_PrintNum (i);\n}\n\n/*\n=============\nED_Count\n\nFor debugging\n=============\n*/\nvoid ED_Count (void)\n{\n\tint\t\ti;\n\tedict_t\t*ent;\n\tint\t\tactive, models, solid, step;\n\n\tactive = models = solid = step = 0;\n\tfor (i=0 ; i<sv.num_edicts ; i++)\n\t{\n\t\tent = EDICT_NUM(i);\n\t\tif (ent->free)\n\t\t\tcontinue;\n\t\tactive++;\n\t\tif (ent->v.solid)\n\t\t\tsolid++;\n\t\tif (ent->v.model)\n\t\t\tmodels++;\n\t\tif (ent->v.movetype == MOVETYPE_STEP)\n\t\t\tstep++;\n\t}\n\n\tCon_Printf (\"num_edicts:%3i\\n\", sv.num_edicts);\n\tCon_Printf (\"active    :%3i\\n\", active);\n\tCon_Printf (\"view      :%3i\\n\", models);\n\tCon_Printf (\"touch     :%3i\\n\", solid);\n\tCon_Printf (\"step      :%3i\\n\", step);\n\n}\n\n/*\n==============================================================================\n\n\t\t\t\t\tARCHIVING GLOBALS\n\nFIXME: need to tag constants, doesn't really work\n==============================================================================\n*/\n\n/*\n=============\nED_WriteGlobals\n=============\n*/\nvoid ED_WriteGlobals (FILE *f)\n{\n\tddef_t\t\t*def;\n\tint\t\t\ti;\n\tchar\t\t*name;\n\tint\t\t\ttype;\n\n\tfprintf (f,\"{\\n\");\n\tfor (i=0 ; i<progs->numglobaldefs ; i++)\n\t{\n\t\tdef = &pr_globaldefs[i];\n\t\ttype = def->type;\n\t\tif ( !(def->type & DEF_SAVEGLOBAL) )\n\t\t\tcontinue;\n\t\ttype &= ~DEF_SAVEGLOBAL;\n\n\t\tif (type != ev_string\n\t\t&& type != ev_float\n\t\t&& type != ev_entity)\n\t\t\tcontinue;\n\n\t\tname = pr_strings + def->s_name;\t\t\n\t\tfprintf (f,\"\\\"%s\\\" \", name);\n\t\tfprintf (f,\"\\\"%s\\\"\\n\", PR_UglyValueString(type, (eval_t *)&pr_globals[def->ofs]));\t\t\n\t}\n\tfprintf (f,\"}\\n\");\n}\n\n/*\n=============\nED_ParseGlobals\n=============\n*/\nvoid ED_ParseGlobals (char *data)\n{\n\tchar\tkeyname[64];\n\tddef_t\t*key;\n\n\twhile (1)\n\t{\t\n\t// parse key\n\t\tdata = COM_Parse (data);\n\t\tif (com_token[0] == '}')\n\t\t\tbreak;\n\t\tif (!data)\n\t\t\tSys_Error (\"ED_ParseEntity: EOF without closing brace\");\n\n\t\tstrcpy (keyname, com_token);\n\n\t// parse value\t\n\t\tdata = COM_Parse (data);\n\t\tif (!data)\n\t\t\tSys_Error (\"ED_ParseEntity: EOF without closing brace\");\n\n\t\tif (com_token[0] == '}')\n\t\t\tSys_Error (\"ED_ParseEntity: closing brace without data\");\n\n\t\tkey = ED_FindGlobal (keyname);\n\t\tif (!key)\n\t\t{\n\t\t\tCon_Printf (\"'%s' is not a global\\n\", keyname);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!ED_ParseEpair ((void *)pr_globals, key, com_token))\n\t\t\tHost_Error (\"ED_ParseGlobals: parse error\");\n\t}\n}\n\n//============================================================================\n\n\n/*\n=============\nED_NewString\n=============\n*/\nchar *ED_NewString (char *string)\n{\n\tchar\t*new, *new_p;\n\tint\t\ti,l;\n\t\n\tl = strlen(string) + 1;\n\tnew = Hunk_Alloc (l);\n\tnew_p = new;\n\n\tfor (i=0 ; i< l ; i++)\n\t{\n\t\tif (string[i] == '\\\\' && i < l-1)\n\t\t{\n\t\t\ti++;\n\t\t\tif (string[i] == 'n')\n\t\t\t\t*new_p++ = '\\n';\n\t\t\telse\n\t\t\t\t*new_p++ = '\\\\';\n\t\t}\n\t\telse\n\t\t\t*new_p++ = string[i];\n\t}\n\t\n\treturn new;\n}\n\n\n/*\n=============\nED_ParseEval\n\nCan parse either fields or globals\nreturns false if error\n=============\n*/\nbool\tED_ParseEpair (void *base, ddef_t *key, char *s)\n{\n\tint\t\ti;\n\tchar\tstring[128];\n\tddef_t\t*def;\n\tchar\t*v, *w;\n\tvoid\t*d;\n\tdfunction_t\t*func;\n\t\n\td = (void *)((int *)base + key->ofs);\n\t\n\tswitch (key->type & ~DEF_SAVEGLOBAL)\n\t{\n\tcase ev_string:\n\t\t*(string_t *)d = ED_NewString (s) - pr_strings;\n\t\tbreak;\n\t\t\n\tcase ev_float:\n\t\t*(float *)d = atof (s);\n\t\tbreak;\n\t\t\n\tcase ev_vector:\n\t\tstrcpy (string, s);\n\t\tv = string;\n\t\tw = string;\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\twhile (*v && *v != ' ')\n\t\t\t\tv++;\n\t\t\t*v = 0;\n\t\t\t((float *)d)[i] = atof (w);\n\t\t\tw = v = v+1;\n\t\t}\n\t\tbreak;\n\t\t\n\tcase ev_entity:\n\t\t*(int *)d = EDICT_TO_PROG(EDICT_NUM(atoi (s)));\n\t\tbreak;\n\t\t\n\tcase ev_field:\n\t\tdef = ED_FindField (s);\n\t\tif (!def)\n\t\t{\n\t\t\tCon_Printf (\"Can't find field %s\\n\", s);\n\t\t\treturn false;\n\t\t}\n\t\t*(int *)d = G_INT(def->ofs);\n\t\tbreak;\n\t\n\tcase ev_function:\n\t\tfunc = ED_FindFunction (s);\n\t\tif (!func)\n\t\t{\n\t\t\tCon_Printf (\"Can't find function %s\\n\", s);\n\t\t\treturn false;\n\t\t}\n\t\t*(func_t *)d = func - pr_functions;\n\t\tbreak;\n\t\t\n\tdefault:\n\t\tbreak;\n\t}\n\treturn true;\n}\n\n/*\n====================\nED_ParseEdict\n\nParses an edict out of the given string, returning the new position\ned should be a properly initialized empty edict.\nUsed for initial level load and for savegames.\n====================\n*/\nchar *ED_ParseEdict (char *data, edict_t *ent)\n{\n\tddef_t\t\t*key;\n\tbool\tanglehack;\n\tbool\tinit;\n\tchar\t\tkeyname[256];\n\tint\t\t\tn;\n\n\tinit = false;\n\n\t// clear it\n\tif (ent != sv.edicts)\t// hack\n\t\tmemset (&ent->v, 0, progs->entityfields * 4);\n\n\t// go through all the dictionary pairs\n\twhile (1)\n\t{\t\n\t\t// parse key\n\t\tdata = COM_Parse (data);\n\t\tif (com_token[0] == '}')\n\t\t\tbreak;\n\t\tif (!data)\n\t\t\tSys_Error (\"ED_ParseEntity: EOF without closing brace\");\n\t\t\n\t\t// anglehack is to allow QuakeEd to write single scalar angles\n\t\t// and allow them to be turned into vectors. (FIXME...)\n\t\tif (!strcmp(com_token, \"angle\"))\n\t\t{\n\t\t\tstrcpy (com_token, \"angles\");\n\t\t\tanglehack = true;\n\t\t}\n\t\telse\n\t\t\tanglehack = false;\n\n\t\t// FIXME: change light to _light to get rid of this hack\n\t\tif (!strcmp(com_token, \"light\"))\n\t\t\tstrcpy (com_token, \"light_lev\");\t// hack for single light def\n\n\t\tstrcpy (keyname, com_token);\n\n\t\t// another hack to fix heynames with trailing spaces\n\t\tn = strlen(keyname);\n\t\twhile (n && keyname[n-1] == ' ')\n\t\t{\n\t\t\tkeyname[n-1] = 0;\n\t\t\tn--;\n\t\t}\n\n\t\t// parse value\t\n\t\tdata = COM_Parse (data);\n\t\tif (!data)\n\t\t\tSys_Error (\"ED_ParseEntity: EOF without closing brace\");\n\n\t\tif (com_token[0] == '}')\n\t\t\tSys_Error (\"ED_ParseEntity: closing brace without data\");\n\n\t\tinit = true;\t\n\n\t\t// keynames with a leading underscore are used for utility comments,\n\t\t// and are immediately discarded by quake\n\t\tif (keyname[0] == '_')\n\t\t\tcontinue;\n\t\t\n\t\tif (!(key = ED_FindField(keyname))) {\n\t\t\tif (strcmp(keyname, \"sky\") && strcmp(keyname, \"fog\")) // Now supported in worldspawn\n\t\t\t\tCon_SafePrintf(\"'%s' is not a field\\n\", keyname);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (anglehack)\n\t\t{\n\t\t\tchar\ttemp[32];\n\t\t\tstrcpy (temp, com_token);\n\t\t\tsprintf (com_token, \"0 %s 0\", temp);\n\t\t}\n\n\t\tif (!ED_ParseEpair ((void *)&ent->v, key, com_token))\n\t\t\tHost_Error (\"ED_ParseEdict: parse error\");\n\t}\n\n\tif (!init)\n\t\tent->free = true;\n\n\treturn data;\n}\n\n\n/*\n================\nED_LoadFromFile\n\nThe entities are directly placed in the array, rather than allocated with\nED_Alloc, because otherwise an error loading the map would have entity\nnumber references out of order.\n\nCreates a server's entity / program execution context by\nparsing textual entity definitions out of an ent file.\n\nUsed for both fresh maps and savegame loads.  A fresh map would also need\nto call ED_CallSpawnFunctions () to let the objects initialize themselves.\n================\n*/\nvoid ED_LoadFromFile (char *data)\n{\t\n\tedict_t\t\t*ent;\n\tint\t\t\tinhibit;\n\tdfunction_t\t*func;\n\t\n\tent = NULL;\n\tinhibit = 0;\n\tpr_global_struct->time = sv.time;\n\t\n// parse ents\n\twhile (1)\n\t{\n// parse the opening brace\t\n\t\tdata = COM_Parse (data);\n\t\tif (!data)\n\t\t\tbreak;\n\t\tif (com_token[0] != '{')\n\t\t\tSys_Error (\"ED_LoadFromFile: found %s when expecting {\",com_token);\n\n\t\tif (!ent)\n\t\t\tent = EDICT_NUM(0);\n\t\telse\n\t\t\tent = ED_Alloc ();\n\t\tdata = ED_ParseEdict (data, ent);\n\n// remove things from different skill levels or deathmatch\n\t\tif (deathmatch.value)\n\t\t{\n\t\t\tif (((int)ent->v.spawnflags & SPAWNFLAG_NOT_DEATHMATCH))\n\t\t\t{\n\t\t\t\tED_Free (ent);\t\n\t\t\t\tinhibit++;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\telse if ((current_skill == 0 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_EASY))\n\t\t\t\t|| (current_skill == 1 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_MEDIUM))\n\t\t\t\t|| (current_skill >= 2 && ((int)ent->v.spawnflags & SPAWNFLAG_NOT_HARD)) )\n\t\t{\n\t\t\tED_Free (ent);\t\n\t\t\tinhibit++;\n\t\t\tcontinue;\n\t\t}\n\n//\n// immediately call spawn function\n//\n\t\tif (!ent->v.classname)\n\t\t{\n\t\t\tCon_Printf (\"No classname for:\\n\");\n\t\t\tED_Print (ent);\n\t\t\tED_Free (ent);\n\t\t\tcontinue;\n\t\t}\n\n\t// look for the spawn function\n\t\tfunc = ED_FindFunction ( pr_strings + ent->v.classname );\n\n\t\tif (!func)\n\t\t{\n\t\t\tCon_Printf (\"No spawn function for:\\n\");\n\t\t\tED_Print (ent);\n\t\t\tED_Free (ent);\n\t\t\tcontinue;\n\t\t}\n\n\t\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\t\tPR_ExecuteProgram (func - pr_functions);\n\t}\t\n\n\tCon_DPrintf (\"%i entities inhibited\\n\", inhibit);\n}\n\n\n/*\n===============\nPR_LoadProgs\n===============\n*/\nvoid PR_LoadProgs (const char *progsname)\n{\n\tint\t\ti;\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  start\n\tint \tj;\n\tint\t\tfuncno;\n\tchar\t*funcname;\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  end\n\n// flush the non-C variable lookup cache\n\tfor (i=0 ; i<GEFV_CACHESIZE ; i++)\n\t\tgefvCache[i].field[0] = 0;\n\t\n\tif (!progsname || !*progsname)\n\t\tHost_Error(\"PR_LoadProgs: passed empty progsname\");\n\n\tCRC_Init (&pr_crc);\n\n\tprogs = (dprograms_t *)COM_LoadHunkFile (progsname, NULL);\n\tif (!progs)\n\t\tSys_Error (\"PR_LoadProgs: couldn't load %s\", progsname);\n\tCon_DPrintf (\"Programs occupy %iK.\\n\", com_filesize/1024);\n\n\tfor (i=0 ; i<com_filesize ; i++)\n\t\tCRC_ProcessByte (&pr_crc, ((byte *)progs)[i]);\n\n// byte swap the header\n\tfor (i=0 ; i<sizeof(*progs)/4 ; i++)\n\t\t((int *)progs)[i] = LittleLong ( ((int *)progs)[i] );\t\t\n\n\tif (progs->version != PROG_VERSION)\n\t\tSys_Error (\"%s has wrong version number (%i should be %i)\", progsname, progs->version, PROG_VERSION);\n\tif (progs->crc != PROGHEADER_CRC)\n\t\tSys_Error (\"%s has wrong CRC number (%i should be %i)\", progsname, progs->crc, PROGHEADER_CRC);\n\n\tpr_functions = (dfunction_t *)((byte *)progs + progs->ofs_functions);\n\tpr_strings = (char *)progs + progs->ofs_strings;\n\tpr_globaldefs = (ddef_t *)((byte *)progs + progs->ofs_globaldefs);\n\tpr_fielddefs = (ddef_t *)((byte *)progs + progs->ofs_fielddefs);\n\tpr_statements = (dstatement_t *)((byte *)progs + progs->ofs_statements);\n\n\tpr_global_struct = (globalvars_t *)((byte *)progs + progs->ofs_globals);\n\tpr_globals = (float *)pr_global_struct;\n\t\n\tpr_edict_size = progs->entityfields * 4 + sizeof (edict_t) - sizeof(entvars_t);\n\t\n// byte swap the lumps\n\tfor (i=0 ; i<progs->numstatements ; i++)\n\t{\n\t\tpr_statements[i].op = LittleShort(pr_statements[i].op);\n\t\tpr_statements[i].a = LittleShort(pr_statements[i].a);\n\t\tpr_statements[i].b = LittleShort(pr_statements[i].b);\n\t\tpr_statements[i].c = LittleShort(pr_statements[i].c);\n\t}\n\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  start\n\t// initialize function numbers for PROGS.DAT\n\tpr_numbuiltins = 0;\n\tpr_builtins = NULL;\n\tif (pr_builtin_remap.value)\n\t{\n\t\t// remove all previous assigned function numbers\n\t\tfor ( j=1 ; j < pr_ebfs_numbuiltins; j++)\n\t\t{\n\t\t\tpr_ebfs_builtins[j].funcno = 0;\n\t\t}\n\t}\n\telse\n\t{\n\t\t// use default function numbers\n\t\tfor ( j=1 ; j < pr_ebfs_numbuiltins; j++)\n\t\t{\n\t\t\tpr_ebfs_builtins[j].funcno = pr_ebfs_builtins[j].default_funcno;\n\t\t\t// determine highest builtin number (when NOT remapped)\n\t\t\tif (pr_ebfs_builtins[j].funcno > pr_numbuiltins)\n\t\t\t{\n\t\t\t\tpr_numbuiltins = pr_ebfs_builtins[j].funcno;\n\t\t\t}\n\t\t}\n\t}\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  end\n\n\tfor (i=0 ; i<progs->numfunctions; i++)\n\t{\n\t\tpr_functions[i].first_statement = LittleLong (pr_functions[i].first_statement);\n\t\tpr_functions[i].parm_start = LittleLong (pr_functions[i].parm_start);\n\t\tpr_functions[i].s_name = LittleLong (pr_functions[i].s_name);\n\t\tpr_functions[i].s_file = LittleLong (pr_functions[i].s_file);\n\t\tpr_functions[i].numparms = LittleLong (pr_functions[i].numparms);\n\t\tpr_functions[i].locals = LittleLong (pr_functions[i].locals);\n\n\t\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  start\n\t\tif (pr_builtin_remap.value)\n\t\t{\n\t\t\tif (pr_functions[i].first_statement < 0)\t// builtin function\n\t\t\t{\n\t\t\t\tfuncno = -pr_functions[i].first_statement;\n\t\t\t\tfuncname = pr_strings + pr_functions[i].s_name;\n\n\t\t\t\t// search function name\n\t\t\t\tfor ( j=1 ; j < pr_ebfs_numbuiltins ; j++)\n\t\t\t\t{\n\t\t\t\t\tif (!(strcasecmp(funcname, pr_ebfs_builtins[j].funcname)))\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\t// found\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (j < pr_ebfs_numbuiltins)\t// found\n\t\t\t\t{\n\t\t\t\t\tpr_ebfs_builtins[j].funcno = funcno;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tCon_DPrintf(\"Can not assign builtin number #%i to %s - function unknown\\n\", funcno, funcname);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  end\n\t}\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  start\n\tif (pr_builtin_remap.value)\n\t{\n\t\t// check for unassigned functions and try to assign their default function number\n\t\tfor ( i=1 ; i < pr_ebfs_numbuiltins; i++)\n\t\t{\n\t\t\tif ((!pr_ebfs_builtins[i].funcno) && (pr_ebfs_builtins[i].default_funcno))\t// unassigned and has a default number\n\t\t\t{\n\t\t\t\t// check if default number is already assigned to another function\n\t\t\t\tfor ( j=1 ; j < pr_ebfs_numbuiltins; j++)\n\t\t\t\t{\n\t\t\t\t\tif (pr_ebfs_builtins[j].funcno == pr_ebfs_builtins[i].default_funcno)\n\t\t\t\t\t{\n\t\t\t\t\t\tbreak;\t// number already assigned to another builtin function\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (j < pr_ebfs_numbuiltins)\t// already assigned\n\t\t\t\t{\n\t\t\t\t\tCon_DPrintf(\"Can not assign default builtin number #%i to %s - number is already assigned to %s\\n\",\n\t\t\t\t\tpr_ebfs_builtins[i].default_funcno, pr_ebfs_builtins[i].funcname, pr_ebfs_builtins[j].funcname);\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tpr_ebfs_builtins[i].funcno = pr_ebfs_builtins[i].default_funcno;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// determine highest builtin number (when remapped)\n\t\t\tif (pr_ebfs_builtins[i].funcno > pr_numbuiltins)\n\t\t\t{\n\t\t\t\tpr_numbuiltins = pr_ebfs_builtins[i].funcno;\n\t\t\t}\n\t\t}\n\t}\n\tpr_numbuiltins++;\n\n\t// allocate and initialize builtin list for execution time\n\tpr_builtins = Hunk_AllocName (pr_numbuiltins*sizeof(builtin_t), \"builtins\");\n\tfor ( i=0 ; i < pr_numbuiltins ; i++)\n\t{\n\t\tpr_builtins[i] = pr_ebfs_builtins[0].function;\n\t}\n\n\t// create builtin list for execution time and set cvars accordingly\n\tCvar_Set(\"pr_builtin_find\", \"0\");\n\tCvar_Set(\"pr_checkextension\", \"0\");\t// 2001-10-20 Extension System by Lord Havoc/Maddes (DP compatibility)\n\n\tfor ( j=1 ; j < pr_ebfs_numbuiltins ; j++)\n\t{\n\t\tif (pr_ebfs_builtins[j].funcno)\t// only put assigned functions into builtin list\n\t\t{\n\t\t\tpr_builtins[pr_ebfs_builtins[j].funcno] = pr_ebfs_builtins[j].function;\n\t\t}\n\n\t\tif (pr_ebfs_builtins[j].default_funcno == PR_DEFAULT_FUNCNO_BUILTIN_FIND)\n\t\t{\n\t\t\tCvar_SetValue(\"pr_builtin_find\", pr_ebfs_builtins[j].funcno);\n\t\t}\n\n// 2001-10-20 Extension System by Lord Havoc/Maddes (DP compatibility)  start\n\t\tif (pr_ebfs_builtins[j].default_funcno == PR_DEFAULT_FUNCNO_EXTENSION_FIND)\n\t\t{\n\t\t\tCvar_SetValue(\"pr_checkextension\", pr_ebfs_builtins[j].funcno);\n\t\t}\n// 2001-10-20 Extension System by Lord Havoc/Maddes (DP compatibility)  end\n\t}\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes/Firestorm  end\n\n\tfor (i=0 ; i<progs->numglobaldefs ; i++)\n\t{\n\t\tpr_globaldefs[i].type = LittleShort (pr_globaldefs[i].type);\n\t\tpr_globaldefs[i].ofs = LittleShort (pr_globaldefs[i].ofs);\n\t\tpr_globaldefs[i].s_name = LittleLong (pr_globaldefs[i].s_name);\n\t}\n\n\tfor (i=0 ; i<progs->numfielddefs ; i++)\n\t{\n\t\tpr_fielddefs[i].type = LittleShort (pr_fielddefs[i].type);\n\t\tif (pr_fielddefs[i].type & DEF_SAVEGLOBAL)\n\t\t\tSys_Error (\"PR_LoadProgs: pr_fielddefs[i].type & DEF_SAVEGLOBAL\");\n\t\tpr_fielddefs[i].ofs = LittleShort (pr_fielddefs[i].ofs);\n\t\tpr_fielddefs[i].s_name = LittleLong (pr_fielddefs[i].s_name);\n\t}\n\n\tfor (i=0 ; i<progs->numglobals ; i++)\n\t\t((int *)pr_globals)[i] = LittleLong (((int *)pr_globals)[i]);\n\t\n\tFindEdictFieldOffsets ();\n}\n\n// 2001-10-20 Extension System by LordHavoc  start\nvoid PR_Extension_List_f (void)\n{\n\tint\t\ti;\n\tchar\t*partial;\n\tint\t\tlen;\n\tint\t\tcount;\n\t\n\tif (Cmd_Argc() > 1)\n\t{\n\t\tpartial = Cmd_Argv (1);\n\t\tlen = strlen(partial);\n\t}\n\telse\n\t{\n\t\tpartial = NULL;\n\t\tlen = 0;\n\t}\n\tcount=0;\n\tfor (i=0; i < pr_numextensions; i++)\n\t{\n\t\tif (partial && strncasecmp (partial, pr_extensions[i], len))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tCon_Printf (\"%s\\n\", pr_extensions[i]);\n\t}\n\tCon_Printf (\"------------\\n\");\n\tif (partial)\n\t{\n\t\tCon_Printf (\"%i beginning with \\\"%s\\\" out of \", count, partial);\n\t}\n\tCon_Printf (\"%i extensions\\n\", i);\n}\n// 2001-10-20 Extension System by LordHavoc  end\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\n/*\n=============\nPR_BuiltInList_f\nFor debugging, prints all builtin functions with assigned and default number\n=============\n*/\n\nvoid PR_BuiltInList_f (void)\n{\n\tint\t\ti;\n\tchar\t*partial;\n\tint\t\tlen;\n\tint\t\tcount;\n\n\tif (Cmd_Argc() > 1)\n\t{\n\t\tpartial = Cmd_Argv (1);\n\t\tlen = strlen(partial);\n\t}\n\telse\n\t{\n\t\tpartial = NULL;\n\t\tlen = 0;\n\t}\n\n\tcount=0;\n\tfor (i=1; i < pr_ebfs_numbuiltins; i++)\n\t{\n\t\tif (partial && strncasecmp (partial, pr_ebfs_builtins[i].funcname, len))\n\t\t{\n\t\t\tcontinue;\n\t\t}\n\t\tcount++;\n\t\tCon_Printf (\"%i(%i): %s\\n\", pr_ebfs_builtins[i].funcno, pr_ebfs_builtins[i].default_funcno, pr_ebfs_builtins[i].funcname);\n\t}\n\n\tCon_Printf (\"------------\\n\");\n\tif (partial)\n\t{\n\t\tCon_Printf (\"%i beginning with \\\"%s\\\" out of \", count, partial);\n\t}\n\tCon_Printf (\"%i builtin functions\\n\", i);\n}\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\n/*\n===============\nPR_Init\n===============\n*/\nvoid PR_Init (void)\n{\n\tCmd_AddCommand (\"edict\", ED_PrintEdict_f);\n\tCmd_AddCommand (\"edicts\", ED_PrintEdicts);\n\tCmd_AddCommand (\"edictcount\", ED_Count);\n\tCmd_AddCommand (\"profile\", PR_Profile_f);\n\tCmd_AddCommand (\"builtinlist\", PR_BuiltInList_f);\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes\n\tCmd_AddCommand (\"extensionlist\", PR_Extension_List_f);\t// 2001-10-20 Extension System by LordHavoc\n\tCvar_RegisterVariable (&nomonsters);\n\tCvar_RegisterVariable (&gamecfg);\n\tCvar_RegisterVariable (&scratch1);\n\tCvar_RegisterVariable (&scratch2);\n\tCvar_RegisterVariable (&scratch3);\n\tCvar_RegisterVariable (&scratch4);\n\tCvar_RegisterVariable (&savedgamecfg);\n\tCvar_RegisterVariable (&saved1);\n\tCvar_RegisterVariable (&saved2);\n\tCvar_RegisterVariable (&saved3);\n\tCvar_RegisterVariable (&saved4);\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\n\tCvar_RegisterVariable (&pr_builtin_find);\n\tCvar_RegisterVariable (&pr_builtin_remap);\n\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\tCvar_RegisterVariable (&pr_checkextension);\t// 2001-10-20 Extension System by LordHavoc (DP compatibility)\n}\n\n\n\nedict_t *EDICT_NUM(int n)\n{\n\tif (n < 0 || n >= sv.max_edicts)\n\t\tSys_Error (\"EDICT_NUM: bad number %i\", n);\n\treturn (edict_t *)((byte *)sv.edicts+ (n)*pr_edict_size);\n}\n\nint NUM_FOR_EDICT(edict_t *e)\n{\n\tint\t\tb;\n\t\n\tb = (byte *)e - (byte *)sv.edicts;\n\tb = b / pr_edict_size;\n\t\n\tif (b < 0 || b >= sv.num_edicts)\n\t\tSys_Error (\"NUM_FOR_EDICT: bad pointer\");\n\treturn b;\n}\n"
  },
  {
    "path": "source/pr_exec.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n\n\n/*\n\n*/\n\ntypedef struct\n{\n\tint\t\t\t\ts;\n\tdfunction_t\t\t*f;\n} prstack_t;\n\n#define\tMAX_STACK_DEPTH\t\t32\nprstack_t\tpr_stack[MAX_STACK_DEPTH];\nint\t\t\tpr_depth;\n\n#define\tLOCALSTACK_SIZE\t\t2048\nint\t\t\tlocalstack[LOCALSTACK_SIZE];\nint\t\t\tlocalstack_used;\n\n\nbool\tpr_trace;\ndfunction_t\t*pr_xfunction;\nint\t\t\tpr_xstatement;\n\n\nint\t\tpr_argc;\n\nconst char *pr_opnames[] =\n{\n\"DONE\",\n\n\"MUL_F\",\n\"MUL_V\", \n\"MUL_FV\",\n\"MUL_VF\",\n \n\"DIV\",\n\n\"ADD_F\",\n\"ADD_V\", \n  \n\"SUB_F\",\n\"SUB_V\",\n\n\"EQ_F\",\n\"EQ_V\",\n\"EQ_S\", \n\"EQ_E\",\n\"EQ_FNC\",\n \n\"NE_F\",\n\"NE_V\", \n\"NE_S\",\n\"NE_E\", \n\"NE_FNC\",\n \n\"LE\",\n\"GE\",\n\"LT\",\n\"GT\", \n\n\"INDIRECT\",\n\"INDIRECT\",\n\"INDIRECT\", \n\"INDIRECT\", \n\"INDIRECT\",\n\"INDIRECT\", \n\n\"ADDRESS\", \n\n\"STORE_F\",\n\"STORE_V\",\n\"STORE_S\",\n\"STORE_ENT\",\n\"STORE_FLD\",\n\"STORE_FNC\",\n\n\"STOREP_F\",\n\"STOREP_V\",\n\"STOREP_S\",\n\"STOREP_ENT\",\n\"STOREP_FLD\",\n\"STOREP_FNC\",\n\n\"RETURN\",\n  \n\"NOT_F\",\n\"NOT_V\",\n\"NOT_S\", \n\"NOT_ENT\", \n\"NOT_FNC\", \n  \n\"IF\",\n\"IFNOT\",\n  \n\"CALL0\",\n\"CALL1\",\n\"CALL2\",\n\"CALL3\",\n\"CALL4\",\n\"CALL5\",\n\"CALL6\",\n\"CALL7\",\n\"CALL8\",\n  \n\"STATE\",\n  \n\"GOTO\", \n  \n\"AND\",\n\"OR\", \n\n\"BITAND\",\n\"BITOR\"\n};\n\nchar *PR_GlobalString (int ofs);\nchar *PR_GlobalStringNoContents (int ofs);\n\n\n//=============================================================================\n\n/*\n=================\nPR_PrintStatement\n=================\n*/\nvoid PR_PrintStatement (dstatement_t *s)\n{\n\tint\t\ti;\n\t\n\tif ( (unsigned)s->op < sizeof(pr_opnames)/sizeof(pr_opnames[0]))\n\t{\n\t\tCon_Printf (\"%s \",  pr_opnames[s->op]);\n\t\ti = strlen(pr_opnames[s->op]);\n\t\tfor ( ; i<10 ; i++)\n\t\t\tCon_Printf (\" \");\n\t}\n\t\t\n\tif (s->op == OP_IF || s->op == OP_IFNOT)\n\t\tCon_Printf (\"%sbranch %i\",PR_GlobalString(s->a),s->b);\n\telse if (s->op == OP_GOTO)\n\t{\n\t\tCon_Printf (\"branch %i\",s->a);\n\t}\n\telse if ( (unsigned)(s->op - OP_STORE_F) < 6)\n\t{\n\t\tCon_Printf (\"%s\",PR_GlobalString(s->a));\n\t\tCon_Printf (\"%s\", PR_GlobalStringNoContents(s->b));\n\t}\n\telse\n\t{\n\t\tif (s->a)\n\t\t\tCon_Printf (\"%s\",PR_GlobalString(s->a));\n\t\tif (s->b)\n\t\t\tCon_Printf (\"%s\",PR_GlobalString(s->b));\n\t\tif (s->c)\n\t\t\tCon_Printf (\"%s\", PR_GlobalStringNoContents(s->c));\n\t}\n\tCon_Printf (\"\\n\");\n}\n\n/*\n============\nPR_StackTrace\n============\n*/\nvoid PR_StackTrace (void)\n{\n\tdfunction_t\t*f;\n\tint\t\t\ti;\n\t\n\tif (pr_depth == 0)\n\t{\n\t\tCon_Printf (\"<NO STACK>\\n\");\n\t\treturn;\n\t}\n\t\n\tpr_stack[pr_depth].f = pr_xfunction;\n\tfor (i=pr_depth ; i>=0 ; i--)\n\t{\n\t\tf = pr_stack[i].f;\n\t\t\n\t\tif (!f)\n\t\t{\n\t\t\tCon_Printf (\"<NO FUNCTION>\\n\");\n\t\t}\n\t\telse\n\t\t\tCon_Printf (\"%12s : %s\\n\", pr_strings + f->s_file, pr_strings + f->s_name);\t\t\n\t}\n}\n\n\n/*\n============\nPR_Profile_f\n\n============\n*/\nvoid PR_Profile_f (void)\n{\n\tdfunction_t\t*f, *best;\n\tint\t\t\tmax;\n\tint\t\t\tnum;\n\tint\t\t\ti;\n\t\n\tnum = 0;\t\n\tdo\n\t{\n\t\tmax = 0;\n\t\tbest = NULL;\n\t\tfor (i=0 ; i<progs->numfunctions ; i++)\n\t\t{\n\t\t\tf = &pr_functions[i];\n\t\t\tif (f->profile > max)\n\t\t\t{\n\t\t\t\tmax = f->profile;\n\t\t\t\tbest = f;\n\t\t\t}\n\t\t}\n\t\tif (best)\n\t\t{\n\t\t\tif (num < 10)\n\t\t\t\tCon_Printf (\"%7i %s\\n\", best->profile, pr_strings+best->s_name);\n\t\t\tnum++;\n\t\t\tbest->profile = 0;\n\t\t}\n\t} while (best);\n}\n\n\n/*\n============\nPR_RunError\n\nAborts the currently executing function\n============\n*/\nvoid PR_RunError (char *error, ...)\n{\n\tva_list\t\targptr;\n\tchar*\t\tstring = Sys_BigStackAlloc(1024, \"PR_RunError\");\n\n\tva_start (argptr,error);\n\tvsprintf (string,error,argptr);\n\tva_end (argptr);\n\n\tPR_PrintStatement (pr_statements + pr_xstatement);\n\tPR_StackTrace ();\n\tCon_Printf (\"%s\\n\", string);\n\t\n\tpr_depth = 0;\t\t// dump the stack so host_error can shutdown functions\n\n\tSys_BigStackFree(1024, \"PR_RunError\");\n\n\tHost_Error (\"Program error\");\n}\n\n/*\n============================================================================\nPR_ExecuteProgram\n\nThe interpretation main loop\n============================================================================\n*/\n\n/*\n====================\nPR_EnterFunction\n\nReturns the new program statement counter\n====================\n*/\nint PR_EnterFunction (dfunction_t *f)\n{\n\tint\t\ti, j, c, o;\n\n\tpr_stack[pr_depth].s = pr_xstatement;\n\tpr_stack[pr_depth].f = pr_xfunction;\t\n\tpr_depth++;\n\tif (pr_depth >= MAX_STACK_DEPTH)\n\t\tPR_RunError (\"stack overflow\");\n\n// save off any locals that the new function steps on\n\tc = f->locals;\n\tif (localstack_used + c > LOCALSTACK_SIZE)\n\t\tPR_RunError (\"PR_ExecuteProgram: locals stack overflow\\n\");\n\n\tfor (i=0 ; i < c ; i++)\n\t\tlocalstack[localstack_used+i] = ((int *)pr_globals)[f->parm_start + i];\n\tlocalstack_used += c;\n\n// copy parameters\n\to = f->parm_start;\n\tfor (i=0 ; i<f->numparms ; i++)\n\t{\n\t\tfor (j=0 ; j<f->parm_size[i] ; j++)\n\t\t{\n\t\t\t((int *)pr_globals)[o] = ((int *)pr_globals)[OFS_PARM0+i*3+j];\n\t\t\to++;\n\t\t}\n\t}\n\n\tpr_xfunction = f;\n\treturn f->first_statement - 1;\t// offset the s++\n}\n\n/*\n====================\nPR_LeaveFunction\n====================\n*/\nint PR_LeaveFunction (void)\n{\n\tint\t\ti, c;\n\n\tif (pr_depth <= 0)\n\t\tSys_Error (\"prog stack underflow\");\n\n// restore locals from the stack\n\tc = pr_xfunction->locals;\n\tlocalstack_used -= c;\n\tif (localstack_used < 0)\n\t\tPR_RunError (\"PR_ExecuteProgram: locals stack underflow\\n\");\n\n\tfor (i=0 ; i < c ; i++)\n\t\t((int *)pr_globals)[pr_xfunction->parm_start + i] = localstack[localstack_used+i];\n\n// up stack\n\tpr_depth--;\n\tpr_xfunction = pr_stack[pr_depth].f;\n\treturn pr_stack[pr_depth].s;\n}\n\n\n/*\n====================\nPR_ExecuteProgram\n====================\n*/\nvoid PR_ExecuteProgram (func_t fnum)\n{\n\teval_t\t*a, *b, *c;\n\tint\t\t\ts;\n\tdstatement_t\t*st;\n\tdfunction_t\t*f, *newf;\n\tint\t\trunaway;\n\tint\t\ti;\n\tedict_t\t*ed;\n\tint\t\texitdepth;\n\teval_t\t*ptr;\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\n\tchar\t*funcname;\n\tchar\t*remaphint;\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\n\tif (!fnum || fnum >= progs->numfunctions)\n\t{\n\t\tif (pr_global_struct->self)\n\t\t\tED_Print (PROG_TO_EDICT(pr_global_struct->self));\n\t\tHost_Error (\"PR_ExecuteProgram: NULL function\");\n\t}\n\t\n\tf = &pr_functions[fnum];\n\n\trunaway = 1000000;\n\tpr_trace = false;\n\n// make a stack frame\n\texitdepth = pr_depth;\n\n\ts = PR_EnterFunction (f);\n\t\nwhile (1)\n{\n\ts++;\t// next statement\n\n\tst = &pr_statements[s];\n\ta = (eval_t *)&pr_globals[st->a];\n\tb = (eval_t *)&pr_globals[st->b];\n\tc = (eval_t *)&pr_globals[st->c];\n\t\n\tif (!--runaway)\n\t\tPR_RunError (\"runaway loop error\");\n\t\t\n\tpr_xfunction->profile++;\n\tpr_xstatement = s;\n\t\n\tif (pr_trace)\n\t\tPR_PrintStatement (st);\n\t\t\n\tswitch (st->op)\n\t{\n\tcase OP_ADD_F:\n\t\tc->_float = a->_float + b->_float;\n\t\tbreak;\n\tcase OP_ADD_V:\n\t\tc->vector[0] = a->vector[0] + b->vector[0];\n\t\tc->vector[1] = a->vector[1] + b->vector[1];\n\t\tc->vector[2] = a->vector[2] + b->vector[2];\n\t\tbreak;\n\t\t\n\tcase OP_SUB_F:\n\t\tc->_float = a->_float - b->_float;\n\t\tbreak;\n\tcase OP_SUB_V:\n\t\tc->vector[0] = a->vector[0] - b->vector[0];\n\t\tc->vector[1] = a->vector[1] - b->vector[1];\n\t\tc->vector[2] = a->vector[2] - b->vector[2];\n\t\tbreak;\n\n\tcase OP_MUL_F:\n\t\tc->_float = a->_float * b->_float;\n\t\tbreak;\n\tcase OP_MUL_V:\n\t\tc->_float = a->vector[0]*b->vector[0]\n\t\t\t\t+ a->vector[1]*b->vector[1]\n\t\t\t\t+ a->vector[2]*b->vector[2];\n\t\tbreak;\n\tcase OP_MUL_FV:\n\t\tc->vector[0] = a->_float * b->vector[0];\n\t\tc->vector[1] = a->_float * b->vector[1];\n\t\tc->vector[2] = a->_float * b->vector[2];\n\t\tbreak;\n\tcase OP_MUL_VF:\n\t\tc->vector[0] = b->_float * a->vector[0];\n\t\tc->vector[1] = b->_float * a->vector[1];\n\t\tc->vector[2] = b->_float * a->vector[2];\n\t\tbreak;\n\n\tcase OP_DIV_F:\n\t\tc->_float = a->_float / b->_float;\n\t\tbreak;\n\t\n\tcase OP_BITAND:\n\t\tc->_float = (int)a->_float & (int)b->_float;\n\t\tbreak;\n\t\n\tcase OP_BITOR:\n\t\tc->_float = (int)a->_float | (int)b->_float;\n\t\tbreak;\n\t\n\t\t\n\tcase OP_GE:\n\t\tc->_float = a->_float >= b->_float;\n\t\tbreak;\n\tcase OP_LE:\n\t\tc->_float = a->_float <= b->_float;\n\t\tbreak;\n\tcase OP_GT:\n\t\tc->_float = a->_float > b->_float;\n\t\tbreak;\n\tcase OP_LT:\n\t\tc->_float = a->_float < b->_float;\n\t\tbreak;\n\tcase OP_AND:\n\t\tc->_float = a->_float && b->_float;\n\t\tbreak;\n\tcase OP_OR:\n\t\tc->_float = a->_float || b->_float;\n\t\tbreak;\n\t\t\n\tcase OP_NOT_F:\n\t\tc->_float = !a->_float;\n\t\tbreak;\n\tcase OP_NOT_V:\n\t\tc->_float = !a->vector[0] && !a->vector[1] && !a->vector[2];\n\t\tbreak;\n\tcase OP_NOT_S:\n\t\tc->_float = !a->string || !pr_strings[a->string];\n\t\tbreak;\n\tcase OP_NOT_FNC:\n\t\tc->_float = !a->function;\n\t\tbreak;\n\tcase OP_NOT_ENT:\n\t\tc->_float = (PROG_TO_EDICT(a->edict) == sv.edicts);\n\t\tbreak;\n\n\tcase OP_EQ_F:\n\t\tc->_float = a->_float == b->_float;\n\t\tbreak;\n\tcase OP_EQ_V:\n\t\tc->_float = (a->vector[0] == b->vector[0]) &&\n\t\t\t\t\t(a->vector[1] == b->vector[1]) &&\n\t\t\t\t\t(a->vector[2] == b->vector[2]);\n\t\tbreak;\n\tcase OP_EQ_S:\n\t\tc->_float = !strcmp(pr_strings+a->string,pr_strings+b->string);\n\t\tbreak;\n\tcase OP_EQ_E:\n\t\tc->_float = a->_int == b->_int;\n\t\tbreak;\n\tcase OP_EQ_FNC:\n\t\tc->_float = a->function == b->function;\n\t\tbreak;\n\n\n\tcase OP_NE_F:\n\t\tc->_float = a->_float != b->_float;\n\t\tbreak;\n\tcase OP_NE_V:\n\t\tc->_float = (a->vector[0] != b->vector[0]) ||\n\t\t\t\t\t(a->vector[1] != b->vector[1]) ||\n\t\t\t\t\t(a->vector[2] != b->vector[2]);\n\t\tbreak;\n\tcase OP_NE_S:\n\t\tc->_float = strcmp(pr_strings+a->string,pr_strings+b->string);\n\t\tbreak;\n\tcase OP_NE_E:\n\t\tc->_float = a->_int != b->_int;\n\t\tbreak;\n\tcase OP_NE_FNC:\n\t\tc->_float = a->function != b->function;\n\t\tbreak;\n\n//==================\n\tcase OP_STORE_F:\n\tcase OP_STORE_ENT:\n\tcase OP_STORE_FLD:\t\t// integers\n\tcase OP_STORE_S:\n\tcase OP_STORE_FNC:\t\t// pointers\n\t\tb->_int = a->_int;\n\t\tbreak;\n\tcase OP_STORE_V:\n\t\tb->vector[0] = a->vector[0];\n\t\tb->vector[1] = a->vector[1];\n\t\tb->vector[2] = a->vector[2];\n\t\tbreak;\n\t\t\n\tcase OP_STOREP_F:\n\tcase OP_STOREP_ENT:\n\tcase OP_STOREP_FLD:\t\t// integers\n\tcase OP_STOREP_S:\n\tcase OP_STOREP_FNC:\t\t// pointers\n\t\tptr = (eval_t *)((byte *)sv.edicts + b->_int);\n\t\tptr->_int = a->_int;\n\t\tbreak;\n\tcase OP_STOREP_V:\n\t\tptr = (eval_t *)((byte *)sv.edicts + b->_int);\n\t\tptr->vector[0] = a->vector[0];\n\t\tptr->vector[1] = a->vector[1];\n\t\tptr->vector[2] = a->vector[2];\n\t\tbreak;\n\t\t\n\tcase OP_ADDRESS:\n\t\ted = PROG_TO_EDICT(a->edict);\n#ifdef PARANOID\n\t\tNUM_FOR_EDICT(ed);\t\t// make sure it's in range\n#endif\n\t\tif (ed == (edict_t *)sv.edicts && sv.state == ss_active)\n\t\t\tPR_RunError (\"assignment to world entity\");\n\t\tc->_int = (byte *)((int *)&ed->v + b->_int) - (byte *)sv.edicts;\n\t\tbreak;\n\t\t\n\tcase OP_LOAD_F:\n\tcase OP_LOAD_FLD:\n\tcase OP_LOAD_ENT:\n\tcase OP_LOAD_S:\n\tcase OP_LOAD_FNC:\n\t\ted = PROG_TO_EDICT(a->edict);\n#ifdef PARANOID\n\t\tNUM_FOR_EDICT(ed);\t\t// make sure it's in range\n#endif\n\t\ta = (eval_t *)((int *)&ed->v + b->_int);\n\t\tc->_int = a->_int;\n\t\tbreak;\n\n\tcase OP_LOAD_V:\n\t\ted = PROG_TO_EDICT(a->edict);\n#ifdef PARANOID\n\t\tNUM_FOR_EDICT(ed);\t\t// make sure it's in range\n#endif\n\t\ta = (eval_t *)((int *)&ed->v + b->_int);\n\t\tc->vector[0] = a->vector[0];\n\t\tc->vector[1] = a->vector[1];\n\t\tc->vector[2] = a->vector[2];\n\t\tbreak;\n\t\t\n//==================\n\n\tcase OP_IFNOT:\n\t\tif (!a->_int)\n\t\t\ts += (signed short)st->b - 1;\t// offset the s++\n\t\tbreak;\n\t\t\n\tcase OP_IF:\n\t\tif (a->_int)\n\t\t\ts += (signed short)st->b - 1;\t// offset the s++\n\t\tbreak;\n\t\t\n\tcase OP_GOTO:\n\t\ts += (signed short)st->a - 1;\t// offset the s++\n\t\tbreak;\n\t\t\n\tcase OP_CALL0:\n\tcase OP_CALL1:\n\tcase OP_CALL2:\n\tcase OP_CALL3:\n\tcase OP_CALL4:\n\tcase OP_CALL5:\n\tcase OP_CALL6:\n\tcase OP_CALL7:\n\tcase OP_CALL8:\n\t\tpr_argc = st->op - OP_CALL0;\n\t\tif (!a->function)\n\t\t\tPR_RunError (\"NULL function\");\n\n\t\tnewf = &pr_functions[a->function];\n\n\t\tif (newf->first_statement < 0)\n\t\t{\t// negative statements are built in functions\n\t\t\ti = -newf->first_statement;\n\t\t\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\n\t\t\tif ( (i >= pr_numbuiltins)\n\t\t\t||   (pr_builtins[i] == pr_ebfs_builtins[0].function) )\n\t\t\t{\n\t\t\t\tfuncname = pr_strings + newf->s_name;\n\t\t\t\tif (pr_builtin_remap.value)\n\t\t\t\t{\n\t\t\t\t\tremaphint = NULL;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tremaphint = \"Try \\\"builtin remapping\\\" by setting PR_BUILTIN_REMAP to 1\\n\";\n\t\t\t\t}\n\t\t\t\tPR_RunError (\"Bad builtin call number %i for %s\\nPlease contact the PROGS.DAT author\\n \\\n\t\t\t\t\tUse BUILTINLIST to see all assigned builtin functions\\n%s\", i, funcname, remaphint);\n\t\t\t}\n\t\t\t// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\t\t\tpr_builtins[i] ();\n\t\t\tbreak;\n\t\t}\n\n\t\ts = PR_EnterFunction (newf);\n\t\tbreak;\n\n\tcase OP_DONE:\n\tcase OP_RETURN:\n\t\tpr_globals[OFS_RETURN] = pr_globals[st->a];\n\t\tpr_globals[OFS_RETURN+1] = pr_globals[st->a+1];\n\t\tpr_globals[OFS_RETURN+2] = pr_globals[st->a+2];\n\t\n\t\ts = PR_LeaveFunction ();\n\t\tif (pr_depth == exitdepth)\n\t\t\treturn;\t\t// all done\n\t\tbreak;\n\t\t\n\tcase OP_STATE:\n\t\ted = PROG_TO_EDICT(pr_global_struct->self);\n#ifdef FPS_20\n\t\ted->v.nextthink = pr_global_struct->time + 0.05;\n#else\n\t\ted->v.nextthink = pr_global_struct->time + 0.1;\n#endif\n\t\tif (a->_float != ed->v.frame)\n\t\t{\n\t\t\ted->v.frame = a->_float;\n\t\t}\n\t\ted->v.think = b->function;\n\t\tbreak;\n\t\t\n\tdefault:\n\t\tPR_RunError (\"Bad opcode %i\", st->op);\n\t}\n}\n\n}\n"
  },
  {
    "path": "source/progdefs.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#ifdef QUAKE2\n#include \"progdefs.q2\"\n#else\n#include \"progdefs.q1\"\n#endif\n"
  },
  {
    "path": "source/progdefs.q1",
    "content": "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[28];\n\tint\tself;\n\tint\tother;\n\tint\tworld;\n\tfloat\ttime;\n\tfloat\tframetime;\n\tfloat\tforce_retouch;\n\tstring_t\tmapname;\n\tfloat\tdeathmatch;\n\tfloat\tcoop;\n\tfloat\tteamplay;\n\tfloat\tserverflags;\n\tfloat\ttotal_secrets;\n\tfloat\ttotal_monsters;\n\tfloat\tfound_secrets;\n\tfloat\tkilled_monsters;\n\tfloat\tparm1;\n\tfloat\tparm2;\n\tfloat\tparm3;\n\tfloat\tparm4;\n\tfloat\tparm5;\n\tfloat\tparm6;\n\tfloat\tparm7;\n\tfloat\tparm8;\n\tfloat\tparm9;\n\tfloat\tparm10;\n\tfloat\tparm11;\n\tfloat\tparm12;\n\tfloat\tparm13;\n\tfloat\tparm14;\n\tfloat\tparm15;\n\tfloat\tparm16;\n\tvec3_t\tv_forward;\n\tvec3_t\tv_up;\n\tvec3_t\tv_right;\n\tfloat\ttrace_allsolid;\n\tfloat\ttrace_startsolid;\n\tfloat\ttrace_fraction;\n\tvec3_t\ttrace_endpos;\n\tvec3_t\ttrace_plane_normal;\n\tfloat\ttrace_plane_dist;\n\tint\ttrace_ent;\n\tfloat\ttrace_inopen;\n\tfloat\ttrace_inwater;\n\tint\tmsg_entity;\n\tfunc_t\tmain;\n\tfunc_t\tStartFrame;\n\tfunc_t\tPlayerPreThink;\n\tfunc_t\tPlayerPostThink;\n\tfunc_t\tClientKill;\n\tfunc_t\tClientConnect;\n\tfunc_t\tPutClientInServer;\n\tfunc_t\tClientDisconnect;\n\tfunc_t\tSetNewParms;\n\tfunc_t\tSetChangeParms;\n} globalvars_t;\n\ntypedef struct\n{\n\tfloat\tmodelindex;\n\tvec3_t\tabsmin;\n\tvec3_t\tabsmax;\n\tfloat\tltime;\n\tfloat\tmovetype;\n\tfloat\tsolid;\n\tvec3_t\torigin;\n\tvec3_t\toldorigin;\n\tvec3_t\tvelocity;\n\tvec3_t\tangles;\n\tvec3_t\tavelocity;\n\tvec3_t\tpunchangle;\n\tstring_t\tclassname;\n\tstring_t\tmodel;\n\tfloat\tframe;\n\tfloat\tskin;\n\tfloat\teffects;\n\tvec3_t\tmins;\n\tvec3_t\tmaxs;\n\tvec3_t\tsize;\n\tfunc_t\ttouch;\n\tfunc_t\tuse;\n\tfunc_t\tthink;\n\tfunc_t\tblocked;\n\tfloat\tnextthink;\n\tint\tgroundentity;\n\tfloat\thealth;\n\tfloat\tfrags;\n\tfloat\tweapon;\n\tstring_t\tweaponmodel;\n\tfloat\tweaponframe;\n\tfloat\tcurrentammo;\n\tfloat\tammo_shells;\n\tfloat\tammo_nails;\n\tfloat\tammo_rockets;\n\tfloat\tammo_cells;\n\tfloat\titems;\n\tfloat\ttakedamage;\n\tint\tchain;\n\tfloat\tdeadflag;\n\tvec3_t\tview_ofs;\n\tfloat\tbutton0;\n\tfloat\tbutton1;\n\tfloat\tbutton2;\n\tfloat\timpulse;\n\tfloat\tfixangle;\n\tvec3_t\tv_angle;\n\tfloat\tidealpitch;\n\tstring_t\tnetname;\n\tint\tenemy;\n\tfloat\tflags;\n\tfloat\tcolormap;\n\tfloat\tteam;\n\tfloat\tmax_health;\n\tfloat\tteleport_time;\n\tfloat\tarmortype;\n\tfloat\tarmorvalue;\n\tfloat\twaterlevel;\n\tfloat\twatertype;\n\tfloat\tideal_yaw;\n\tfloat\tyaw_speed;\n\tint\taiment;\n\tint\tgoalentity;\n\tfloat\tspawnflags;\n\tstring_t\ttarget;\n\tstring_t\ttargetname;\n\tfloat\tdmg_take;\n\tfloat\tdmg_save;\n\tint\tdmg_inflictor;\n\tint\towner;\n\tvec3_t\tmovedir;\n\tstring_t\tmessage;\n\tfloat\tsounds;\n\tstring_t\tnoise;\n\tstring_t\tnoise1;\n\tstring_t\tnoise2;\n\tstring_t\tnoise3;\n} entvars_t;\n\n#define PROGHEADER_CRC 5927\n"
  },
  {
    "path": "source/progdefs.q2",
    "content": "\n/* file generated by qcc, do not modify */\n\ntypedef struct\n{\tint\tpad[28];\n\tint\tself;\n\tint\tother;\n\tint\tworld;\n\tfloat\ttime;\n\tfloat\tframetime;\n\tfloat\tforce_retouch;\n\tstring_t\tmapname;\n\tstring_t\tstartspot;\n\tfloat\tdeathmatch;\n\tfloat\tcoop;\n\tfloat\tteamplay;\n\tfloat\tserverflags;\n\tfloat\ttotal_secrets;\n\tfloat\ttotal_monsters;\n\tfloat\tfound_secrets;\n\tfloat\tkilled_monsters;\n\tfloat\tparm1;\n\tfloat\tparm2;\n\tfloat\tparm3;\n\tfloat\tparm4;\n\tfloat\tparm5;\n\tfloat\tparm6;\n\tfloat\tparm7;\n\tfloat\tparm8;\n\tfloat\tparm9;\n\tfloat\tparm10;\n\tfloat\tparm11;\n\tfloat\tparm12;\n\tfloat\tparm13;\n\tfloat\tparm14;\n\tfloat\tparm15;\n\tfloat\tparm16;\n\tvec3_t\tv_forward;\n\tvec3_t\tv_up;\n\tvec3_t\tv_right;\n\tfloat\ttrace_allsolid;\n\tfloat\ttrace_startsolid;\n\tfloat\ttrace_fraction;\n\tvec3_t\ttrace_endpos;\n\tvec3_t\ttrace_plane_normal;\n\tfloat\ttrace_plane_dist;\n\tint\ttrace_ent;\n\tfloat\ttrace_inopen;\n\tfloat\ttrace_inwater;\n\tint\tmsg_entity;\n\tstring_t\tnull;\n\tfunc_t\tmain;\n\tfunc_t\tStartFrame;\n\tfunc_t\tPlayerPreThink;\n\tfunc_t\tPlayerPostThink;\n\tfunc_t\tClientKill;\n\tfunc_t\tClientConnect;\n\tfunc_t\tPutClientInServer;\n\tfunc_t\tClientDisconnect;\n\tfunc_t\tSetNewParms;\n\tfunc_t\tSetChangeParms;\n} globalvars_t;\n\ntypedef struct\n{\n\tfloat\tmodelindex;\n\tvec3_t\tabsmin;\n\tvec3_t\tabsmax;\n\tfloat\tltime;\n\tfloat\tmovetype;\n\tfloat\tsolid;\n\tvec3_t\torigin;\n\tvec3_t\toldorigin;\n\tvec3_t\tvelocity;\n\tvec3_t\tangles;\n\tvec3_t\tavelocity;\n\tvec3_t\tbasevelocity;\n\tvec3_t\tpunchangle;\n\tstring_t\tclassname;\n\tstring_t\tmodel;\n\tfloat\tframe;\n\tfloat\tskin;\n\tfloat\teffects;\n\tfloat\tdrawPercent;\n\tfloat\tgravity;\n\tfloat\tmass;\n\tfloat\tlight_level;\n\tvec3_t\tmins;\n\tvec3_t\tmaxs;\n\tvec3_t\tsize;\n\tfunc_t\ttouch;\n\tfunc_t\tuse;\n\tfunc_t\tthink;\n\tfunc_t\tblocked;\n\tfloat\tnextthink;\n\tint\tgroundentity;\n\tfloat\thealth;\n\tfloat\tfrags;\n\tfloat\tweapon;\n\tstring_t\tweaponmodel;\n\tfloat\tweaponframe;\n\tfloat\tcurrentammo;\n\tfloat\tammo_shells;\n\tfloat\tammo_nails;\n\tfloat\tammo_rockets;\n\tfloat\tammo_cells;\n\tfloat\titems;\n\tfloat\titems2;\n\tfloat\ttakedamage;\n\tint\tchain;\n\tfloat\tdeadflag;\n\tvec3_t\tview_ofs;\n\tfloat\tbutton0;\n\tfloat\tbutton1;\n\tfloat\tbutton2;\n\tfloat\timpulse;\n\tfloat\tfixangle;\n\tvec3_t\tv_angle;\n\tfloat\tidealpitch;\n\tfloat\tpitch_speed;\n\tstring_t\tnetname;\n\tint\tenemy;\n\tfloat\tflags;\n\tfloat\tcolormap;\n\tfloat\tteam;\n\tfloat\tmax_health;\n\tfloat\tteleport_time;\n\tfloat\tarmortype;\n\tfloat\tarmorvalue;\n\tfloat\twaterlevel;\n\tfloat\twatertype;\n\tfloat\tideal_yaw;\n\tfloat\tyaw_speed;\n\tint\taiment;\n\tint\tgoalentity;\n\tfloat\tspawnflags;\n\tstring_t\ttarget;\n\tstring_t\ttargetname;\n\tfloat\tdmg_take;\n\tfloat\tdmg_save;\n\tint\tdmg_inflictor;\n\tint\towner;\n\tvec3_t\tmovedir;\n\tstring_t\tmessage;\n\tfloat\tsounds;\n\tstring_t\tnoise;\n\tstring_t\tnoise1;\n\tstring_t\tnoise2;\n\tstring_t\tnoise3;\n\tfloat\tdmg;\n\tfloat\tdmgtime;\n\tfloat\tair_finished;\n\tfloat\tpain_finished;\n\tfloat\tradsuit_finished;\n\tfloat\tspeed;\n} entvars_t;\n\n#define PROGHEADER_CRC 31586\n"
  },
  {
    "path": "source/progs.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"pr_comp.h\"\t\t\t// defs shared with qcc\n#include \"progdefs.h\"\t\t\t// generated by program cdefs\n\ntypedef union eval_s\n{\n\tstring_t\t\tstring;\n\tfloat\t\t\t_float;\n\tfloat\t\t\tvector[3];\n\tfunc_t\t\t\tfunction;\n\tint\t\t\t\t_int;\n\tint\t\t\t\tedict;\n} eval_t;\t\n\n#define\tMAX_ENT_LEAFS\t16\ntypedef struct edict_s\n{\n\tbool\tfree;\n\tlink_t\t\tarea;\t\t\t\t// linked to a division node or leaf\n\t\n\tint\t\t\tnum_leafs;\n\tshort\t\tleafnums[MAX_ENT_LEAFS];\n\n\tentity_state_t\tbaseline;\n\t\n\tfloat\t\tfreetime;\t\t\t// sv.time when the object was freed\n\tentvars_t\tv;\t\t\t\t\t// C exported fields from progs\n// other fields from progs come immediately after\n} edict_t;\n#define\tEDICT_FROM_AREA(l) STRUCT_FROM_LINK(l,edict_t,area)\n\n//============================================================================\n\nextern\tdprograms_t\t\t*progs;\nextern\tdfunction_t\t\t*pr_functions;\nextern\tchar\t\t\t*pr_strings;\nextern\tddef_t\t\t\t*pr_globaldefs;\nextern\tddef_t\t\t\t*pr_fielddefs;\nextern\tdstatement_t\t*pr_statements;\nextern\tglobalvars_t\t*pr_global_struct;\nextern\tfloat\t\t\t*pr_globals;\t\t\t// same as pr_global_struct\n\nextern\tint\t\t\t\tpr_edict_size;\t// in bytes\n\n//============================================================================\n\nvoid PR_Init (void);\n\nvoid PR_ExecuteProgram (func_t fnum);\nvoid PR_LoadProgs (const char *progsname);\n\nvoid PR_Profile_f (void);\n\nedict_t *ED_Alloc (void);\nvoid ED_Free (edict_t *ed);\n\nchar\t*ED_NewString (char *string);\n// returns a copy of the string allocated from the server's string heap\n\nvoid ED_Print (edict_t *ed);\nvoid ED_Write (FILE *f, edict_t *ed);\nchar *ED_ParseEdict (char *data, edict_t *ent);\n\nvoid ED_WriteGlobals (FILE *f);\nvoid ED_ParseGlobals (char *data);\n\nvoid ED_LoadFromFile (char *data);\n\n//define EDICT_NUM(n) ((edict_t *)(sv.edicts+ (n)*pr_edict_size))\n//define NUM_FOR_EDICT(e) (((byte *)(e) - sv.edicts)/pr_edict_size)\n\nedict_t *EDICT_NUM(int n);\nint NUM_FOR_EDICT(edict_t *e);\n\n#define\tNEXT_EDICT(e) ((edict_t *)( (byte *)e + pr_edict_size))\n\n#define\tEDICT_TO_PROG(e) ((byte *)e - (byte *)sv.edicts)\n#define PROG_TO_EDICT(e) ((edict_t *)((byte *)sv.edicts + e))\n\n//============================================================================\n\n#define\tG_FLOAT(o) (pr_globals[o])\n#define\tG_INT(o) (*(int *)&pr_globals[o])\n#define\tG_EDICT(o) ((edict_t *)((byte *)sv.edicts+ *(int *)&pr_globals[o]))\n#define G_EDICTNUM(o) NUM_FOR_EDICT(G_EDICT(o))\n#define\tG_VECTOR(o) (&pr_globals[o])\n#define\tG_STRING(o) (pr_strings + *(string_t *)&pr_globals[o])\n#define\tG_FUNCTION(o) (*(func_t *)&pr_globals[o])\n\n#define\tE_FLOAT(e,o) (((float*)&e->v)[o])\n#define\tE_INT(e,o) (*(int *)&((float*)&e->v)[o])\n#define\tE_VECTOR(e,o) (&((float*)&e->v)[o])\n#define\tE_STRING(e,o) (pr_strings + *(string_t *)&((float*)&e->v)[o])\n\nextern\tint\t\ttype_size[8];\n\ntypedef void (*builtin_t) (void);\nextern\tbuiltin_t *pr_builtins;\nextern int pr_numbuiltins;\n\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  start\ntypedef struct ebfs_builtin_s\n{\n\tint\t\t\tdefault_funcno;\n\tchar\t\t*funcname;\n\tbuiltin_t\tfunction;\n\tint\t\t\tfuncno;\n} ebfs_builtin_t;\n\nextern ebfs_builtin_t\tpr_ebfs_builtins[];\nextern int\t\t\t\tpr_ebfs_numbuiltins;\n\n#define PR_DEFAULT_FUNCNO_BUILTIN_FIND\t100\n\nextern cvar_t\tpr_builtin_find;\nextern cvar_t\tpr_builtin_remap;\n\n#define PR_DEFAULT_FUNCNO_EXTENSION_FIND\t99\t// 2001-10-20 Extension System by Lord Havoc/Maddes\n// 2001-09-14 Enhanced BuiltIn Function System (EBFS) by Maddes  end\n\n// 2001-10-20 Extension System by LordHavoc  start\nextern char *pr_extensions[];\nextern int\tpr_numextensions;\n// 2001-10-20 Extension System by LordHavoc  end\n\nextern int\t\tpr_argc;\n\nextern\tbool\tpr_trace;\nextern\tdfunction_t\t*pr_xfunction;\nextern\tint\t\t\tpr_xstatement;\n\nextern\tunsigned short\t\tpr_crc;\n\nvoid PR_RunError (char *error, ...);\n\nvoid ED_PrintEdicts (void);\nvoid ED_PrintNum (int ent);\n\neval_t *GetEdictFieldValue(edict_t *ed, char *field);\n\n#define   GETEDICTFIELDVALUE(ed, fieldoffset) (fieldoffset ? (eval_t *)((byte *)&ed->v + fieldoffset) : NULL)\n\nextern int eval_alpha;\nextern int eval_renderamt;\nextern int eval_drawonlytoclient;\nextern int eval_nodrawtoclient;\n"
  },
  {
    "path": "source/protocol.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// protocol.h -- communications protocols\n\n/*\n================\nHere is a short list of known protocol used by other NetQuake ports:\n- 15: Default NetQuake protocol.\n- 666: FitzQuake protocol (also used by QuakeSpasm)\n- 35, 36, 37, 38: ProQuake protocol\n================\n*/\n#define\tPROTOCOL_NETQUAKE\t15\t// Official NetQuake protocol used.\n#define PROTOCOL_FITZQUAKE\t666 // Protocol for FitzQuake 0.85\n\n// if the high bit of the servercmd is set, the low bits are fast update flags:\n#define\tU_MOREBITS\tBIT(0)\n#define\tU_ORIGIN1\tBIT(1)\n#define\tU_ORIGIN2\tBIT(2)\n#define\tU_ORIGIN3\tBIT(3)\n#define\tU_ANGLE2\tBIT(4)\n#define\tU_NOLERP\tBIT(5)\t\t// don't interpolate movement\n#define\tU_FRAME\t\tBIT(6)\n#define U_SIGNAL\tBIT(7)\t\t// just differentiates from other updates\n\n// svc_update can pass all of the fast update bits, plus more\n#define\tU_ANGLE1\tBIT(8)\n#define\tU_ANGLE3\tBIT(9)\n#define\tU_MODEL\t\tBIT(10)\n#define\tU_COLORMAP\tBIT(11)\n#define\tU_SKIN\t\tBIT(12)\n#define\tU_EFFECTS\tBIT(13)\n#define\tU_LONGENTITY\tBIT(14)\n\n// FitzQuake -- Protocol extender\n#define U_EXTEND1\t\tBIT(15)\n#define U_ALPHA\t\t\tBIT(16) // 1 byte, uses ENTALPHA_ENCODE, not sent if equal to baseline\n#define U_FRAME2\t\tBIT(17) // 1 byte, this is .frame & 0xFF00 (second byte)\n#define U_MODEL2\t\tBIT(18) // 1 byte, this is .modelindex & 0xFF00 (second byte)\n#define U_LERPFINISH\tBIT(19) // 1 byte, 0.0-1.0 maps to 0-255, not sent if exactly 0.1, this is ent->v.nextthink - sv.time, used for lerping\n#define U_SCALE\t\t\tBIT(20) // 1 byte, for PROTOCOL_RMQ PRFL_EDICTSCALE, currently read but ignored\n#define U_RENDERAMT\t\tBIT(21)\n#define U_UNUSED22\t\tBIT(22)\n#define U_EXTEND2\t\tBIT(23) // another byte to follow, future expansion\n\n#define\tSU_VIEWHEIGHT\tBIT(0)\n#define\tSU_IDEALPITCH\tBIT(1)\n#define\tSU_PUNCH1\t\tBIT(2)\n#define\tSU_PUNCH2\t\tBIT(3)\n#define\tSU_PUNCH3\t\tBIT(4)\n#define\tSU_VELOCITY1\tBIT(5)\n#define\tSU_VELOCITY2\tBIT(6)\n#define\tSU_VELOCITY3\tBIT(7)\n//define\tSU_AIMENT\t\tBIT(8)  AVAILABLE BIT\n#define\tSU_ITEMS\t\tBIT(9)\n#define\tSU_ONGROUND\t\tBIT(10)\t\t// no data follows, the bit is it\n#define\tSU_INWATER\t\tBIT(11)\t\t// no data follows, the bit is it\n#define\tSU_WEAPONFRAME\tBIT(12)\n#define\tSU_ARMOR\t\tBIT(13)\n#define\tSU_WEAPON\t\tBIT(14)\n\n// FitzQuake -- Protocol extender \n#define SU_EXTEND1\t\tBIT(15) // another byte to follow\n#define SU_WEAPON2\t\tBIT(16) // 1 byte, this is .weaponmodel & 0xFF00 (second byte)\n#define SU_ARMOR2\t\tBIT(17) // 1 byte, this is .armorvalue & 0xFF00 (second byte)\n#define SU_AMMO2\t\tBIT(18) // 1 byte, this is .currentammo & 0xFF00 (second byte)\n#define SU_SHELLS2\t\tBIT(19) // 1 byte, this is .ammo_shells & 0xFF00 (second byte)\n#define SU_NAILS2\t\tBIT(20) // 1 byte, this is .ammo_nails & 0xFF00 (second byte)\n#define SU_ROCKETS2\t\tBIT(21) // 1 byte, this is .ammo_rockets & 0xFF00 (second byte)\n#define SU_CELLS2\t\tBIT(22) // 1 byte, this is .ammo_cells & 0xFF00 (second byte)\n#define SU_EXTEND2\t\tBIT(23) // another byte to follow\n#define SU_WEAPONFRAME2\tBIT(24) // 1 byte, this is .weaponframe & 0xFF00 (second byte)\n#define SU_WEAPONALPHA\tBIT(25) // 1 byte, this is alpha for weaponmodel, uses ENTALPHA_ENCODE, not sent if ENTALPHA_DEFAULT\n#define SU_UNUSED26\t\tBIT(26)\n#define SU_UNUSED27\t\tBIT(27)\n#define SU_UNUSED28\t\tBIT(28)\n#define SU_UNUSED29\t\tBIT(29)\n#define SU_UNUSED30\t\tBIT(30)\n#define SU_EXTEND3\t\tBIT(31) // another byte to follow, future expansion\n\n\n// a sound with no channel is a local only sound\n#define\tSND_VOLUME\t\tBIT(0)\t\t// a byte\n#define\tSND_ATTENUATION\tBIT(1)\t\t// a byte\n#define\tSND_LOOPING\t\tBIT(2)\t\t// a long\n\n\n// defaults for clientinfo messages\n#define\tDEFAULT_VIEWHEIGHT\t22\n\n\n// game types sent by serverinfo\n// these determine which intermission screen plays\n#define\tGAME_COOP\t\t\t0\n#define\tGAME_DEATHMATCH\t\t1\n\n//==================\n// note that there are some defs.qc that mirror to these numbers\n// also related to svc_strings[] in cl_parse\n//==================\n\n//\n// server to client\n//\n#define\tsvc_bad\t\t\t\t0\n#define\tsvc_nop\t\t\t\t1\n#define\tsvc_disconnect\t\t2\n#define\tsvc_updatestat\t\t3\t// [byte] [long]\n#define\tsvc_version\t\t\t4\t// [long] server version\n#define\tsvc_setview\t\t\t5\t// [short] entity number\n#define\tsvc_sound\t\t\t6\t// <see code>\n#define\tsvc_time\t\t\t7\t// [float] server time\n#define\tsvc_print\t\t\t8\t// [string] null terminated string\n#define\tsvc_stufftext\t\t9\t// [string] stuffed into client's console buffer\n\t\t\t\t\t\t\t\t// the string should be \\n terminated\n#define\tsvc_setangle\t\t10\t// [angle3] set the view angle to this absolute value\n\t\n#define\tsvc_serverinfo\t\t11\t// [long] version\n\t\t\t\t\t\t// [string] signon string\n\t\t\t\t\t\t// [string]..[0]model cache\n\t\t\t\t\t\t// [string]...[0]sounds cache\n#define\tsvc_lightstyle\t\t12\t// [byte] [string]\n#define\tsvc_updatename\t\t13\t// [byte] [string]\n#define\tsvc_updatefrags\t\t14\t// [byte] [short]\n#define\tsvc_clientdata\t\t15\t// <shortbits + data>\n#define\tsvc_stopsound\t\t16\t// <see code>\n#define\tsvc_updatecolors\t17\t// [byte] [byte]\n#define\tsvc_particle\t\t18\t// [vec3] <variable>\n#define\tsvc_damage\t\t\t19\n\t\n#define\tsvc_spawnstatic\t\t20\n//\tsvc_spawnbinary\t\t21\n#define\tsvc_spawnbaseline\t22\n\t\n#define\tsvc_temp_entity\t\t23\n\n#define\tsvc_setpause\t\t24\t// [byte] on / off\n#define\tsvc_signonnum\t\t25\t// [byte]  used for the signon sequence\n\n#define\tsvc_centerprint\t\t26\t// [string] to put in center of the screen\n\n#define\tsvc_killedmonster\t27\n#define\tsvc_foundsecret\t\t28\n\n#define\tsvc_spawnstaticsound\t29\t// [coord3] [byte] samp [byte] vol [byte] aten\n\n#define\tsvc_intermission\t30\t\t// [string] music\n#define\tsvc_finale\t\t\t31\t\t// [string] music [string] text\n\n#define\tsvc_cdtrack\t\t\t32\t\t// [byte] track [byte] looptrack\n#define svc_sellscreen\t\t33\n\n#define svc_cutscene\t\t34\n\n//\n// client to server\n//\n#define\tclc_bad\t\t\t0\n#define\tclc_nop \t\t1\n#define\tclc_disconnect\t2\n#define\tclc_move\t\t3\t\t\t// [usercmd_t]\n#define\tclc_stringcmd\t4\t\t// [string] message\n\n\n//\n// temp entity events\n//\n#define\tTE_SPIKE\t\t\t0\n#define\tTE_SUPERSPIKE\t\t1\n#define\tTE_GUNSHOT\t\t\t2\n#define\tTE_EXPLOSION\t\t3\n#define\tTE_TAREXPLOSION\t\t4\n#define\tTE_LIGHTNING1\t\t5\n#define\tTE_LIGHTNING2\t\t6\n#define\tTE_WIZSPIKE\t\t\t7\n#define\tTE_KNIGHTSPIKE\t\t8\n#define\tTE_LIGHTNING3\t\t9\n#define\tTE_LAVASPLASH\t\t10\n#define\tTE_TELEPORT\t\t\t11\n#define TE_EXPLOSION2\t\t12\n\n// PGM 01/21/97 \n#define TE_BEAM\t\t\t\t13\n// PGM 01/21/97 \n\n#ifdef QUAKE2\n#define TE_IMPLOSION\t\t14\n#define TE_RAILTRAIL\t\t15\n#endif\n"
  },
  {
    "path": "source/quakeasm.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//\n// quakeasm.h: general asm header file\n//\n\n//#define GLQUAKE\t1\n\n#if defined(_WIN32) && !defined(WINDED)\n\n#if defined(_M_IX86)\n#define __i386__\t1\n#endif\n\n#endif\n\n#ifdef __i386__\n#define id386\t1\n#else\n#define id386\t0\n#endif\n\n// !!! must be kept the same as in d_iface.h !!!\n#define TRANSPARENT_COLOR\t255\n\n#ifndef NeXT\n#ifndef GLQUAKE\n\t.extern C(d_zistepu)\n\t.extern C(d_pzbuffer)\n\t.extern C(d_zistepv)\n\t.extern C(d_zrowbytes)\n\t.extern C(d_ziorigin)\n\t.extern C(r_turb_s)\n\t.extern C(r_turb_t)\n\t.extern C(r_turb_pdest)\n\t.extern C(r_turb_spancount)\n\t.extern C(r_turb_turb)\n\t.extern C(r_turb_pbase)\n\t.extern C(r_turb_sstep)\n\t.extern C(r_turb_tstep)\n\t.extern\tC(r_bmodelactive)\n\t.extern\tC(d_sdivzstepu)\n\t.extern\tC(d_tdivzstepu)\n\t.extern\tC(d_sdivzstepv)\n\t.extern\tC(d_tdivzstepv)\n\t.extern\tC(d_sdivzorigin)\n\t.extern\tC(d_tdivzorigin)\n\t.extern\tC(sadjust)\n\t.extern\tC(tadjust)\n\t.extern\tC(bbextents)\n\t.extern\tC(bbextentt)\n\t.extern\tC(cacheblock)\n\t.extern\tC(d_viewbuffer)\n\t.extern\tC(cachewidth)\n\t.extern\tC(d_pzbuffer)\n\t.extern\tC(d_zrowbytes)\n\t.extern\tC(d_zwidth)\n\t.extern C(d_scantable)\n\t.extern C(r_lightptr)\n\t.extern C(r_numvblocks)\n\t.extern C(prowdestbase)\n\t.extern C(pbasesource)\n\t.extern C(r_lightwidth)\n\t.extern C(lightright)\n\t.extern C(lightrightstep)\n\t.extern C(lightdeltastep)\n\t.extern C(lightdelta)\n\t.extern C(lightright)\n\t.extern C(lightdelta)\n\t.extern C(sourcetstep)\n\t.extern C(surfrowbytes)\n\t.extern C(lightrightstep)\n\t.extern C(lightdeltastep)\n\t.extern C(r_sourcemax)\n\t.extern C(r_stepback)\n\t.extern C(colormap)\n\t.extern C(blocksize)\n\t.extern C(sourcesstep)\n\t.extern C(lightleft)\n\t.extern C(blockdivshift)\n\t.extern C(blockdivmask)\n\t.extern C(lightleftstep)\n\t.extern C(r_origin)\n\t.extern C(r_ppn)\n\t.extern C(r_pup)\n\t.extern C(r_pright)\n\t.extern C(ycenter)\n\t.extern C(xcenter)\n\t.extern C(d_vrectbottom_particle)\n\t.extern C(d_vrectright_particle)\n\t.extern C(d_vrecty)\n\t.extern C(d_vrectx)\n\t.extern C(d_pix_shift)\n\t.extern C(d_pix_min)\n\t.extern C(d_pix_max)\n\t.extern C(d_y_aspect_shift)\n\t.extern C(screenwidth)\n\t.extern C(r_leftclipped)\n\t.extern C(r_leftenter)\n\t.extern C(r_rightclipped)\n\t.extern C(r_rightenter)\n\t.extern C(modelorg)\n\t.extern C(xscale)\n\t.extern C(r_refdef)\n\t.extern C(yscale)\n\t.extern C(r_leftexit)\n\t.extern C(r_rightexit)\n\t.extern C(r_lastvertvalid)\n\t.extern C(cacheoffset)\n\t.extern C(newedges)\n\t.extern C(removeedges)\n\t.extern C(r_pedge)\n\t.extern C(r_framecount)\n\t.extern C(r_u1)\n\t.extern C(r_emitted)\n\t.extern C(edge_p)\n\t.extern C(surface_p)\n\t.extern C(surfaces)\n\t.extern C(r_lzi1)\n\t.extern C(r_v1)\n\t.extern C(r_ceilv1)\n\t.extern C(r_nearzi)\n\t.extern C(r_nearzionly)\n\t.extern C(edge_aftertail)\n\t.extern C(edge_tail)\n\t.extern C(current_iv)\n\t.extern C(edge_head_u_shift20)\n\t.extern C(span_p)\n\t.extern C(edge_head)\n\t.extern C(fv)\n\t.extern C(edge_tail_u_shift20)\n\t.extern C(r_apverts)\n\t.extern C(r_anumverts)\n\t.extern C(aliastransform)\n\t.extern C(r_avertexnormals)\n\t.extern C(r_plightvec)\n\t.extern C(r_ambientlight)\n\t.extern C(r_shadelight)\n\t.extern C(aliasxcenter)\n\t.extern C(aliasycenter)\n\t.extern C(a_sstepxfrac)\n\t.extern C(r_affinetridesc)\n\t.extern C(acolormap)\n\t.extern C(d_pcolormap)\n\t.extern C(r_affinetridesc)\n\t.extern C(d_sfrac)\n\t.extern C(d_ptex)\n\t.extern C(d_pedgespanpackage)\n\t.extern C(d_tfrac)\n\t.extern C(d_light)\n\t.extern C(d_zi)\n\t.extern C(d_pdest)\n\t.extern C(d_pz)\n\t.extern C(d_aspancount)\n\t.extern C(erroradjustup)\n\t.extern C(errorterm)\n\t.extern C(d_xdenom)\n\t.extern C(r_p0)\n\t.extern C(r_p1)\n\t.extern C(r_p2)\n\t.extern C(a_tstepxfrac)\n\t.extern C(r_sstepx)\n\t.extern C(r_tstepx)\n\t.extern C(a_ststepxwhole)\n\t.extern C(zspantable)\n\t.extern C(skintable)\n\t.extern C(r_zistepx)\n\t.extern C(erroradjustdown)\n\t.extern C(d_countextrastep)\n\t.extern C(ubasestep)\n\t.extern C(a_ststepxwhole)\n\t.extern C(a_tstepxfrac)\n\t.extern C(r_lstepx)\n\t.extern C(a_spans)\n\t.extern C(erroradjustdown)\n\t.extern C(d_pdestextrastep)\n\t.extern C(d_pzextrastep)\n\t.extern C(d_sfracextrastep)\n\t.extern C(d_ptexextrastep)\n\t.extern C(d_countextrastep)\n\t.extern C(d_tfracextrastep)\n\t.extern C(d_lightextrastep)\n\t.extern C(d_ziextrastep)\n\t.extern C(d_pdestbasestep)\n\t.extern C(d_pzbasestep)\n\t.extern C(d_sfracbasestep)\n\t.extern C(d_ptexbasestep)\n\t.extern C(ubasestep)\n\t.extern C(d_tfracbasestep)\n\t.extern C(d_lightbasestep)\n\t.extern C(d_zibasestep)\n\t.extern C(zspantable)\n\t.extern C(r_lstepy)\n\t.extern C(r_sstepy)\n\t.extern C(r_tstepy)\n\t.extern C(r_zistepy)\n\t.extern C(D_PolysetSetEdgeTable)\n\t.extern C(D_RasterizeAliasPolySmooth)\n\n\t.extern float_point5\n\t.extern Float2ToThe31nd\n\t.extern izistep\n\t.extern izi\n\t.extern FloatMinus2ToThe31nd\n\t.extern float_1\n\t.extern float_particle_z_clip\n\t.extern float_minus_1\n\t.extern float_0\n\t.extern fp_16\n\t.extern fp_64k\n\t.extern fp_1m\n\t.extern fp_1m_minus_1\n\t.extern fp_8 \n\t.extern entryvec_table\n\t.extern advancetable\n\t.extern sstep\n\t.extern tstep\n\t.extern pspantemp\n\t.extern counttemp\n\t.extern jumptemp\n\t.extern reciprocal_table\n\t.extern DP_Count\n\t.extern DP_u\n\t.extern DP_v\n\t.extern DP_32768\n\t.extern DP_Color\n\t.extern DP_Pix\n\t.extern DP_EntryTable\n\t.extern\tpbase\n\t.extern s\n\t.extern t\n\t.extern sfracf\n\t.extern tfracf\n\t.extern snext\n\t.extern tnext\n\t.extern\tspancountminus1\n\t.extern zi16stepu\n\t.extern sdivz16stepu\n\t.extern tdivz16stepu\n\t.extern\tzi8stepu\n\t.extern sdivz8stepu\n\t.extern tdivz8stepu\n\t.extern reciprocal_table_16\n\t.extern entryvec_table_16\n\t.extern ceil_cw\n\t.extern single_cw\n\t.extern fp_64kx64k\n\t.extern pz\n\t.extern spr8entryvec_table\n#endif\n\n\t.extern C(snd_scaletable)\n\t.extern C(paintbuffer)\n\t.extern C(snd_linear_count)\n\t.extern C(snd_p)\n\t.extern C(snd_vol)\n\t.extern C(snd_out)\n\t.extern C(vright)\n\t.extern C(vup)\n\t.extern C(vpn)\n\t.extern C(BOPS_Error)\n\n#endif\n"
  },
  {
    "path": "source/quakedef.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// quakedef.h -- primary header for client\n\n#define m_none 0\n#define m_main 1\n#define m_singleplayer 2\n#define m_load 3\n#define m_save 4\n#define m_multiplayer 5\n#define m_setup 6\n#define m_net 7\n#define m_options 8\n#define m_video 9\n#define m_keys 10\n#define m_help 11\n#define m_quit 12\n#define m_lanconfig 13\n#define m_gameoptions 14\n#define m_search 15\n#define m_slist 16\n#define m_onlineserverlist 17\n#define m_benchmark 18\n#define m_mods 19\n#define m_graphics 20\n\nextern int m_state;\n\n#define\tQUAKE_GAME\t\t\t// as opposed to utilities\n//#define\tDEBUG\n\n#define ENGINE_NAME\t\t\t\"vitaQuake\"\n#define\tVERSION\t\t\t\t4.20\n#define VERSION_PROQUAKE\t3.50\n#define\tGLQUAKE_VERSION\t    1.00\n\n//define\tPARANOID\t\t\t// speed sapping error checking\n\n#define\tGAMENAME_DIR\t\"id1\"\n\n#include <math.h>\n#include <string.h>\n#include <stdarg.h>\n#include <stdio.h>\n#include <stdlib.h>\n#include <setjmp.h>\n#include <malloc.h>\n#include \"neon_mathfun.h\"\n\n#if defined(_WIN32) && !defined(WINDED)\n\n#if defined(_M_IX86)\n#define __i386__\t1\n#endif\n\nvoid\tVID_LockBuffer (void);\nvoid\tVID_UnlockBuffer (void);\n\n#else\n\n#define\tVID_LockBuffer()\n#define\tVID_UnlockBuffer()\n\n#endif\n\n#if defined __i386__ // && !defined __sun__\n#define id386\t1\n#else\n#define id386\t0\n#endif\n\n#if id386\n#define UNALIGNED_OK\t1\t// set to 0 if unaligned accesses are not supported\n#else\n#define UNALIGNED_OK\t0\n#endif\n\n// !!! if this is changed, it must be changed in d_ifacea.h too !!!\n#define CACHE_SIZE\t32\t\t// used to align key data structures\n\n#define\tMINIMUM_MEMORY\t\t\t0x550000\n#define\tMINIMUM_MEMORY_LEVELPAK\t(MINIMUM_MEMORY + 0x100000)\n\n#define MAX_NUM_ARGVS\t50\n\n// up / down\n#define\tPITCH\t0\n\n// left / right\n#define\tYAW\t\t1\n\n// fall over\n#define\tROLL\t2\n\n\n#define\tMAX_QPATH\t\t64\t\t\t// max length of a quake game pathname\n#define\tMAX_OSPATH\t\t128\t\t\t// max length of a filesystem pathname\n\n#define\tON_EPSILON\t\t0.1\t\t\t// point on plane side epsilon\n\n#define\tMAX_MSGLEN\t\t8000\t\t// max length of a reliable message\n#define\tMAX_DATAGRAM\t1024\t\t// max length of unreliable message\n\n//\n// per-level limits\n//\n#define\tMAX_EDICTS\t\t32768\n#define\tMAX_LIGHTSTYLES\t64\n#define\tMAX_MODELS\t\t256\t\t\t// these are sent over the net as bytes\n#define\tMAX_SOUNDS\t\t256\t\t\t// so they cannot be blindly increased\n\n#define\tSAVEGAME_COMMENT_LENGTH\t39\n\n#define\tMAX_STYLESTRING\t64\n\n#define BIT(x) (1<<x)\t// Ch0wW: To ease things slightly\n\n//\n// stats are integers communicated to the client by the server\n//\n#define\tMAX_CL_STATS\t\t32\n#define\tSTAT_HEALTH\t\t\t0\n#define\tSTAT_FRAGS\t\t\t1\n#define\tSTAT_WEAPON\t\t\t2\n#define\tSTAT_AMMO\t\t\t3\n#define\tSTAT_ARMOR\t\t\t4\n#define\tSTAT_WEAPONFRAME\t5\n#define\tSTAT_SHELLS\t\t\t6\n#define\tSTAT_NAILS\t\t\t7\n#define\tSTAT_ROCKETS\t\t8\n#define\tSTAT_CELLS\t\t\t9\n#define\tSTAT_ACTIVEWEAPON\t10\n#define\tSTAT_TOTALSECRETS\t11\n#define\tSTAT_TOTALMONSTERS\t12\n#define\tSTAT_SECRETS\t\t13\t\t// bumped on client side by svc_foundsecret\n#define\tSTAT_MONSTERS\t\t14\t\t// bumped by svc_killedmonster\n\n// stock defines\n\n#define\tIT_SHOTGUN\t\t\t\tBIT(0)\n#define\tIT_SUPER_SHOTGUN\t\tBIT(1)\n#define\tIT_NAILGUN\t\t\t\tBIT(2)\n#define\tIT_SUPER_NAILGUN\t\tBIT(3)\n#define\tIT_GRENADE_LAUNCHER\t\tBIT(4)\n#define\tIT_ROCKET_LAUNCHER\t\tBIT(5)\n#define\tIT_LIGHTNING\t\t\tBIT(6)\n#define IT_SUPER_LIGHTNING      BIT(7)\n#define IT_SHELLS               BIT(8)\n#define IT_NAILS                BIT(9)\n#define IT_ROCKETS              BIT(10)\n#define IT_CELLS                BIT(11)\n#define IT_AXE                  BIT(12)\n#define IT_ARMOR1               BIT(13)\n#define IT_ARMOR2               BIT(14)\n#define IT_ARMOR3               BIT(15)\n#define IT_SUPERHEALTH          BIT(16)\n#define IT_KEY1                 BIT(17)\n#define IT_KEY2                 BIT(18)\n#define\tIT_INVISIBILITY\t\t\tBIT(19)\n#define\tIT_INVULNERABILITY\t\tBIT(20)\n#define\tIT_SUIT\t\t\t\t\tBIT(21)\n#define\tIT_QUAD\t\t\t\t\tBIT(22)\n// [......]\n#define IT_SIGIL1               BIT(27)\n#define IT_SIGIL2               BIT(28)\n#define IT_SIGIL3               BIT(29)\n#define IT_SIGIL4               BIT(30)\n\n//===========================================\n//rogue changed and added defines\n\n#define RIT_SHELLS              128\n#define RIT_NAILS               256\n#define RIT_ROCKETS             512\n#define RIT_CELLS               1024\n#define RIT_AXE                 2048\n#define RIT_LAVA_NAILGUN        4096\n#define RIT_LAVA_SUPER_NAILGUN  8192\n#define RIT_MULTI_GRENADE       16384\n#define RIT_MULTI_ROCKET        32768\n#define RIT_PLASMA_GUN          65536\n#define RIT_ARMOR1              8388608\n#define RIT_ARMOR2              16777216\n#define RIT_ARMOR3              33554432\n#define RIT_LAVA_NAILS          67108864\n#define RIT_PLASMA_AMMO         134217728\n#define RIT_MULTI_ROCKETS       268435456\n#define RIT_SHIELD              536870912\n#define RIT_ANTIGRAV            1073741824\n#define RIT_SUPERHEALTH         2147483648\n\n//MED 01/04/97 added hipnotic defines\n//===========================================\n//hipnotic added defines\n#define HIT_PROXIMITY_GUN_BIT 16\n#define HIT_MJOLNIR_BIT       7\n#define HIT_LASER_CANNON_BIT  23\n#define HIT_PROXIMITY_GUN   BIT(HIT_PROXIMITY_GUN_BIT)\n#define HIT_MJOLNIR         BIT(HIT_MJOLNIR_BIT)\n#define HIT_LASER_CANNON    BIT(HIT_LASER_CANNON_BIT)\n#define HIT_WETSUIT         BIT(25)\n#define HIT_EMPATHY_SHIELDS BIT(26)\n\n//===========================================\n\n#define\tMAX_SCOREBOARD\t\t16\n#define\tMAX_SCOREBOARDNAME\t32\n\n#define\tSOUND_CHANNELS\t\t8\n\n// This makes anyone on id's net privileged\n// Use for multiplayer testing only - VERY dangerous!!!\n// #define IDGODS\n\n#include \"common.h\"\n#include \"bspfile.h\"\n#include \"vid.h\"\n#include \"sys.h\"\n#include \"zone.h\"\n#include \"mathlib.h\"\n\ntypedef struct\n{\n\tvec3_t\torigin;\n\tvec3_t\tangles;\n\tint\t\tmodelindex;\n\tint\t\tframe;\n\tint\t\tcolormap;\n\tint\t\tskin;\n\tint\t\teffects;\n\tunsigned short nodrawtoclient;\n\tunsigned short drawonlytoclient;\n} entity_state_t;\n\n\n#include \"wad.h\"\n#include \"draw.h\"\n#include \"cvar.h\"\n#include \"screen.h\"\n#include \"net.h\"\n#include \"protocol.h\"\n#include \"cmd.h\"\n#include \"sbar.h\"\n#include \"sound.h\"\n#include \"render.h\"\n#include \"client.h\"\n#include \"progs.h\"\n#include \"server.h\"\n\n#ifdef GLQUAKE\n#include \"gl_model.h\"\n#else\n#include \"model.h\"\n#include \"d_iface.h\"\n#endif\n\n#include \"input.h\"\n#include \"world.h\"\n#include \"keys.h\"\n#include \"console.h\"\n#include \"view.h\"\n#include \"menu.h\"\n#include \"crc.h\"\n#include \"cdaudio.h\"\n\n#ifdef GLQUAKE\n#include \"glquake.h\"\n#endif\n\n#include \"image.h\"\n\n//=============================================================================\n\n// the host system specifies the base of the directory tree, the\n// command line parms passed to the program, and the amount of memory\n// available for the program to use\n\ntypedef struct\n{\n\tchar\t*basedir;\n\tchar\t*cachedir;\t\t// for development over ISDN lines\n\tint\t\targc;\n\tchar\t**argv;\n\tvoid\t*membase;\n\tint\t\tmemsize;\n} quakeparms_t;\n\n\n//=============================================================================\n\n\n\nextern bool noclip_anglehack;\n\n\n//\n// host\n//\nextern\tquakeparms_t host_parms;\n\nextern\tcvar_t\t\tsys_ticrate;\nextern\tcvar_t\t\tsys_nostdout;\nextern\tcvar_t\t\tdeveloper;\n\nextern\tbool\thost_initialized;\t\t// true if into command execution\nextern\tdouble\t\thost_frametime;\nextern\tbyte\t\t*host_basepal;\nextern\tbyte\t\t*host_colormap;\nextern\tint\t\t\thost_framecount;\t// incremented every frame, never reset\nextern\tdouble\t\trealtime;\t\t\t// not bounded in any way, changed at\n\t\t\t\t\t\t\t\t\t\t// start of every frame, never reset\n\nvoid Host_ClearMemory (void);\nvoid Host_ServerFrame (void);\nvoid Host_InitCommands (void);\nvoid Host_Init (quakeparms_t *parms);\nvoid Host_Shutdown(void);\nvoid Host_Error (char *error, ...);\nvoid Host_EndGame (char *message, ...);\nvoid Host_Frame (float time);\nvoid Host_Quit_f (void);\nvoid Host_ClientCommands (char *fmt, ...);\nvoid Host_ShutdownServer (bool crash);\n\nextern bool\t\tmsg_suppress_1;\t\t// suppresses resolution and cache size console output\n\t\t\t\t\t\t\t\t\t\t//  an fullscreen DIB focus gain/loss\nextern int\t\t\tcurrent_skill;\t\t// skill level for currently loaded level (in case\n\t\t\t\t\t\t\t\t\t\t//  the user changes the cvar while the level is\n\t\t\t\t\t\t\t\t\t\t//  running, this reflects the level actually in use)\n\nextern bool\t\tisDedicated;\n\nextern int\t\t\tminimum_memory;\n\n//\n// chase\n//\nextern\tcvar_t\tchase_active;\n\nvoid Chase_Init (void);\nvoid Chase_Reset (void);\nvoid Chase_Update (void);\n\nvoid DrawQuad_NoTex(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat r, GLfloat g, GLfloat b, GLfloat a);\nvoid DrawQuad(GLfloat x, GLfloat y, GLfloat w, GLfloat h, GLfloat u, GLfloat v, GLfloat uw, GLfloat vh);\n\nvoid GL_SubdivideSurface (msurface_t *fa);\nvoid GL_MakeAliasModelDisplayLists (model_t *m, aliashdr_t *hdr);\nint R_LightPoint (vec3_t p);\nvoid R_DrawBrushModel (entity_t *e);\nvoid RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees );\nvoid R_AnimateLight (void);\nvoid V_CalcBlend (void);\nvoid R_DrawWorld (void);\nvoid R_RenderDlights(void);\nvoid R_DrawParticles (void);\nvoid R_DrawWaterSurfaces (void);\nvoid R_RenderBrushPoly (msurface_t *fa);\nvoid R_InitParticles (void);\nvoid GL_Upload8_EXT (byte *data, int width, int height,  bool mipmap, bool alpha);\nvoid R_ClearParticles (void);\nvoid GL_BuildLightmaps (void);\nvoid EmitWaterPolys (msurface_t *fa);\nvoid EmitSkyPolys (msurface_t *fa);\nvoid EmitBothSkyLayers (msurface_t *fa);\nvoid R_DrawSkyChain (msurface_t *s);\nbool R_CullBox (vec3_t mins, vec3_t maxs);\nvoid R_MarkLights (dlight_t *light, int bit, mnode_t *node);\nvoid R_RotateForEntity (entity_t *e);\nvoid R_StoreEfrags (efrag_t **ppefrag);\nvoid GL_Set2D (void);\nvoid GL_DrawFPS(void);\nvoid GL_DrawBenchmark(void);\nvoid GL_SelectTexture (GLenum target);\n\nextern float *gVertexBuffer;\nextern float *gColorBuffer;\nextern float *gTexCoordBuffer;\n\n// Fragment shaders\n#define MODULATE_WITH_COLOR  0\n#define MODULATE             1\n#define REPLACE              2\n#define MONO_COLOR           4\n#define MODULATE_COLOR_A     5\n#define MODULATE_A           6\n#define RGBA_A               7\n#define REPLACE_A            8\n\n// Vertex shaders\n#define TEXTURE2D            0\n#define TEXTURE2D_WITH_COLOR 1\n#define COLOR                2\n#define VERTEX_ONLY          3\n\n// Shader programs\n#define TEX2D_REPL      0\n#define TEX2D_MODUL     1\n#define TEX2D_MODUL_CLR 2\n#define RGBA_COLOR      3\n#define NO_COLOR        4\n#define TEX2D_REPL_A    5\n#define TEX2D_MODUL_A   6\n#define RGBA_CLR_A      7\n#define FULL_A          8\n\nextern GLuint fs[9];\nextern GLuint vs[4];\nextern GLuint programs[9];\nextern GLint monocolor;\nextern GLint modulcolor[2];\n\nvoid GL_EnableState(GLenum state);\nvoid GL_DisableState(GLenum state);\nvoid GL_DrawPolygon(GLenum prim, int num);\nvoid GL_Color(float r, float g, float b, float a);\nvoid GL_ResetShaders();\nvoid GL_SetCanvas(int type);\n\nextern float sintablef[17];\nextern float costablef[17];\n\n// Mods support\ntypedef struct ModsList{\n\tchar name[256];\n\tstruct ModsList* next;\n} ModsList;\n\n#define CANVAS_DEFAULT     0\n#define CANVAS_CONSOLE     1\n#define CANVAS_MENU        2\n#define CANVAS_SBAR        3\n#define CANVAS_CROSSHAIR   4\n#define CANVAS_TOPRIGHT    5\n\nextern void Log(const char *format, ...);\n"
  },
  {
    "path": "source/r_local.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// r_local.h -- private refresh defs\n\n#ifndef GLQUAKE\n#include \"r_shared.h\"\n\n#define ALIAS_BASE_SIZE_RATIO\t\t(1.0 / 11.0)\n\t\t\t\t\t// normalizing factor so player model works out to about\n\t\t\t\t\t//  1 pixel per triangle\n\n#define BMODEL_FULLY_CLIPPED\t0x10 // value returned by R_BmodelCheckBBox ()\n\t\t\t\t\t\t\t\t\t //  if bbox is trivially rejected\n\n//===========================================================================\n// viewmodel lighting\n\ntypedef struct {\n\tint\t\t\tambientlight;\n\tint\t\t\tshadelight;\n\tfloat\t\t*plightvec;\n} alight_t;\n\n//===========================================================================\n// clipped bmodel edges\n\ntypedef struct bedge_s\n{\n\tmvertex_t\t\t*v[2];\n\tstruct bedge_s\t*pnext;\n} bedge_t;\n\ntypedef struct {\n\tfloat\tfv[3];\t\t// viewspace x, y\n} auxvert_t;\n\n//===========================================================================\n\nextern cvar_t\tr_draworder;\nextern cvar_t\tr_speeds;\nextern cvar_t\tr_timegraph;\nextern cvar_t\tr_graphheight;\nextern cvar_t\tr_clearcolor;\nextern cvar_t\tr_waterwarp;\nextern cvar_t\tr_fullbright;\nextern cvar_t\tr_drawentities;\nextern cvar_t\tr_aliasstats;\nextern cvar_t\tr_dspeeds;\nextern cvar_t\tr_drawflat;\nextern cvar_t\tr_ambient;\nextern cvar_t\tr_reportsurfout;\nextern cvar_t\tr_maxsurfs;\nextern cvar_t\tr_numsurfs;\nextern cvar_t\tr_reportedgeout;\nextern cvar_t\tr_maxedges;\nextern cvar_t\tr_numedges;\n\n#define XCENTERING\t(1.0 / 2.0)\n#define YCENTERING\t(1.0 / 2.0)\n\n#define CLIP_EPSILON\t\t0.001\n\n#define BACKFACE_EPSILON\t0.01\n\n//===========================================================================\n\n#define\tDIST_NOT_SET\t98765\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct clipplane_s\n{\n\tvec3_t\t\tnormal;\n\tfloat\t\tdist;\n\tstruct\t\tclipplane_s\t*next;\n\tbyte\t\tleftedge;\n\tbyte\t\trightedge;\n\tbyte\t\treserved[2];\n} clipplane_t;\n\nextern\tclipplane_t\tview_clipplanes[4];\n\n//=============================================================================\n\nvoid R_RenderWorld (void);\n\n//=============================================================================\n\nextern\tmplane_t\tscreenedge[4];\n\nextern\tvec3_t\tr_origin;\n\nextern\tvec3_t\tr_entorigin;\n\nextern\tfloat\tscreenAspect;\nextern\tfloat\tverticalFieldOfView;\nextern\tfloat\txOrigin, yOrigin;\n\nextern\tint\t\tr_visframecount;\n\n//=============================================================================\n\nextern int\tvstartscan;\n\n\nvoid R_ClearPolyList (void);\nvoid R_DrawPolyList (void);\n\n//\n// current entity info\n//\nextern\tbool\t\tinsubmodel;\n\n\nvoid R_DrawSprite (void);\nvoid R_RenderFace (msurface_t *fa, int clipflags);\nvoid R_RenderPoly (msurface_t *fa, int clipflags);\nvoid R_RenderBmodelFace (bedge_t *pedges, msurface_t *psurf);\nvoid R_TransformPlane (mplane_t *p, float *normal, float *dist);\nvoid R_TransformFrustum (void);\nvoid R_SetSkyFrame (void);\nvoid R_DrawSurfaceBlock16 (void);\nvoid R_DrawSurfaceBlock8 (void);\ntexture_t *R_TextureAnimation (texture_t *base);\n\n#if\tid386\n\nvoid R_DrawSurfaceBlock8_mip0 (void);\nvoid R_DrawSurfaceBlock8_mip1 (void);\nvoid R_DrawSurfaceBlock8_mip2 (void);\nvoid R_DrawSurfaceBlock8_mip3 (void);\n\n#endif\n\nvoid R_GenSkyTile (void *pdest);\nvoid R_GenSkyTile16 (void *pdest);\nvoid R_Surf8Patch (void);\nvoid R_Surf16Patch (void);\nvoid R_DrawSubmodelPolygons (model_t *pmodel, int clipflags);\nvoid R_DrawSolidClippedSubmodelPolygons (model_t *pmodel);\n\nvoid R_AddPolygonEdges (emitpoint_t *pverts, int numverts, int miplevel);\nsurf_t *R_GetSurf (void);\nvoid R_AliasDrawModel (entity_t *e, alight_t *plighting);\nvoid R_BeginEdgeFrame (void);\nvoid R_ScanEdges (void);\nvoid D_DrawSurfaces (void);\nvoid R_InsertNewEdges (edge_t *edgestoadd, edge_t *edgelist);\nvoid R_StepActiveU (edge_t *pedge);\nvoid R_RemoveEdges (edge_t *pedge);\n\nextern void R_Surf8Start (void);\nextern void R_Surf8End (void);\nextern void R_Surf16Start (void);\nextern void R_Surf16End (void);\nextern void R_EdgeCodeStart (void);\nextern void R_EdgeCodeEnd (void);\n\nextern void R_RotateBmodel (void);\n\nextern int\tc_faceclip;\nextern int\tr_polycount;\nextern int\tr_wholepolycount;\n\nextern\tmodel_t\t\t*cl_worldmodel;\n\nextern int\t\t*pfrustum_indexes[4];\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\n#define\tNEAR_CLIP\t0.01\n\nextern int\t\t\tubasestep, errorterm, erroradjustup, erroradjustdown;\nextern int\t\t\tvstartscan;\n\nextern fixed16_t\tsadjust, tadjust;\nextern fixed16_t\tbbextents, bbextentt;\n\n#define MAXBVERTINDEXES\t1000\t// new clipped vertices when clipping bmodels\n\t\t\t\t\t\t\t\t//  to the world BSP\nextern mvertex_t\t*r_ptverts, *r_ptvertsmax;\n\nextern vec3_t\t\t\tsbaseaxis[3], tbaseaxis[3];\nextern float\t\t\tentity_rotation[3][3];\n\nextern int\t\treinit_surfcache;\n\nextern int\t\tr_currentkey;\nextern int\t\tr_currentbkey;\n\ntypedef struct btofpoly_s {\n\tint\t\t\tclipflags;\n\tmsurface_t\t*psurf;\n} btofpoly_t;\n\n#define MAX_BTOFPOLYS\t5000\t// FIXME: tune this\n\nextern int\t\t\tnumbtofpolys;\nextern btofpoly_t\t*pbtofpolys;\n\nvoid\tR_InitTurb (void);\nvoid\tR_ZDrawSubmodelPolys (model_t *clmodel);\n\n//=========================================================\n// Alias models\n//=========================================================\n\n#define MAXALIASVERTS\t\t2000\t// TODO: tune this\n#define ALIAS_Z_CLIP_PLANE\t5\n\nextern int\t\t\t\tnumverts;\nextern int\t\t\t\ta_skinwidth;\nextern int\t\t\t\tnumtriangles;\nextern float\t\t\tleftclip, topclip, rightclip, bottomclip;\nextern int\t\t\t\tr_acliptype;\n\nbool R_AliasCheckBBox (entity_t *e);\n\n//=========================================================\n// turbulence stuff\n\n#define\tAMP\t\t8*0x10000\n#define\tAMP2\t3\n#define\tSPEED\t20\n\n//=========================================================\n// particle stuff\n\nvoid R_DrawParticles (void);\nvoid R_InitParticles (void);\nvoid R_ClearParticles (void);\nvoid R_ReadPointFile_f (void);\nvoid R_SurfacePatch (void);\n\nextern int\t\tr_amodels_drawn;\nextern edge_t\t*auxedges;\nextern int\t\tr_numallocatededges;\nextern edge_t\t*r_edges, *edge_p, *edge_max;\n\nextern\tedge_t\t*newedges[MAXHEIGHT];\nextern\tedge_t\t*removeedges[MAXHEIGHT];\n\nextern\tint\tscreenwidth;\n\n// FIXME: make stack vars when debugging done\nextern\tedge_t\tedge_head;\nextern\tedge_t\tedge_tail;\nextern\tedge_t\tedge_aftertail;\nextern int\t\tr_bmodelactive;\nextern vrect_t\t*pconupdate;\n\nextern float\t\taliasxscale, aliasyscale, aliasxcenter, aliasycenter;\nextern float\t\tr_aliastransition, r_resfudge;\n\nextern int\t\tr_outofsurfaces;\nextern int\t\tr_outofedges;\n\nextern mvertex_t\t*r_pcurrentvertbase;\nextern int\t\t\tr_maxvalidedgeoffset;\n\nvoid R_AliasClipTriangle (mtriangle_t *ptri, finalvert_t *pfinalverts, auxvert_t *pauxverts);\n\nextern float\tr_time1;\nextern float\tdp_time1, dp_time2, db_time1, db_time2, rw_time1, rw_time2;\nextern float\tse_time1, se_time2, de_time1, de_time2, dv_time1, dv_time2;\nextern int\t\tr_frustum_indexes[4*6];\nextern int\t\tr_maxsurfsseen, r_maxedgesseen, r_cnumsurfs;\nextern bool\tr_surfsonstack;\nextern cshift_t\tcshift_water;\nextern bool\tr_dowarpold, r_viewchanged;\n\nextern mleaf_t\t*r_viewleaf, *r_oldviewleaf;\n\nextern vec3_t\tr_emins, r_emaxs;\nextern mnode_t\t*r_pefragtopnode;\nextern int\t\tr_clipflags;\nextern int\t\tr_dlightframecount;\n\nvoid R_StoreEfrags (efrag_t **ppefrag);\nvoid R_TimeRefresh_f (void);\nvoid R_TimeGraph (void);\nvoid R_PrintAliasStats (void);\nvoid R_PrintTimes (void);\nvoid R_PrintDSpeeds (void);\nvoid R_AnimateLight (void);\nint R_LightPoint (vec3_t p);\nvoid R_SetupFrame (void);\nvoid R_cshift_f (void);\nvoid R_EmitEdge (mvertex_t *pv0, mvertex_t *pv1);\nvoid R_ClipEdge (mvertex_t *pv0, mvertex_t *pv1, clipplane_t *clip);\nvoid R_SplitEntityOnNode2 (mnode_t *node);\nvoid R_MarkLights (dlight_t *light, int bit, mnode_t *node);\n\n#endif"
  },
  {
    "path": "source/r_part.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include <vitaGL.h>\n#include \"quakedef.h\"\n#include \"r_local.h\"\n\n#define DEFAULT_NUM_PARTICLES\t1024\t// default max # of particles at one time\n#define ABSOLUTE_MIN_PARTICLES\t512\t\t// no fewer than this no matter what's on the command line\n#define ABSOLUTE_MAX_PARTICLES\t8192\n\nstatic int ramp1[8] = {0x6f, 0x6d, 0x6b, 0x69, 0x67, 0x65, 0x63, 0x61};\nstatic int ramp2[8] = {0x6f, 0x6e, 0x6d, 0x6c, 0x6b, 0x6a, 0x68, 0x66};\nstatic int ramp3[6] = {0x6d, 0x6b, 0x06, 0x05, 0x04, 0x03};\n\nparticle_t\t*active_particles, *free_particles;\n\nparticle_t\t*particles;\nint\t\t\tr_numparticles;\n\nvec3_t\t\t\tr_pright, r_pup, r_ppn;\n\nextern float d_8to32ftable[];\n\n/*\n===============\nR_InitParticles\n===============\n*/\nvoid R_InitParticles (void)\n{\n\tint\t\ti;\n\n\tif ((i = COM_CheckParm (\"-particles\"))  && i+1 < com_argc)\n\t{\n\t\tr_numparticles = (int)(atoi(com_argv[i+1]));\n\t\tif (r_numparticles < ABSOLUTE_MIN_PARTICLES) r_numparticles = ABSOLUTE_MIN_PARTICLES;\n\t\telse if (r_numparticles > ABSOLUTE_MAX_PARTICLES) r_numparticles = ABSOLUTE_MAX_PARTICLES;\n\t}\n\telse\n\t{\n\t\tr_numparticles = DEFAULT_NUM_PARTICLES;\n\t}\n\n\tparticles = (particle_t *)\n\t\t\tHunk_AllocName (r_numparticles * sizeof(particle_t), \"particles\");\n}\n\n\n/*\n===============\nR_EntityParticles\n===============\n*/\n\n#define NUMVERTEXNORMALS\t162\nextern\tfloat\tr_avertexnormals[NUMVERTEXNORMALS][3];\nvec3_t\tavelocities[NUMVERTEXNORMALS];\nfloat\tbeamlength = 16;\nvec3_t\tavelocity = {23, 7, 3};\nfloat\tpartstep = 0.01;\nfloat\ttimescale = 0.01;\n\nvoid R_EntityParticles (entity_t *ent)\n{\n\tint\t\t\ti;\n\tparticle_t\t*p;\n\tfloat\t\tangle;\n\tfloat\t\tsr, sp, sy, cr, cp, cy;\n\tvec3_t\t\tforward;\n\tfloat\t\tdist;\n\t\n\tdist = 64;\n\n\tif (!avelocities[0][0])\n\t{\n\t\tfor (i = 0 ; i < NUMVERTEXNORMALS; i++)\n\t\t{\n\t\t\tavelocities[i][0] = (rand() & 255) * 0.01;\n\t\t\tavelocities[i][1] = (rand() & 255) * 0.01;\n\t\t\tavelocities[i][2] = (rand() & 255) * 0.01;\n\t\t}\n\t}\t\n\n\n\tfor (i=0 ; i<NUMVERTEXNORMALS ; i++)\n\t{\n\t\t\n\t\tv4sf src = {\n\t\t\tcl.time * avelocities[i][0],\n\t\t\tcl.time * avelocities[i][1],\n\t\t\tcl.time * avelocities[i][2],\n\t\t\t0\n\t\t};\n\t\t\n\t\tv4sf sins, coss;\n\t\tsincos_ps(src, &sins, &coss);\n\t\t\n\t\tsy = sins[0];\n\t\tcy = coss[0];\n\t\tsp = sins[1];\n\t\tcp = coss[2];\n\t\tsr = sins[2];\n\t\tcr = coss[2];\n\t\n\t\tforward[0] = cp*cy;\n\t\tforward[1] = cp*sy;\n\t\tforward[2] = -sp;\n\n\t\tif (!free_particles)\n\t\t\treturn;\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->die = cl.time + 0.01;\n\t\tp->color = 0x6f;\n\t\tp->type = pt_explode;\n\t\t\n\t\tp->org[0] = ent->origin[0] + r_avertexnormals[i][0]*dist + forward[0]*beamlength;\t\t\t\n\t\tp->org[1] = ent->origin[1] + r_avertexnormals[i][1]*dist + forward[1]*beamlength;\t\t\t\n\t\tp->org[2] = ent->origin[2] + r_avertexnormals[i][2]*dist + forward[2]*beamlength;\t\t\t\n\t}\n}\n\n\n/*\n===============\nR_ClearParticles\n===============\n*/\nvoid R_ClearParticles (void)\n{\n\tint\t\ti;\n\t\n\tfree_particles = &particles[0];\n\tactive_particles = NULL;\n\n\tfor (i=0 ;i<r_numparticles ; i++)\n\t\tparticles[i].next = &particles[i+1];\n\tparticles[r_numparticles-1].next = NULL;\n}\n\n/*\n===============\nR_ReadPointFile_f\n===============\n*/\nvoid R_ReadPointFile_f (void)\n{\n\tFILE\t*f;\n\tvec3_t\torg;\n\tint\t\tr;\n\tint\t\tc;\n\tparticle_t\t*p;\n\tchar\tname[MAX_OSPATH];\n\t\n\tsnprintf(name, sizeof(name), \"maps/%s.pts\", sv.name);\n\n\tCOM_FOpenFile (name, &f, NULL);\n\tif (!f)\n\t{\n\t\tCon_Printf (\"couldn't open %s\\n\", name);\n\t\treturn;\n\t}\n\t\n\tCon_Printf (\"Reading %s...\\n\", name);\n\tc = 0;\n\tfor ( ;; )\n\t{\n\t\tr = fscanf (f, \"%f %f %f\\n\", &org[0], &org[1], &org[2]);\n\t\tif (r != 3)\n\t\t\tbreak;\n\t\tc++;\n\t\t\n\t\tif (!free_particles)\n\t\t{\n\t\t\tCon_Printf (\"Not enough free particles\\n\");\n\t\t\tbreak;\n\t\t}\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\t\t\n\t\tp->die = 99999;\n\t\tp->color = (-c)&15;\n\t\tp->type = pt_static;\n\t\tVectorCopy (vec3_origin, p->vel);\n\t\tVectorCopy (org, p->org);\n\t}\n\n\tfclose (f);\n\tCon_Printf (\"%i points read\\n\", c);\n}\n\n/*\n===============\nR_ParseParticleEffect\n\nParse an effect out of the server message\n===============\n*/\nvoid R_ParseParticleEffect (void)\n{\n\tvec3_t\t\torg, dir;\n\tint\t\t\ti, count, msgcount, color;\n\t\n\tfor (i=0 ; i<3 ; i++)\n\t\torg[i] = MSG_ReadCoord ();\n\tfor (i=0 ; i<3 ; i++)\n\t\tdir[i] = MSG_ReadChar () * (1.0/16);\n\tmsgcount = MSG_ReadByte ();\n\tcolor = MSG_ReadByte ();\n\nif (msgcount == 255)\n\tcount = 1024;\nelse\n\tcount = msgcount;\n\t\n\tR_RunParticleEffect (org, dir, color, count);\n}\n\t\n/*\n===============\nR_ParticleExplosion\n\n===============\n*/\nvoid R_ParticleExplosion (vec3_t org)\n{\n\tint\t\t\ti, j;\n\tparticle_t\t*p;\n\t\n\tfor (i=0 ; i<1024 ; i++)\n\t{\n\t\tif (!free_particles)\n\t\t\treturn;\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\t\t\n\t\tp->color = ramp1[0];\n\t\tp->ramp = rand()&3;\n\t\tif (i & 1)\n\t\t{\n\t\t\tp->type = pt_explode;\n\t\t\tp->die = cl.time + (8 - p->ramp) / 10.0f;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tp->type = pt_explode2;\n\t\t\tp->die = cl.time + (8 - p->ramp) / 15.0f;\n\t\t}\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tp->org[j] = org[j] + ((rand()%32)-16);\n\t\t\tp->vel[j] = (rand()%512)-256;\n\t\t}\n\t}\n}\n\n/*\n===============\nR_ParticleExplosion2\n\n===============\n*/\nvoid R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength)\n{\n\tint\t\t\ti, j;\n\tparticle_t\t*p;\n\tint\t\t\tcolorMod = 0;\n\n\tfor (i=0; i<512; i++)\n\t{\n\t\tif (!free_particles)\n\t\t\treturn;\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->die = cl.time + 0.3;\n\t\tp->color = colorStart + (colorMod % colorLength);\n\t\tcolorMod++;\n\n\t\tp->type = pt_blob;\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t{\n\t\t\tp->org[j] = org[j] + ((rand()%32)-16);\n\t\t\tp->vel[j] = (rand()%512)-256;\n\t\t}\n\t}\n}\n\n/*\n===============\nR_BlobExplosion\n\n===============\n*/\nvoid R_BlobExplosion (vec3_t org)\n{\n\tint\t\t\ti, j;\n\tparticle_t\t*p;\n\t\n\tfor (i=0 ; i<1024 ; i++)\n\t{\n\t\tif (!free_particles)\n\t\t\treturn;\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->die = cl.time + 1 + (rand()&8)*0.05;\n\n\t\tif (i & 1)\n\t\t{\n\t\t\tp->type = pt_blob;\n\t\t\tp->color = 66 + rand()%6;\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tp->org[j] = org[j] + ((rand()%32)-16);\n\t\t\t\tp->vel[j] = (rand()%512)-256;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tp->type = pt_blob2;\n\t\t\tp->color = 150 + rand()%6;\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tp->org[j] = org[j] + ((rand()%32)-16);\n\t\t\t\tp->vel[j] = (rand()%512)-256;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n===============\nR_RunParticleEffect\n\n===============\n*/\nvoid R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count)\n{\n\tint\t\t\ti, j;\n\tparticle_t\t*p;\n\t\n\tfor (i=0 ; i<count ; i++)\n\t{\n\t\tif (!free_particles)\n\t\t\treturn;\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\tif (count == 1024)\n\t\t{\t// rocket explosion\n\t\t\tp->color = ramp1[0];\n\t\t\tp->ramp = rand()&3;\n\t\t\tif (i & 1)\n\t\t\t{\n\t\t\t\tp->type = pt_explode;\n\t\t\t\tp->die = cl.time + (8 - p->ramp) / 10.0f;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tp->type = pt_explode2;\n\t\t\t\tp->die = cl.time + (8 - p->ramp) / 15.0f;\n\t\t\t}\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tp->org[j] = org[j] + ((rand()%32)-16);\n\t\t\t\tp->vel[j] = (rand()%512)-256;\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n\t\t\tp->die = cl.time + 0.1*(rand()%5);\n\t\t\tp->color = (color&~7) + (rand()&7);\n\t\t\tp->type = pt_slowgrav;\n\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t{\n\t\t\t\tp->org[j] = org[j] + ((rand()&15)-8);\n\t\t\t\tp->vel[j] = dir[j]*15;// + (rand()%300)-150;\n\t\t\t}\n\t\t}\n\t}\n}\n\n\n/*\n===============\nR_LavaSplash\n\n===============\n*/\nvoid R_LavaSplash (vec3_t org)\n{\n\tint\t\t\ti, j, k;\n\tparticle_t\t*p;\n\tfloat\t\tvel;\n\tvec3_t\t\tdir;\n\n\tfor (i=-16 ; i<16 ; i++)\n\t\tfor (j=-16 ; j<16 ; j++)\n\t\t\tfor (k=0 ; k<1 ; k++)\n\t\t\t{\n\t\t\t\tif (!free_particles)\n\t\t\t\t\treturn;\n\t\t\t\tp = free_particles;\n\t\t\t\tfree_particles = p->next;\n\t\t\t\tp->next = active_particles;\n\t\t\t\tactive_particles = p;\n\t\t\n\t\t\t\tp->die = cl.time + 2 + (rand()&31) * 0.02;\n\t\t\t\tp->color = 224 + (rand()&7);\n\t\t\t\tp->type = pt_slowgrav;\n\t\t\t\t\n\t\t\t\tdir[0] = j*8 + (rand()&7);\n\t\t\t\tdir[1] = i*8 + (rand()&7);\n\t\t\t\tdir[2] = 256;\n\t\n\t\t\t\tp->org[0] = org[0] + dir[0];\n\t\t\t\tp->org[1] = org[1] + dir[1];\n\t\t\t\tp->org[2] = org[2] + (rand()&63);\n\t\n\t\t\t\tVectorNormalize (dir);\t\t\t\t\t\t\n\t\t\t\tvel = 50 + (rand()&63);\n\t\t\t\tVectorScale (dir, vel, p->vel);\n\t\t\t}\n}\n\n/*\n===============\nR_TeleportSplash\n\n===============\n*/\nvoid R_TeleportSplash (vec3_t org)\n{\n\tint\t\t\ti, j, k;\n\tparticle_t\t*p;\n\tfloat\t\tvel;\n\tvec3_t\t\tdir;\n\n\tfor (i=-16 ; i<16 ; i+=4)\n\t\tfor (j=-16 ; j<16 ; j+=4)\n\t\t\tfor (k=-24 ; k<32 ; k+=4)\n\t\t\t{\n\t\t\t\tif (!free_particles)\n\t\t\t\t\treturn;\n\t\t\t\tp = free_particles;\n\t\t\t\tfree_particles = p->next;\n\t\t\t\tp->next = active_particles;\n\t\t\t\tactive_particles = p;\n\t\t\n\t\t\t\tp->die = cl.time + 0.2 + (rand()&7) * 0.02;\n\t\t\t\tp->color = 7 + (rand()&7);\n\t\t\t\tp->type = pt_slowgrav;\n\t\t\t\t\n\t\t\t\tdir[0] = j*8;\n\t\t\t\tdir[1] = i*8;\n\t\t\t\tdir[2] = k*8;\n\t\n\t\t\t\tp->org[0] = org[0] + i + (rand()&3);\n\t\t\t\tp->org[1] = org[1] + j + (rand()&3);\n\t\t\t\tp->org[2] = org[2] + k + (rand()&3);\n\t\n\t\t\t\tVectorNormalize (dir);\t\t\t\t\t\t\n\t\t\t\tvel = 50 + (rand()&63);\n\t\t\t\tVectorScale (dir, vel, p->vel);\n\t\t\t}\n}\n\n/*\n===============\nR_RocketTrail\n\nFIXME -- rename function and use #defined types instead of numbers\n===============\n*/\nvoid R_RocketTrail (vec3_t start, vec3_t end, int type)\n{\n\tvec3_t\t\tvec;\n\tfloat\t\tlen;\n\tint\t\t\tj;\n\tparticle_t\t*p;\n\tint\t\t\tdec;\n\tstatic int\ttracercount;\n\n\tVectorSubtract (end, start, vec);\n\tlen = VectorNormalize (vec);\n\tif (type < 128)\n\t\tdec = 3;\n\telse\n\t{\n\t\tdec = 1;\n\t\ttype -= 128;\n\t}\n\n\twhile (len > 0)\n\t{\n\t\tlen -= dec;\n\n\t\tif (!free_particles)\n\t\t\treturn;\n\t\tp = free_particles;\n\t\tfree_particles = p->next;\n\t\tp->next = active_particles;\n\t\tactive_particles = p;\n\t\t\n\t\tVectorCopy (vec3_origin, p->vel);\n\t\tp->die = cl.time + 2;\n\t\t\n\t\tswitch (type)\n\t\t{\n\t\t\tcase 0:\t// rocket trail\n\t\t\t\tp->ramp = (rand()&3);\n\t\t\t\tif (p->ramp >= 6) p->ramp -= 6;\n\t\t\t\tp->die = cl.time + (6 - p->ramp) / 5.0f;\n\t\t\t\tp->color = ramp3[(int)p->ramp];\n\t\t\t\tp->type = pt_fire;\n\t\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t\t\tp->org[j] = start[j] + ((rand()%6)-3);\n\t\t\t\tbreak;\n\n\t\t\tcase 1:\t// smoke trail\n\t\t\t\tp->ramp = (rand()&2) + 2;\n\t\t\t\tp->die = cl.time + (6 - p->ramp) / 5.0f;\n\t\t\t\tp->color = ramp3[(int)p->ramp];\n\t\t\t\tp->type = pt_fire;\n\t\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t\t\tp->org[j] = start[j] + ((rand()%6)-3);\n\t\t\t\tbreak;\n\n\t\t\tcase 2:\t// blood\n\t\t\t\tp->type = pt_grav;\n\t\t\t\tp->color = 67 + (rand()&3);\n\t\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t\t\tp->org[j] = start[j] + ((rand()%6)-3);\n\t\t\t\tbreak;\n\n\t\t\tcase 3:\n\t\t\tcase 5:\t// tracer\n\t\t\t\tp->die = cl.time + 0.5;\n\t\t\t\tp->type = pt_static;\n\t\t\t\tif (type == 3)\n\t\t\t\t\tp->color = 52 + ((tracercount&4)<<1);\n\t\t\t\telse\n\t\t\t\t\tp->color = 230 + ((tracercount&4)<<1);\n\t\t\t\n\t\t\t\ttracercount++;\n\n\t\t\t\tVectorCopy (start, p->org);\n\t\t\t\tif (tracercount & 1)\n\t\t\t\t{\n\t\t\t\t\tp->vel[0] = 30*vec[1];\n\t\t\t\t\tp->vel[1] = 30*-vec[0];\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tp->vel[0] = 30*-vec[1];\n\t\t\t\t\tp->vel[1] = 30*vec[0];\n\t\t\t\t}\n\t\t\t\tbreak;\n\n\t\t\tcase 4:\t// slight blood\n\t\t\t\tp->type = pt_grav;\n\t\t\t\tp->color = 67 + (rand()&3);\n\t\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t\t\tp->org[j] = start[j] + ((rand()%6)-3);\n\t\t\t\tlen -= 3;\n\t\t\t\tbreak;\n\n\t\t\tcase 6:\t// voor trail\n\t\t\t\tp->color = 9*16 + 8 + (rand()&3);\n\t\t\t\tp->type = pt_static;\n\t\t\t\tp->die = cl.time + 0.3;\n\t\t\t\tfor (j=0 ; j<3 ; j++)\n\t\t\t\t\tp->org[j] = start[j] + ((rand()&15)-8);\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\n\t\tVectorAdd (start, vec, start);\n\t}\n}\n\n/*\n===============\nCL_RunParticles -- johnfitz -- all the particle behavior, separated from R_DrawParticles\n===============\n*/\nvoid CL_RunParticles (void)\n{\n\tparticle_t\t\t*p, *kill;\n\tint\t\t\t\ti;\n\tfloat\t\t\ttime1, time2, time3, dvel, frametime, scale, grav;\n\textern\tcvar_t\tsv_gravity;\n\n\tframetime = cl.time - cl.oldtime;\n\ttime3 = frametime * 15;\n\ttime2 = frametime * 10;\n\ttime1 = frametime * 5;\n\tgrav = frametime * sv_gravity.value * 0.05;\n\tdvel = 4*frametime;\n\n\tfor ( ;; )\n\t{\n\t\tkill = active_particles;\n\t\tif (kill && kill->die < cl.time)\n\t\t{\n\t\t\tactive_particles = kill->next;\n\t\t\tkill->next = free_particles;\n\t\t\tfree_particles = kill;\n\t\t\tcontinue;\n\t\t}\n\t\tbreak;\n\t}\n\n\tfor (p=active_particles ; p ; p=p->next)\n\t{\n\t\tfor ( ;; )\n\t\t{\n\t\t\tkill = p->next;\n\t\t\tif (kill && kill->die < cl.time)\n\t\t\t{\n\t\t\t\tp->next = kill->next;\n\t\t\t\tkill->next = free_particles;\n\t\t\t\tfree_particles = kill;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tbreak;\n\t\t}\n\n\t\tp->org[0] += p->vel[0]*frametime;\n\t\tp->org[1] += p->vel[1]*frametime;\n\t\tp->org[2] += p->vel[2]*frametime;\n\n\t\tswitch (p->type)\n\t\t{\n\t\tcase pt_static:\n\t\t\tbreak;\n\t\tcase pt_fire:\n\t\t\tp->ramp += time1;\n\t\t\tif (p->ramp >= 6)\n\t\t\t\tp->die = cl.time - 0.01f;\n\t\t\telse\n\t\t\t\tp->color = ramp3[(int)p->ramp];\n\t\t\tp->vel[2] += grav;\n\t\t\tbreak;\n\n\t\tcase pt_explode:\n\t\t\tp->ramp += time2;\n\t\t\tif (p->ramp >=8)\n\t\t\t\tp->die = cl.time - 0.01f;\n\t\t\telse\n\t\t\t\tp->color = ramp1[(int)p->ramp];\n\t\t\tfor (i=0 ; i<3 ; i++)\n\t\t\t\tp->vel[i] += p->vel[i]*dvel;\n\t\t\tp->vel[2] -= grav;\n\t\t\tbreak;\n\n\t\tcase pt_explode2:\n\t\t\tp->ramp += time3;\n\t\t\tif (p->ramp >=8)\n\t\t\t\tp->die = cl.time - 0.01f;\n\t\t\telse\n\t\t\t\tp->color = ramp2[(int)p->ramp];\n\t\t\tfor (i=0 ; i<3 ; i++)\n\t\t\t\tp->vel[i] -= p->vel[i]*frametime;\n\t\t\tp->vel[2] -= grav;\n\t\t\tbreak;\n\n\t\tcase pt_blob:\n\t\t\tfor (i=0 ; i<3 ; i++)\n\t\t\t\tp->vel[i] += p->vel[i]*dvel;\n\t\t\tp->vel[2] -= grav;\n\t\t\tbreak;\n\n\t\tcase pt_blob2:\n\t\t\tfor (i=0 ; i<2 ; i++)\n\t\t\t\tp->vel[i] -= p->vel[i]*dvel;\n\t\t\tp->vel[2] -= grav;\n\t\t\tbreak;\n\n\t\tcase pt_grav:\n\t\tcase pt_slowgrav:\n\t\t\tp->vel[2] -= grav;\n\t\t\tbreak;\n\t\t}\n\t}\n}\n\n/*\n===============\nR_DrawParticles\n===============\n*/\nextern\tcvar_t\tsv_gravity;\n\nvoid R_DrawParticles (void)\n{\n\tparticle_t\t\t*p, *kill;\n\tvec3_t\t\t\tup, right, p_up, p_right, p_upright; //johnfitz -- p_ vectors\n\tGLubyte\t\tcolor[4], *c; //johnfitz -- particle transparency\n\tfloat\t\t\talpha; //johnfitz -- particle transparency\n\tfloat\t\t\tgrav;\n\tint\t\t\t\ti;\n\tfloat\t\t\ttime2, time3;\n\tfloat\t\t\ttime1;\n\tfloat\t\t\tdvel;\n\tfloat\t\t\tframetime;\n\tfloat*\t\t\tpPos = gVertexBuffer;\n\tfloat*\t\t\tpColor = gColorBuffer;\n\tfloat*\t\t\tpUV = gTexCoordBuffer;\n\tfloat\t\t\tcolors[3];\n\t\n\tfloat\t\t\tscale;\n\t\n    GL_Bind(particletexture);\n\t\n\t\n    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\n    glEnable (GL_BLEND);\n\tGL_EnableState(GL_MODULATE);\n\tglDepthMask (GL_FALSE); //johnfitz -- fix for particle z-buffer bug\n\tGL_EnableState(GL_COLOR_ARRAY);\n\t\n\t//->glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);\n\n\tVectorScale (vup, 1.50, up);\n\tVectorScale (vright, 1.50, right);\n\t\n\tint num_vertices = 0;\n\tfor (p=active_particles ; p ; p=p->next)\n\t{\n\t\tnum_vertices += 3;\n\n\t\t// hack a scale up to keep particles from disapearing\n\t\tscale = (p->org[0] - r_origin[0])*vpn[0] + (p->org[1] - r_origin[1])*vpn[1]\n\t\t\t+ (p->org[2] - r_origin[2])*vpn[2];\n\t\tif (scale < 20)\n\t\t\tscale = 1.08f; //johnfitz -- added .08 to be consistent\n\t\telse\n\t\t\tscale = 1 + scale * 0.004;\n\t\t\n\t\tscale *= 1.27;\n\t\t\n\t\tc = (GLubyte *) &d_8to24table[(int)p->color];\n\t\tcolors[0] = ((float)(c[0])) / 255.0f;\n\t\tcolors[1] = ((float)(c[1])) / 255.0f;\n\t\tcolors[2] = ((float)(c[2])) / 255.0f;\n\t\t*gColorBuffer++ = colors[0];\n\t\t*gColorBuffer++ = colors[1];\n\t\t*gColorBuffer++ = colors[2];\n\t\t*gColorBuffer++ = 1.0f;\n\t\t*gTexCoordBuffer++ = 0.0f;\n\t\t*gTexCoordBuffer++ = 0.0f;\n\t\t*gVertexBuffer++ = p->org[0];\n\t\t*gVertexBuffer++ = p->org[1];\n\t\t*gVertexBuffer++ = p->org[2];\n\n\t\t*gColorBuffer++ = colors[0];\n\t\t*gColorBuffer++ = colors[1];\n\t\t*gColorBuffer++ = colors[2];\n\t\t*gColorBuffer++ = 1.0f;\n\t\t*gTexCoordBuffer++ = 1.0f;\n\t\t*gTexCoordBuffer++ = 0.0f;\n\t\tVectorMA (p->org, scale, up, p_up);\n\t\t*gVertexBuffer++ = (p_up[0]);\n\t\t*gVertexBuffer++ = (p_up[1]);\n\t\t*gVertexBuffer++ = (p_up[2]);\n\n\t\t*gColorBuffer++ = colors[0];\n\t\t*gColorBuffer++ = colors[1];\n\t\t*gColorBuffer++ = colors[2];\n\t\t*gColorBuffer++ = 1.0f;\n\t\t*gTexCoordBuffer++ = 0.0;\n\t\t*gTexCoordBuffer++ = 1.0;\n\t\tVectorMA (p->org, scale, right, p_right);\n\t\t*gVertexBuffer++ = (p_right[0]);\n\t\t*gVertexBuffer++ = (p_right[1]);\n\t\t*gVertexBuffer++ = (p_right[2]);\n\t}\n\n\tvglVertexAttribPointerMapped(0, pPos);\n\tvglVertexAttribPointerMapped(1, pUV);\n\tvglVertexAttribPointerMapped(2, pColor);\n\tGL_DrawPolygon(GL_TRIANGLES, num_vertices);\n\tGL_DisableState(GL_COLOR_ARRAY);\n\t//->glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);\n\tglDepthMask (GL_TRUE);\n\tglDisable (GL_BLEND);\n\tGL_EnableState(GL_REPLACE);\n\tGL_Color(1,1,1,1);\n}\n\n"
  },
  {
    "path": "source/r_shared.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n#ifndef GLQUAKE\n// r_shared.h: general refresh-related stuff shared between the refresh and the\n// driver\n\n// FIXME: clean up and move into d_iface.h\n\n#ifndef _R_SHARED_H_\n#define _R_SHARED_H_\n\n#define\tMAXVERTS\t16\t\t\t\t\t// max points in a surface polygon\n#define MAXWORKINGVERTS\t(MAXVERTS+4)\t// max points in an intermediate\n\t\t\t\t\t\t\t\t\t\t//  polygon (while processing)\n// !!! if this is changed, it must be changed in d_ifacea.h too !!!\n#define\tMAXHEIGHT\t\t1024\n#define\tMAXWIDTH\t\t1280\n#define MAXDIMENSION\t((MAXHEIGHT > MAXWIDTH) ? MAXHEIGHT : MAXWIDTH)\n\n#define SIN_BUFFER_SIZE\t(MAXDIMENSION+CYCLE)\n\n#define INFINITE_DISTANCE\t0x10000\t\t// distance that's always guaranteed to\n\t\t\t\t\t\t\t\t\t\t//  be farther away than anything in\n\t\t\t\t\t\t\t\t\t\t//  the scene\n\n//===================================================================\n\nextern void\tR_DrawLine (polyvert_t *polyvert0, polyvert_t *polyvert1);\n\nextern int\t\tcachewidth;\nextern pixel_t\t*cacheblock;\nextern int\t\tscreenwidth;\n\nextern\tfloat\tpixelAspect;\n\nextern int\t\tr_drawnpolycount;\n\nextern cvar_t\tr_clearcolor;\n\nextern int\tsintable[SIN_BUFFER_SIZE];\nextern int\tintsintable[SIN_BUFFER_SIZE];\n\nextern\tvec3_t\tvup, base_vup;\nextern\tvec3_t\tvpn, base_vpn;\nextern\tvec3_t\tvright, base_vright;\nextern\tentity_t\t\t*currententity;\n\n#define NUMSTACKEDGES\t\t2400\n#define\tMINEDGES\t\t\tNUMSTACKEDGES\n#define NUMSTACKSURFACES\t800\n#define MINSURFACES\t\t\tNUMSTACKSURFACES\n#define\tMAXSPANS\t\t\t3000\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct espan_s\n{\n\tint\t\t\t\tu, v, count;\n\tstruct espan_s\t*pnext;\n} espan_t;\n\n// FIXME: compress, make a union if that will help\n// insubmodel is only 1, flags is fewer than 32, spanstate could be a byte\ntypedef struct surf_s\n{\n\tstruct surf_s\t*next;\t\t\t// active surface stack in r_edge.c\n\tstruct surf_s\t*prev;\t\t\t// used in r_edge.c for active surf stack\n\tstruct espan_s\t*spans;\t\t\t// pointer to linked list of spans to draw\n\tint\t\t\tkey;\t\t\t\t// sorting key (BSP order)\n\tint\t\t\tlast_u;\t\t\t\t// set during tracing\n\tint\t\t\tspanstate;\t\t\t// 0 = not in span\n\t\t\t\t\t\t\t\t\t// 1 = in span\n\t\t\t\t\t\t\t\t\t// -1 = in inverted span (end before\n\t\t\t\t\t\t\t\t\t//  start)\n\tint\t\t\tflags;\t\t\t\t// currentface flags\n\tvoid\t\t*data;\t\t\t\t// associated data like msurface_t\n\tentity_t\t*entity;\n\tfloat\t\tnearzi;\t\t\t\t// nearest 1/z on surface, for mipmapping\n\tbool\tinsubmodel;\n\tfloat\t\td_ziorigin, d_zistepu, d_zistepv;\n\n\tint\t\t\tpad[2];\t\t\t\t// to 64 bytes\n} surf_t;\n\nextern\tsurf_t\t*surfaces, *surface_p, *surf_max;\n\n// surfaces are generated in back to front order by the bsp, so if a surf\n// pointer is greater than another one, it should be drawn in front\n// surfaces[1] is the background, and is used as the active surface stack.\n// surfaces[0] is a dummy, because index 0 is used to indicate no surface\n//  attached to an edge_t\n\n//===================================================================\n\nextern vec3_t\tsxformaxis[4];\t// s axis transformed into viewspace\nextern vec3_t\ttxformaxis[4];\t// t axis transformed into viewspac\n\nextern vec3_t\tmodelorg, base_modelorg;\n\nextern\tfloat\txcenter, ycenter;\nextern\tfloat\txscale, yscale;\nextern\tfloat\txscaleinv, yscaleinv;\nextern\tfloat\txscaleshrink, yscaleshrink;\n\nextern\tint d_lightstylevalue[256]; // 8.8 frac of base light value\n\nextern void TransformVector (vec3_t in, vec3_t out);\nextern void SetUpForLineScan(fixed8_t startvertu, fixed8_t startvertv,\n\tfixed8_t endvertu, fixed8_t endvertv);\n\nextern int\tr_skymade;\nextern void R_MakeSky (void);\n\nextern int\tubasestep, errorterm, erroradjustup, erroradjustdown;\n\n// flags in finalvert_t.flags\n#define ALIAS_LEFT_CLIP\t\t\t\t0x0001\n#define ALIAS_TOP_CLIP\t\t\t\t0x0002\n#define ALIAS_RIGHT_CLIP\t\t\t0x0004\n#define ALIAS_BOTTOM_CLIP\t\t\t0x0008\n#define ALIAS_Z_CLIP\t\t\t\t0x0010\n// !!! if this is changed, it must be changed in d_ifacea.h too !!!\n#define ALIAS_ONSEAM\t\t\t\t0x0020\t// also defined in modelgen.h;\n\t\t\t\t\t\t\t\t\t\t\t//  must be kept in sync\n#define ALIAS_XY_CLIP_MASK\t\t\t0x000F\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct edge_s\n{\n\tfixed16_t\t\tu;\n\tfixed16_t\t\tu_step;\n\tstruct edge_s\t*prev, *next;\n\tunsigned short\tsurfs[2];\n\tstruct edge_s\t*nextremove;\n\tfloat\t\t\tnearzi;\n\tmedge_t\t\t\t*owner;\n} edge_t;\n\n#endif\t// _R_SHARED_H_\n\n#endif\t// GLQUAKE\n"
  },
  {
    "path": "source/render.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// refresh.h -- public interface to refresh functions\n\n#define\tMAXCLIPPLANES\t11\n\n#define\tTOP_RANGE\t\t16\t\t\t// soldier uniform colors\n#define\tBOTTOM_RANGE\t96\n\n//=============================================================================\n\ntypedef struct efrag_s\n{\n\tstruct mleaf_s\t\t*leaf;\n\tstruct efrag_s\t\t*leafnext;\n\tstruct entity_s\t\t*entity;\n\tstruct efrag_s\t\t*entnext;\n} efrag_t;\n\n\ntypedef struct entity_s\n{\n\tbool\t\t\t\tforcelink;\t\t// model changed\n\n\tint\t\t\t\t\t\tupdate_type;\n\n\tentity_state_t\t\t\tbaseline;\t\t// to fill in defaults in updates\n\n\tdouble\t\t\t\t\tmsgtime;\t\t// time of last update\n\tvec3_t\t\t\t\t\tmsg_origins[2];\t// last two updates (0 is newest)\t\n\tvec3_t\t\t\t\t\torigin;\n\tvec3_t\t\t\t\t\tmsg_angles[2];\t// last two updates (0 is newest)\n\tvec3_t\t\t\t\t\tangles;\t\n\tstruct model_s\t\t\t*model;\t\t\t// NULL = no model\n\tstruct efrag_s\t\t\t*efrag;\t\t\t// linked list of efrags\n\tint\t\t\t\t\t\tframe;\n\tfloat\t\t\t\t\tsyncbase;\t\t// for client-side animations\n\tbyte\t\t\t\t\t*colormap;\n\tint\t\t\t\t\t\teffects;\t\t// light, particals, etc\n\tint\t\t\t\t\t\tskinnum;\t\t// for Alias models\n\tint\t\t\t\t\t\tvisframe;\t\t// last frame this entity was\n\t\t\t\t\t\t\t\t\t\t\t//  found in an active leaf\n\t\t\t\t\t\t\t\t\t\t\t\n\tint\t\t\t\t\t\tdlightframe;\t// dynamic lighting\n\tint\t\t\t\t\t\tdlightbits;\n\t\n// FIXME: could turn these into a union\n\tint\t\t\t\t\t\ttrivial_accept;\n\tstruct mnode_s\t\t\t*topnode;\t\t// for bmodels, first world node\n\t\t\t\t\t\t\t\t\t\t\t//  that splits bmodel, or NULL if\n\t\t\t\t\t\t\t\t\t\t\t//  not split\n\t\t\t\t\t\t\t\t\t\t\t\n\t// fenix@io.com: model animation interpolation\n\tfloat                   frame_start_time;\n\tfloat                   frame_interval;\n\tint                     pose1; \n\tint                     pose2;\n\t\n\t// fenix@io.com: model transform interpolation\n\tfloat                   translate_start_time;\n\tvec3_t                  origin1;\n\tvec3_t                  origin2;\n\n\tfloat                   rotate_start_time;\n\tvec3_t                  angles1;\n\tvec3_t                  angles2;\n\t\n\tint                     modelflags;\n\t\n\tfloat                   alpha;\n} entity_t;\n\n// !!! if this is changed, it must be changed in asm_draw.h too !!!\ntypedef struct\n{\n\tvrect_t\t\tvrect;\t\t\t\t// subwindow in video for refresh\n\t\t\t\t\t\t\t\t\t// FIXME: not need vrect next field here?\n\tvrect_t\t\taliasvrect;\t\t\t// scaled Alias version\n\tint\t\t\tvrectright, vrectbottom;\t// right & bottom screen coords\n\tint\t\t\taliasvrectright, aliasvrectbottom;\t// scaled Alias versions\n\tfloat\t\tvrectrightedge;\t\t\t// rightmost right edge we care about,\n\t\t\t\t\t\t\t\t\t\t//  for use in edge list\n\tfloat\t\tfvrectx, fvrecty;\t\t// for floating-point compares\n\tfloat\t\tfvrectx_adj, fvrecty_adj; // left and top edges, for clamping\n\tint\t\t\tvrect_x_adj_shift20;\t// (vrect.x + 0.5 - epsilon) << 20\n\tint\t\t\tvrectright_adj_shift20;\t// (vrectright + 0.5 - epsilon) << 20\n\tfloat\t\tfvrectright_adj, fvrectbottom_adj;\n\t\t\t\t\t\t\t\t\t\t// right and bottom edges, for clamping\n\tfloat\t\tfvrectright;\t\t\t// rightmost edge, for Alias clamping\n\tfloat\t\tfvrectbottom;\t\t\t// bottommost edge, for Alias clamping\n\tfloat\t\thorizontalFieldOfView;\t// at Z = 1.0, this many X is visible \n\t\t\t\t\t\t\t\t\t\t// 2.0 = 90 degrees\n\tfloat\t\txOrigin;\t\t\t// should probably always be 0.5\n\tfloat\t\tyOrigin;\t\t\t// between be around 0.3 to 0.5\n\n\tvec3_t\t\tvieworg;\n\tvec3_t\t\tviewangles;\n\t\n\tfloat\t\tfov_x, fov_y;\n\n\tint\t\t\tambientlight;\n} refdef_t;\n\n\n//\n// refresh\n//\nextern\tint\t\treinit_surfcache;\n\n\nextern\trefdef_t\tr_refdef;\nextern vec3_t\tr_origin, vpn, vright, vup;\n\nextern\tstruct texture_s\t*r_notexture_mip;\n\n\nvoid R_Init (void);\nvoid R_InitTextures (void);\nvoid R_InitEfrags (void);\nvoid R_RenderView (void);\t\t// must set r_refdef first\nvoid R_ViewChanged (vrect_t *pvrect, int lineadj, float aspect);\n\t\t\t\t\t\t\t\t// called whenever r_refdef or vid change\nvoid R_InitSky (struct miptex_s *mt);\t// called at level load\n\nvoid R_AddEfrags (entity_t *ent);\nvoid R_RemoveEfrags (entity_t *ent);\n\nvoid R_NewMap (void);\n\n\nvoid R_ParseParticleEffect (void);\nvoid R_RunParticleEffect (vec3_t org, vec3_t dir, int color, int count);\nvoid R_RocketTrail (vec3_t start, vec3_t end, int type);\n\n#ifdef QUAKE2\nvoid R_DarkFieldParticles (entity_t *ent);\n#endif\nvoid R_EntityParticles (entity_t *ent);\nvoid R_BlobExplosion (vec3_t org);\nvoid R_ParticleExplosion (vec3_t org);\nvoid R_ParticleExplosion2 (vec3_t org, int colorStart, int colorLength);\nvoid R_LavaSplash (vec3_t org);\nvoid R_TeleportSplash (vec3_t org);\n\nvoid R_PushDlights (void);\n\n\n//\n// surface cache related\n//\nextern\tint\t\treinit_surfcache;\t// if 1, surface cache is currently empty and\nextern bool\tr_cache_thrash;\t// set if thrashing the surface cache\n\nint\tD_SurfaceCacheForRes (int width, int height);\nvoid D_FlushCaches (void);\nvoid D_DeleteSurfaceCache (void);\nvoid D_InitCaches (void *buffer, int size);\nvoid R_SetVrect (vrect_t *pvrect, vrect_t *pvrectin, int lineadj);\n\nextern entity_t r_worldentity;"
  },
  {
    "path": "source/sbar.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sbar.c -- status bar code\n\n#include \"quakedef.h\"\n\nextern void M_Print (int cx, int cy, char *str);\n\nextern cvar_t scr_sbaralpha;\nextern cvar_t scr_sbarscale;\nextern cvar_t viewsize;\n\nint\t\t\tsb_updates;\t\t// if >= vid.numpages, no update needed\n\n#define STAT_MINUS\t\t10\t// num frame for '-' stats digit\nqpic_t\t\t*sb_nums[2][11];\nqpic_t\t\t*sb_colon, *sb_slash;\nqpic_t\t\t*sb_ibar;\nqpic_t\t\t*sb_sbar;\nqpic_t\t\t*sb_scorebar;\n\nqpic_t      *sb_weapons[7][8];   // 0 is active, 1 is owned, 2-5 are flashes\nqpic_t      *sb_ammo[4];\nqpic_t\t\t*sb_sigil[4];\nqpic_t\t\t*sb_armor[3];\nqpic_t\t\t*sb_items[32];\n\nqpic_t\t*sb_faces[7][2];\t\t// 0 is gibbed, 1 is dead, 2-6 are alive\n\t\t\t\t\t\t\t// 0 is static, 1 is temporary animation\nqpic_t\t*sb_face_invis;\nqpic_t\t*sb_face_quad;\nqpic_t\t*sb_face_invuln;\nqpic_t\t*sb_face_invis_invuln;\n\nbool\tsb_showscores;\n\nqpic_t      *rsb_invbar[2];\nqpic_t      *rsb_weapons[5];\nqpic_t      *rsb_items[2];\nqpic_t      *rsb_ammo[3];\nqpic_t      *rsb_teambord;\t\t// PGM 01/19/97 - team color border\n\n//MED 01/04/97 added two more weapons + 3 alternates for grenade launcher\nqpic_t      *hsb_weapons[7][5];   // 0 is active, 1 is owned, 2-5 are flashes\n//MED 01/04/97 added array to simplify weapon parsing\nint         hipweapons[4] = {HIT_LASER_CANNON_BIT,HIT_MJOLNIR_BIT,4,HIT_PROXIMITY_GUN_BIT};\n//MED 01/04/97 added hipnotic items array\nqpic_t      *hsb_items[2];\n\nvoid Sbar_MiniDeathmatchOverlay (void);\nvoid Sbar_DeathmatchOverlay (void);\nvoid M_DrawPic (int x, int y, qpic_t *pic);\n\n/*\n===============\nSbar_ShowScores\n\nTab key down\n===============\n*/\nvoid Sbar_ShowScores (void)\n{\n\tif (sb_showscores)\n\t\treturn;\n\tsb_showscores = true;\n\tsb_updates = 0;\n}\n\n/*\n===============\nSbar_DontShowScores\n\nTab key up\n===============\n*/\nvoid Sbar_DontShowScores (void)\n{\n\tsb_showscores = false;\n\tsb_updates = 0;\n}\n\n/*\n===============\nSbar_Changed\n===============\n*/\nvoid Sbar_Changed (void)\n{\n\tsb_updates = 0;\t// update next frame\n}\n\n/*\n===============\nSbar_Init\n===============\n*/\nvoid Sbar_Init (void)\n{\n\tint\t\ti;\n\n\tfor (i=0 ; i<10 ; i++)\n\t{\n\t\tsb_nums[0][i] = Draw_PicFromWad (va(\"num_%i\",i));\n\t\tsb_nums[1][i] = Draw_PicFromWad (va(\"anum_%i\",i));\n\t}\n\n\tsb_nums[0][10] = Draw_PicFromWad (\"num_minus\");\n\tsb_nums[1][10] = Draw_PicFromWad (\"anum_minus\");\n\n\tsb_colon = Draw_PicFromWad (\"num_colon\");\n\tsb_slash = Draw_PicFromWad (\"num_slash\");\n\n\tsb_weapons[0][0] = Draw_PicFromWad (\"inv_shotgun\");\n\tsb_weapons[0][1] = Draw_PicFromWad (\"inv_sshotgun\");\n\tsb_weapons[0][2] = Draw_PicFromWad (\"inv_nailgun\");\n\tsb_weapons[0][3] = Draw_PicFromWad (\"inv_snailgun\");\n\tsb_weapons[0][4] = Draw_PicFromWad (\"inv_rlaunch\");\n\tsb_weapons[0][5] = Draw_PicFromWad (\"inv_srlaunch\");\n\tsb_weapons[0][6] = Draw_PicFromWad (\"inv_lightng\");\n\n\tsb_weapons[1][0] = Draw_PicFromWad (\"inv2_shotgun\");\n\tsb_weapons[1][1] = Draw_PicFromWad (\"inv2_sshotgun\");\n\tsb_weapons[1][2] = Draw_PicFromWad (\"inv2_nailgun\");\n\tsb_weapons[1][3] = Draw_PicFromWad (\"inv2_snailgun\");\n\tsb_weapons[1][4] = Draw_PicFromWad (\"inv2_rlaunch\");\n\tsb_weapons[1][5] = Draw_PicFromWad (\"inv2_srlaunch\");\n\tsb_weapons[1][6] = Draw_PicFromWad (\"inv2_lightng\");\n\n\tfor (i=0 ; i<5 ; i++)\n\t{\n\t\tsb_weapons[2+i][0] = Draw_PicFromWad (va(\"inva%i_shotgun\",i+1));\n\t\tsb_weapons[2+i][1] = Draw_PicFromWad (va(\"inva%i_sshotgun\",i+1));\n\t\tsb_weapons[2+i][2] = Draw_PicFromWad (va(\"inva%i_nailgun\",i+1));\n\t\tsb_weapons[2+i][3] = Draw_PicFromWad (va(\"inva%i_snailgun\",i+1));\n\t\tsb_weapons[2+i][4] = Draw_PicFromWad (va(\"inva%i_rlaunch\",i+1));\n\t\tsb_weapons[2+i][5] = Draw_PicFromWad (va(\"inva%i_srlaunch\",i+1));\n\t\tsb_weapons[2+i][6] = Draw_PicFromWad (va(\"inva%i_lightng\",i+1));\n\t}\n\n\tsb_ammo[0] = Draw_PicFromWad (\"sb_shells\");\n\tsb_ammo[1] = Draw_PicFromWad (\"sb_nails\");\n\tsb_ammo[2] = Draw_PicFromWad (\"sb_rocket\");\n\tsb_ammo[3] = Draw_PicFromWad (\"sb_cells\");\n\n\tsb_armor[0] = Draw_PicFromWad (\"sb_armor1\");\n\tsb_armor[1] = Draw_PicFromWad (\"sb_armor2\");\n\tsb_armor[2] = Draw_PicFromWad (\"sb_armor3\");\n\n\tsb_items[0] = Draw_PicFromWad (\"sb_key1\");\n\tsb_items[1] = Draw_PicFromWad (\"sb_key2\");\n\tsb_items[2] = Draw_PicFromWad (\"sb_invis\");\n\tsb_items[3] = Draw_PicFromWad (\"sb_invuln\");\n\tsb_items[4] = Draw_PicFromWad (\"sb_suit\");\n\tsb_items[5] = Draw_PicFromWad (\"sb_quad\");\n\n\tsb_sigil[0] = Draw_PicFromWad (\"sb_sigil1\");\n\tsb_sigil[1] = Draw_PicFromWad (\"sb_sigil2\");\n\tsb_sigil[2] = Draw_PicFromWad (\"sb_sigil3\");\n\tsb_sigil[3] = Draw_PicFromWad (\"sb_sigil4\");\n\n\tsb_faces[4][0] = Draw_PicFromWad (\"face1\");\n\tsb_faces[4][1] = Draw_PicFromWad (\"face_p1\");\n\tsb_faces[3][0] = Draw_PicFromWad (\"face2\");\n\tsb_faces[3][1] = Draw_PicFromWad (\"face_p2\");\n\tsb_faces[2][0] = Draw_PicFromWad (\"face3\");\n\tsb_faces[2][1] = Draw_PicFromWad (\"face_p3\");\n\tsb_faces[1][0] = Draw_PicFromWad (\"face4\");\n\tsb_faces[1][1] = Draw_PicFromWad (\"face_p4\");\n\tsb_faces[0][0] = Draw_PicFromWad (\"face5\");\n\tsb_faces[0][1] = Draw_PicFromWad (\"face_p5\");\n\n\tsb_face_invis = Draw_PicFromWad (\"face_invis\");\n\tsb_face_invuln = Draw_PicFromWad (\"face_invul2\");\n\tsb_face_invis_invuln = Draw_PicFromWad (\"face_inv2\");\n\tsb_face_quad = Draw_PicFromWad (\"face_quad\");\n\n\tCmd_AddCommand (\"+showscores\", Sbar_ShowScores);\n\tCmd_AddCommand (\"-showscores\", Sbar_DontShowScores);\n\n\tsb_sbar = Draw_PicFromWad (\"sbar\");\n\tsb_ibar = Draw_PicFromWad (\"ibar\");\n\tsb_scorebar = Draw_PicFromWad (\"scorebar\");\n\n//MED 01/04/97 added new hipnotic weapons\n\tif (hipnotic)\n\t{\n\t  hsb_weapons[0][0] = Draw_PicFromWad (\"inv_laser\");\n\t  hsb_weapons[0][1] = Draw_PicFromWad (\"inv_mjolnir\");\n\t  hsb_weapons[0][2] = Draw_PicFromWad (\"inv_gren_prox\");\n\t  hsb_weapons[0][3] = Draw_PicFromWad (\"inv_prox_gren\");\n\t  hsb_weapons[0][4] = Draw_PicFromWad (\"inv_prox\");\n\n\t  hsb_weapons[1][0] = Draw_PicFromWad (\"inv2_laser\");\n\t  hsb_weapons[1][1] = Draw_PicFromWad (\"inv2_mjolnir\");\n\t  hsb_weapons[1][2] = Draw_PicFromWad (\"inv2_gren_prox\");\n\t  hsb_weapons[1][3] = Draw_PicFromWad (\"inv2_prox_gren\");\n\t  hsb_weapons[1][4] = Draw_PicFromWad (\"inv2_prox\");\n\n\t  for (i=0 ; i<5 ; i++)\n\t  {\n\t\t hsb_weapons[2+i][0] = Draw_PicFromWad (va(\"inva%i_laser\",i+1));\n\t\t hsb_weapons[2+i][1] = Draw_PicFromWad (va(\"inva%i_mjolnir\",i+1));\n\t\t hsb_weapons[2+i][2] = Draw_PicFromWad (va(\"inva%i_gren_prox\",i+1));\n\t\t hsb_weapons[2+i][3] = Draw_PicFromWad (va(\"inva%i_prox_gren\",i+1));\n\t\t hsb_weapons[2+i][4] = Draw_PicFromWad (va(\"inva%i_prox\",i+1));\n\t  }\n\n\t  hsb_items[0] = Draw_PicFromWad (\"sb_wsuit\");\n\t  hsb_items[1] = Draw_PicFromWad (\"sb_eshld\");\n\t}\n\n\tif (rogue)\n\t{\n\t\trsb_invbar[0] = Draw_PicFromWad (\"r_invbar1\");\n\t\trsb_invbar[1] = Draw_PicFromWad (\"r_invbar2\");\n\n\t\trsb_weapons[0] = Draw_PicFromWad (\"r_lava\");\n\t\trsb_weapons[1] = Draw_PicFromWad (\"r_superlava\");\n\t\trsb_weapons[2] = Draw_PicFromWad (\"r_gren\");\n\t\trsb_weapons[3] = Draw_PicFromWad (\"r_multirock\");\n\t\trsb_weapons[4] = Draw_PicFromWad (\"r_plasma\");\n\n\t\trsb_items[0] = Draw_PicFromWad (\"r_shield1\");\n        rsb_items[1] = Draw_PicFromWad (\"r_agrav1\");\n\n// PGM 01/19/97 - team color border\n        rsb_teambord = Draw_PicFromWad (\"r_teambord\");\n// PGM 01/19/97 - team color border\n\n\t\trsb_ammo[0] = Draw_PicFromWad (\"r_ammolava\");\n\t\trsb_ammo[1] = Draw_PicFromWad (\"r_ammomulti\");\n\t\trsb_ammo[2] = Draw_PicFromWad (\"r_ammoplasma\");\n\t}\n}\n\n\n//=============================================================================\n\n// drawing routines are relative to the status bar location\n\n/*\n=============\nSbar_DrawPic\n=============\n*/\ninline __attribute__((always_inline)) void Sbar_DrawPic (int x, int y, qpic_t *pic)\n{\n\tDraw_Pic (x, y + 24, pic);\n}\n\n/*\n=============\nSbar_DrawPicAlpha\n=============\n*/\ninline __attribute__((always_inline)) void Sbar_DrawPicAlpha (int x, int y, qpic_t *pic, float alpha)\n{\n\tDraw_AlphaPic (x, y + 24, pic, alpha);\n}\n\n/*\n================\nSbar_DrawCharacter\n\nDraws one solid graphics character\n================\n*/\ninline __attribute__((always_inline)) void Sbar_DrawCharacter (int x, int y, int num)\n{\n\tBatch_Character (x, y + 24, num);\n}\n\n/*\n================\nSbar_DrawString\n================\n*/\ninline __attribute__((always_inline)) void Sbar_DrawString (int x, int y, char *str)\n{\n\tBatch_String (x, y + 24, str, 0);\n}\n\n/*\n=============\nSbar_itoa\n=============\n*/\nint Sbar_itoa (int num, char *buf)\n{\n\tchar\t*str;\n\tint\t\tpow10;\n\tint\t\tdig;\n\n\tstr = buf;\n\n\tif (num < 0)\n\t{\n\t\t*str++ = '-';\n\t\tnum = -num;\n\t}\n\n\tfor (pow10 = 10 ; num >= pow10 ; pow10 *= 10)\n\t;\n\n\tdo\n\t{\n\t\tpow10 /= 10;\n\t\tdig = num/pow10;\n\t\t*str++ = '0'+dig;\n\t\tnum -= dig*pow10;\n\t} while (pow10 != 1);\n\n\t*str = 0;\n\n\treturn str-buf;\n}\n\n\n/*\n=============\nSbar_DrawNum\n=============\n*/\nvoid Sbar_DrawNum (int x, int y, int num, int digits, int color)\n{\n\tchar\t\t\tstr[12];\n\tchar\t\t\t*ptr;\n\tint\t\t\t\tl, frame;\n\t\n\tnum = min(999,num); //johnfitz -- cap high values rather than truncating number\n\t\n\tl = Sbar_itoa (num, str);\n\tptr = str;\n\tif (l > digits)\n\t\tptr += (l-digits);\n\tif (l < digits)\n\t\tx += (digits-l)*24;\n\n\twhile (*ptr)\n\t{\n\t\tif (*ptr == '-')\n\t\t\tframe = STAT_MINUS;\n\t\telse\n\t\t\tframe = *ptr -'0';\n\n\t\tSbar_DrawPic (x,y,sb_nums[color][frame]); //johnfitz -- DrawTransPic is obsolete\n\t\tx += 24;\n\t\tptr++;\n\t}\n}\n\n//=============================================================================\n\nint\t\tfragsort[MAX_SCOREBOARD];\n\nchar\tscoreboardtext[MAX_SCOREBOARD][20];\nint\t\tscoreboardtop[MAX_SCOREBOARD];\nint\t\tscoreboardbottom[MAX_SCOREBOARD];\nint\t\tscoreboardcount[MAX_SCOREBOARD];\nint\t\tscoreboardlines;\n\n/*\n===============\nSbar_SortFrags\n===============\n*/\nvoid Sbar_SortFrags (void)\n{\n\tint\t\ti, j, k;\n\n// sort by frags\n\tscoreboardlines = 0;\n\tfor (i=0 ; i<cl.maxclients ; i++)\n\t{\n\t\tif (cl.scores[i].name[0])\n\t\t{\n\t\t\tfragsort[scoreboardlines] = i;\n\t\t\tscoreboardlines++;\n\t\t}\n\t}\n\n\tfor (i=0 ; i<scoreboardlines ; i++)\n\t\tfor (j=0 ; j<scoreboardlines-1-i ; j++)\n\t\t\tif (cl.scores[fragsort[j]].frags < cl.scores[fragsort[j+1]].frags)\n\t\t\t{\n\t\t\t\tk = fragsort[j];\n\t\t\t\tfragsort[j] = fragsort[j+1];\n\t\t\t\tfragsort[j+1] = k;\n\t\t\t}\n}\n\nint\tSbar_ColorForMap (int m)\n{\n\treturn m < 128 ? m + 8 : m + 8;\n}\n\n/*\n===============\nSbar_UpdateScoreboard\n===============\n*/\nvoid Sbar_UpdateScoreboard (void)\n{\n\tint\t\ti, k;\n\tint\t\ttop, bottom;\n\tscoreboard_t\t*s;\n\n\tSbar_SortFrags ();\n\n// draw the text\n\tmemset (scoreboardtext, 0, sizeof(scoreboardtext));\n\n\tfor (i=0 ; i<scoreboardlines; i++)\n\t{\n\t\tk = fragsort[i];\n\t\ts = &cl.scores[k];\n\t\tsprintf (&scoreboardtext[i][1], \"%3i %s\", s->frags, s->name);\n\n\t\ttop = s->colors & 0xf0;\n\t\tbottom = (s->colors & 15) <<4;\n\t\tscoreboardtop[i] = Sbar_ColorForMap (top);\n\t\tscoreboardbottom[i] = Sbar_ColorForMap (bottom);\n\t}\n}\n\n\n\n/*\n===============\nSbar_SoloScoreboard\n===============\n*/\nvoid Sbar_SoloScoreboard (void)\n{\n\tchar\tstr[80];\n\tint\t\tminutes, seconds, tens, units;\n\tint\t\tl;\n\n\tsprintf (str,\"Monsters:%3i /%3i\", cl.stats[STAT_MONSTERS], cl.stats[STAT_TOTALMONSTERS]);\n\tSbar_DrawString (8, 4, str);\n\n\tsprintf (str,\"Secrets :%3i /%3i\", cl.stats[STAT_SECRETS], cl.stats[STAT_TOTALSECRETS]);\n\tSbar_DrawString (8, 12, str);\n\n// time\n\tminutes = cl.time / 60;\n\tseconds = cl.time - 60*minutes;\n\ttens = seconds / 10;\n\tunits = seconds - 10*tens;\n\tsprintf (str,\"Time :%3i:%i%i\", minutes, tens, units);\n\tSbar_DrawString (184, 4, str);\n\n// draw level name\n\tl = strlen (cl.levelname);\n\tSbar_DrawString (232 - l*4, 12, cl.levelname);\n\t\n\tDraw_Batched();\n}\n\n/*\n===============\nSbar_DrawScoreboard\n===============\n*/\nvoid Sbar_DrawScoreboard (void)\n{\n\tSbar_SoloScoreboard ();\n\tif (cl.gametype == GAME_DEATHMATCH)\n\t\tSbar_DeathmatchOverlay ();\n}\n\n//=============================================================================\n\n/*\n===============\nSbar_DrawInventory\n===============\n*/\nvoid Sbar_DrawInventory (void)\n{\n\tint\t\ti;\n\tchar\tnum[6];\n\tfloat\ttime;\n\tint\t\tflashon;\n\n\tif (rogue)\n\t{\n\t\tif ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )\n\t\t\tSbar_DrawPicAlpha (0, -24, rsb_invbar[0], scr_sbaralpha.value);\n\t\telse\n\t\t\tSbar_DrawPicAlpha (0, -24, rsb_invbar[1], scr_sbaralpha.value);\n\t}\n\telse\n\t{\n\t\tSbar_DrawPicAlpha (0, -24, sb_ibar, scr_sbaralpha.value);\n\t}\n\n// weapons\n\tfor (i=0 ; i<7 ; i++)\n\t{\n\t\tif (cl.items & (IT_SHOTGUN<<i) )\n\t\t{\n\t\t\ttime = cl.item_gettime[i];\n\t\t\tflashon = (int)((cl.time - time)*10);\n\t\t\tif (flashon >= 10)\n\t\t\t{\n\t\t\t\tif ( cl.stats[STAT_ACTIVEWEAPON] == (IT_SHOTGUN<<i)  )\n\t\t\t\t\tflashon = 1;\n\t\t\t\telse\n\t\t\t\t\tflashon = 0;\n\t\t\t}\n\t\t\telse\n\t\t\t\tflashon = (flashon%5) + 2;\n\n         Sbar_DrawPic (i*24, -16, sb_weapons[flashon][i]);\n\n\t\t\tif (flashon > 1)\n\t\t\t\tsb_updates = 0;\t\t// force update to remove flash\n\t\t}\n\t}\n\n// MED 01/04/97\n// hipnotic weapons\n    if (hipnotic)\n    {\n      int grenadeflashing=0;\n      for (i=0 ; i<4 ; i++)\n      {\n         if (cl.items & (1<<hipweapons[i]) )\n         {\n            time = cl.item_gettime[hipweapons[i]];\n            flashon = (int)((cl.time - time)*10);\n            if (flashon >= 10)\n            {\n               if ( cl.stats[STAT_ACTIVEWEAPON] == (1<<hipweapons[i])  )\n                  flashon = 1;\n               else\n                  flashon = 0;\n            }\n            else\n               flashon = (flashon%5) + 2;\n\n            // check grenade launcher\n            if (i==2)\n            {\n               if (cl.items & HIT_PROXIMITY_GUN)\n               {\n                  if (flashon)\n                  {\n                     grenadeflashing = 1;\n                     Sbar_DrawPic (96, -16, hsb_weapons[flashon][2]);\n                  }\n               }\n            }\n            else if (i==3)\n            {\n               if (cl.items & (IT_SHOTGUN<<4))\n               {\n                  if (flashon && !grenadeflashing)\n                  {\n                     Sbar_DrawPic (96, -16, hsb_weapons[flashon][3]);\n                  }\n                  else if (!grenadeflashing)\n                  {\n                     Sbar_DrawPic (96, -16, hsb_weapons[0][3]);\n                  }\n               }\n               else\n                  Sbar_DrawPic (96, -16, hsb_weapons[flashon][4]);\n            }\n            else\n               Sbar_DrawPic (176 + (i*24), -16, hsb_weapons[flashon][i]);\n            if (flashon > 1)\n               sb_updates = 0;      // force update to remove flash\n         }\n      }\n    }\n\n\tif (rogue)\n\t{\n    // check for powered up weapon.\n\t\tif ( cl.stats[STAT_ACTIVEWEAPON] >= RIT_LAVA_NAILGUN )\n\t\t{\n\t\t\tfor (i=0;i<5;i++)\n\t\t\t{\n\t\t\t\tif (cl.stats[STAT_ACTIVEWEAPON] == (RIT_LAVA_NAILGUN << i))\n\t\t\t\t{\n\t\t\t\t\tSbar_DrawPic ((i+2)*24, -16, rsb_weapons[i]);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n// ammo counts\n\tfor (i=0 ; i<4 ; i++)\n\t{\n\t\tsprintf (num, \"%3i\",cl.stats[STAT_SHELLS+i] );\n\t\tif (num[0] != ' ')\n\t\t\tSbar_DrawCharacter ( (6*i+1)*8 - 2, -24, 18 + num[0] - '0');\n\t\tif (num[1] != ' ')\n\t\t\tSbar_DrawCharacter ( (6*i+2)*8 - 2, -24, 18 + num[1] - '0');\n\t\tif (num[2] != ' ')\n\t\t\tSbar_DrawCharacter ( (6*i+3)*8 - 2, -24, 18 + num[2] - '0');\n\t}\n\tDraw_Batched();\n\n\tflashon = 0;\n   // items\n   for (i=0 ; i<6 ; i++)\n      if (cl.items & (1<<(17+i)))\n      {\n         time = cl.item_gettime[17+i];\n         if (time && time > cl.time - 2 && flashon )\n         {  // flash frame\n            sb_updates = 0;\n         }\n         else\n         {\n         //MED 01/04/97 changed keys\n            if (!hipnotic || (i>1))\n            {\n               Sbar_DrawPic (192 + i*16, -16, sb_items[i]);\n            }\n         }\n         if (time && time > cl.time - 2)\n            sb_updates = 0;\n      }\n   //MED 01/04/97 added hipnotic items\n   // hipnotic items\n   if (hipnotic)\n   {\n      for (i=0 ; i<2 ; i++)\n         if (cl.items & (1<<(24+i)))\n         {\n            time = cl.item_gettime[24+i];\n            if (time && time > cl.time - 2 && flashon )\n            {  // flash frame\n               sb_updates = 0;\n            }\n            else\n            {\n               Sbar_DrawPic (288 + i*16, -16, hsb_items[i]);\n            }\n            if (time && time > cl.time - 2)\n               sb_updates = 0;\n         }\n   }\n\n\tif (rogue)\n\t{\n\t// new rogue items\n\t\tfor (i=0 ; i<2 ; i++)\n\t\t{\n\t\t\tif (cl.items & (1<<(29+i)))\n\t\t\t{\n\t\t\t\ttime = cl.item_gettime[29+i];\n\n\t\t\t\tif (time &&\ttime > cl.time - 2 && flashon )\n\t\t\t\t{\t// flash frame\n\t\t\t\t\tsb_updates = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t{\n\t\t\t\t\tSbar_DrawPic (288 + i*16, -16, rsb_items[i]);\n\t\t\t\t}\n\n\t\t\t\tif (time &&\ttime > cl.time - 2)\n\t\t\t\t\tsb_updates = 0;\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t{\n\t// sigils\n\t\tfor (i=0 ; i<4 ; i++)\n\t\t{\n\t\t\tif (cl.items & (1<<(28+i)))\n\t\t\t{\n\t\t\t\ttime = cl.item_gettime[28+i];\n\t\t\t\tif (time &&\ttime > cl.time - 2 && flashon )\n\t\t\t\t{\t// flash frame\n\t\t\t\t\tsb_updates = 0;\n\t\t\t\t}\n\t\t\t\telse\n\t\t\t\t\tSbar_DrawPic (320-32 + i*8, -16, sb_sigil[i]);\n\t\t\t\tif (time &&\ttime > cl.time - 2)\n\t\t\t\t\tsb_updates = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\n//=============================================================================\n\n/*\n===============\nSbar_DrawFrags -- johnfitz -- heavy revision\n===============\n*/\nvoid Sbar_DrawFrags (void)\n{\n\tint\tnumscores, i, x, color;\n\tchar\tnum[12];\n\tscoreboard_t\t*s;\n\n\tSbar_SortFrags ();\n\n// draw the text\n\tnumscores = min(scoreboardlines, 4);\n\n\tfor (i = 0, x = 184; i<numscores; i++, x += 32)\n\t{\n\t\ts = &cl.scores[fragsort[i]];\n\t\tif (!s->name[0])\n\t\t\tcontinue;\n\n\t// top color\n\t\tcolor = s->colors & 0xf0;\n\t\tcolor = Sbar_ColorForMap (color);\n\t\tDraw_Fill (x + 10, 1, 28, 4, color);\n\n\t// bottom color\n\t\tcolor = (s->colors & 15)<<4;\n\t\tcolor = Sbar_ColorForMap (color);\n\t\tDraw_Fill (x + 10, 5, 28, 3, color);\n\n\t// number\n\t\tsprintf (num, \"%3i\", s->frags);\n\t\tSbar_DrawCharacter (x + 12, -24, num[0]);\n\t\tSbar_DrawCharacter (x + 20, -24, num[1]);\n\t\tSbar_DrawCharacter (x + 28, -24, num[2]);\n\n\t// brackets\n\t\tif (fragsort[i] == cl.viewentity - 1)\n\t\t{\n\t\t\tSbar_DrawCharacter (x + 6, -24, 16);\n\t\t\tSbar_DrawCharacter (x + 32, -24, 17);\n\t\t}\n\t\tDraw_Batched();\n\t}\n}\n\n//=============================================================================\n\n\n/*\n===============\nSbar_DrawFace\n===============\n*/\nvoid Sbar_DrawFace (void)\n{\n\tint\t\tf, anim;\n\n// PGM 01/19/97 - team color drawing\n// PGM 03/02/97 - fixed so color swatch only appears in CTF modes\n\tif (rogue &&\n        (cl.maxclients != 1) &&\n        (teamplay.value>3) &&\n        (teamplay.value<7))\n\t{\n\t\tint\t\t\t\ttop, bottom;\n\t\tint\t\t\t\txofs;\n\t\tchar\t\t\tnum[12];\n\t\tscoreboard_t\t*s;\n\t\t\n\t\ts = &cl.scores[cl.viewentity - 1];\n\t\t// draw background\n\t\ttop = s->colors & 0xf0;\n\t\tbottom = (s->colors & 15)<<4;\n\t\ttop = Sbar_ColorForMap (top);\n\t\tbottom = Sbar_ColorForMap (bottom);\n\n\t\tif (cl.gametype == GAME_DEATHMATCH)\n\t\t\txofs = 113;\n\t\telse\n\t\t\txofs = ((vid.width - 320)>>1) + 113;\n\n\t\tSbar_DrawPic (112, 0, rsb_teambord);\n\t\tDraw_Fill (xofs, /*vid.height-*/24+3, 22, 9, top); //johnfitz -- sbar coords are now relative\n\t\tDraw_Fill (xofs, /*vid.height-*/24+12, 22, 9, bottom); //johnfitz -- sbar coords are now relative\n\n\t\t// draw number\n\t\tf = s->frags;\n\t\tsprintf (num, \"%3i\",f);\n\n\t\tif (top==8)\n\t\t{\n\t\t\tif (num[0] != ' ')\n\t\t\t\tSbar_DrawCharacter(109, 3, 18 + num[0] - '0');\n\t\t\tif (num[1] != ' ')\n\t\t\t\tSbar_DrawCharacter(116, 3, 18 + num[1] - '0');\n\t\t\tif (num[2] != ' ')\n\t\t\t\tSbar_DrawCharacter(123, 3, 18 + num[2] - '0');\n\t\t}\n\t\telse\n\t\t{\n\t\t\tSbar_DrawCharacter ( 109, 3, num[0]);\n\t\t\tSbar_DrawCharacter ( 116, 3, num[1]);\n\t\t\tSbar_DrawCharacter ( 123, 3, num[2]);\n\t\t}\n\t\tDraw_Batched();\n\t\t\n\t\treturn;\n\t}\n// PGM 01/19/97 - team color drawing\n\n\tif ( (cl.items & (IT_INVISIBILITY | IT_INVULNERABILITY) )\n\t== (IT_INVISIBILITY | IT_INVULNERABILITY) )\n\t{\n\t\tSbar_DrawPic (112, 0, sb_face_invis_invuln);\n\t\treturn;\n\t}\n\tif (cl.items & IT_QUAD)\n\t{\n\t\tSbar_DrawPic (112, 0, sb_face_quad );\n\t\treturn;\n\t}\n\tif (cl.items & IT_INVISIBILITY)\n\t{\n\t\tSbar_DrawPic (112, 0, sb_face_invis );\n\t\treturn;\n\t}\n\tif (cl.items & IT_INVULNERABILITY)\n\t{\n\t\tSbar_DrawPic (112, 0, sb_face_invuln);\n\t\treturn;\n\t}\n\n\tif (cl.stats[STAT_HEALTH] >= 100)\n\t\tf = 4;\n\telse\n\t\tf = cl.stats[STAT_HEALTH] / 20;\n\n\tif (cl.time <= cl.faceanimtime)\n\t{\n\t\tanim = 1;\n\t\tsb_updates = 0;\t\t// make sure the anim gets drawn over\n\t}\n\telse\n\t\tanim = 0;\n\tSbar_DrawPic (112, 0, sb_faces[f][anim]);\n}\n\n/*\n===============\nSbar_Draw\n===============\n*/\nvoid Sbar_Draw (void)\n{\n\tif (scr_con_current == vid.height)\n\t\treturn;\t\t// console is full screen\n\n\tif (cl.intermission)\n\t\treturn; //johnfitz -- never draw sbar during intermission\n\n\tif (sb_updates >= vid.numpages)\n\t\treturn;\n\n\tscr_copyeverything = 1;\n\n\tsb_updates++;\n\t\n\tGL_SetCanvas (CANVAS_DEFAULT); //johnfitz\n\t\n\tif (viewsize.value < 100.0) \n\t\tDraw_TileClear (0, vid.height - sb_lines, vid.width, sb_lines);\n\n\tGL_SetCanvas (CANVAS_SBAR); //johnfitz\n\n\tif (viewsize.value < 110.0)\n\t{\n\t\tSbar_DrawInventory ();\n\t\tif (cl.maxclients != 1)\n\t\t\tSbar_DrawFrags ();\n\t}\n\n\tif (sb_showscores || cl.stats[STAT_HEALTH] <= 0)\n\t{\n\t\tSbar_DrawPicAlpha (0, 0, sb_scorebar, scr_sbaralpha.value);\n\t\tSbar_DrawScoreboard ();\n\t\tsb_updates = 0;\n\t}\n\telse if (viewsize.value < 120)\n\t{\n\t\tSbar_DrawPicAlpha (0, 0, sb_sbar, scr_sbaralpha.value);\n\n   // keys (hipnotic only)\n      //MED 01/04/97 moved keys here so they would not be overwritten\n      if (hipnotic)\n      {\n         if (cl.items & IT_KEY1)\n            Sbar_DrawPic (209, 3, sb_items[0]);\n         if (cl.items & IT_KEY2)\n            Sbar_DrawPic (209, 12, sb_items[1]);\n      }\n   // armor\n\t\tif (cl.items & IT_INVULNERABILITY)\n\t\t{\n\t\t\tSbar_DrawNum (24, 0, 666, 3, 1);\n\t\t\tSbar_DrawPic (0, 0, draw_disc);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (rogue)\n\t\t\t{\n\t\t\t\tSbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3,\n\t\t\t\t\t\t\t\tcl.stats[STAT_ARMOR] <= 25);\n\t\t\t\tif (cl.items & RIT_ARMOR3)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[2]);\n\t\t\t\telse if (cl.items & RIT_ARMOR2)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[1]);\n\t\t\t\telse if (cl.items & RIT_ARMOR1)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[0]);\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tSbar_DrawNum (24, 0, cl.stats[STAT_ARMOR], 3\n\t\t\t\t, cl.stats[STAT_ARMOR] <= 25);\n\t\t\t\tif (cl.items & IT_ARMOR3)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[2]);\n\t\t\t\telse if (cl.items & IT_ARMOR2)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[1]);\n\t\t\t\telse if (cl.items & IT_ARMOR1)\n\t\t\t\t\tSbar_DrawPic (0, 0, sb_armor[0]);\n\t\t\t}\n\t\t}\n\n\t// face\n\t\tSbar_DrawFace ();\n\n\t// health\n\t\tSbar_DrawNum (136, 0, cl.stats[STAT_HEALTH], 3\n\t\t, cl.stats[STAT_HEALTH] <= 25);\n\n\t// ammo icon\n\t\tif (rogue)\n\t\t{\n\t\t\tif (cl.items & RIT_SHELLS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[0]);\n\t\t\telse if (cl.items & RIT_NAILS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[1]);\n\t\t\telse if (cl.items & RIT_ROCKETS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[2]);\n\t\t\telse if (cl.items & RIT_CELLS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[3]);\n\t\t\telse if (cl.items & RIT_LAVA_NAILS)\n\t\t\t\tSbar_DrawPic (224, 0, rsb_ammo[0]);\n\t\t\telse if (cl.items & RIT_PLASMA_AMMO)\n\t\t\t\tSbar_DrawPic (224, 0, rsb_ammo[1]);\n\t\t\telse if (cl.items & RIT_MULTI_ROCKETS)\n\t\t\t\tSbar_DrawPic (224, 0, rsb_ammo[2]);\n\t\t}\n\t\telse\n\t\t{\n\t\t\tif (cl.items & IT_SHELLS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[0]);\n\t\t\telse if (cl.items & IT_NAILS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[1]);\n\t\t\telse if (cl.items & IT_ROCKETS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[2]);\n\t\t\telse if (cl.items & IT_CELLS)\n\t\t\t\tSbar_DrawPic (224, 0, sb_ammo[3]);\n\t\t}\n\n\t\tSbar_DrawNum (248, 0, cl.stats[STAT_AMMO], 3,\n\t\t\t\t\t  cl.stats[STAT_AMMO] <= 10);\n\t}\n\n\tif (cl.gametype == GAME_DEATHMATCH)\n\t\tSbar_MiniDeathmatchOverlay ();\n\t\n}\n\n//=============================================================================\n\n/*\n==================\nSbar_IntermissionNumber\n\n==================\n*/\nvoid Sbar_IntermissionNumber (int x, int y, int num, int digits, int color)\n{\n\tchar\t\t\tstr[12];\n\tchar\t\t\t*ptr;\n\tint\t\t\t\tl, frame;\n\n\tl = Sbar_itoa (num, str);\n\tptr = str;\n\tif (l > digits)\n\t\tptr += (l-digits);\n\tif (l < digits)\n\t\tx += (digits-l)*24;\n\n\twhile (*ptr)\n\t{\n\t\tif (*ptr == '-')\n\t\t\tframe = STAT_MINUS;\n\t\telse\n\t\t\tframe = *ptr -'0';\n\n\t\tDraw_Pic (x,y,sb_nums[color][frame]);\n\t\tx += 24;\n\t\tptr++;\n\t}\n}\n\n/*\n==================\nSbar_DeathmatchOverlay\n\n==================\n*/\nvoid Sbar_DeathmatchOverlay (void)\n{\n\tqpic_t\t\t\t*pic;\n\tint\t\t\t\ti, k, l;\n\tint\t\t\t\ttop, bottom;\n\tint\t\t\t\tx, y, f;\n\tchar\t\t\tnum[12];\n\tscoreboard_t\t*s;\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n\tscr_copyeverything = 1;\n\tscr_fullupdate = 0;\n\n\tpic = Draw_CachePic (\"gfx/ranking.lmp\");\n\tM_DrawPic ((320-pic->width)/2, 8, pic);\n\n// scores\n\tSbar_SortFrags ();\n\n// draw the text\n\tl = scoreboardlines;\n\n\tx = 80;\n\ty = 40;\n\tfor (i=0 ; i<l ; i++)\n\t{\n\t\tk = fragsort[i];\n\t\ts = &cl.scores[k];\n\t\tif (!s->name[0])\n\t\t\tcontinue;\n\n\t// draw background\n\t\ttop = s->colors & 0xf0;\n\t\tbottom = (s->colors & 15)<<4;\n\t\ttop = Sbar_ColorForMap (top);\n\t\tbottom = Sbar_ColorForMap (bottom);\n\n\t\tDraw_Fill ( x, y, 40, 4, top);\n\t\tDraw_Fill ( x, y+4, 40, 4, bottom);\n\n\t// draw number\n\t\tf = s->frags;\n\t\tsprintf (num, \"%3i\",f);\n\n\t\tBatch_Character ( x+8 , y, num[0]);\n\t\tBatch_Character ( x+16 , y, num[1]);\n\t\tBatch_Character ( x+24 , y, num[2]);\n\n\t\tif (k == cl.viewentity - 1)\n\t\t\tBatch_Character ( x - 8, y, 12);\n\n\t// draw name\n\t\tM_Print (x+64, y, s->name);\n\t\tDraw_Batched();\n\n\t\ty += 10;\n\t}\n\t\n\tGL_SetCanvas (CANVAS_SBAR); //johnfitz\n}\n\n/*\n==================\nSbar_DeathmatchOverlay\n\n==================\n*/\nvoid Sbar_MiniDeathmatchOverlay (void)\n{\n\tqpic_t\t\t\t*pic;\n\tint\t\t\t\ti, k, l;\n\tint\t\t\t\ttop, bottom;\n\tint\t\t\t\tx, y, f;\n\tchar\t\t\tnum[12];\n\tscoreboard_t\t*s;\n\tint\t\t\t\tnumlines;\n\t\n\tfloat scale = Q_CLAMP (1.0, scr_sbarscale.value, (float)glwidth / 320.0); //johnfitz\n\t\n\tif (((float)glwidth / scale) < 512 || !sb_lines)\n\t\treturn;\n\n\tscr_copyeverything = 1;\n\tscr_fullupdate = 0;\n\n// scores\n\tSbar_SortFrags ();\n\n// draw the text\n\tl = scoreboardlines;\n\ty = vid.height - sb_lines;\n\tnumlines = (viewsize.value >= 110) ? 3 : 6; //johnfitz\n\tif (numlines < 3)\n\t\treturn;\n\n\t//find us\n\tfor (i = 0; i < scoreboardlines; i++)\n\t\tif (fragsort[i] == cl.viewentity - 1)\n\t\t\tbreak;\n\n    if (i == scoreboardlines) // we're not there\n            i = 0;\n    else // figure out start\n            i = i - numlines/2;\n\n    if (i > scoreboardlines - numlines)\n            i = scoreboardlines - numlines;\n    if (i < 0)\n            i = 0;\n\n\tx = 324;\n\ty = (viewsize.value >= 110) ? 24 : 0; //johnfitz -- start at the right place\n\tfor ( ; i < scoreboardlines && y <= 48; i++, y+=8) //johnfitz -- change y init, test, inc\n\t{\n\t\tk = fragsort[i];\n\t\ts = &cl.scores[k];\n\t\tif (!s->name[0])\n\t\t\tcontinue;\n\n\t// draw background\n\t\ttop = s->colors & 0xf0;\n\t\tbottom = (s->colors & 15)<<4;\n\t\ttop = Sbar_ColorForMap (top);\n\t\tbottom = Sbar_ColorForMap (bottom);\n\n\t\tDraw_Fill ( x, y+1, 40, 3, top);\n\t\tDraw_Fill ( x, y+4, 40, 4, bottom);\n\n\t// draw number\n\t\tf = s->frags;\n\t\tsprintf (num, \"%3i\",f);\n\n\t\tBatch_Character ( x+8 , y, num[0]);\n\t\tBatch_Character ( x+16 , y, num[1]);\n\t\tBatch_Character ( x+24 , y, num[2]);\n\n\t\tif (k == cl.viewentity - 1) {\n\t\t\tBatch_Character ( x, y, 16);\n\t\t\tBatch_Character ( x + 32, y, 17);\n\t\t}\n\n\t// draw name\n\t\tBatch_String (x+48, y, s->name, 0);\n\t\tDraw_Batched();\n\n\t\ty += 8;\n\t}\n}\n\n/*\n==================\nSbar_IntermissionOverlay\n\n==================\n*/\nvoid Sbar_IntermissionOverlay (void)\n{\n\tqpic_t\t*pic;\n\tint\t\tdig;\n\tint\t\tnum;\n\n\tscr_copyeverything = 1;\n\tscr_fullupdate = 0;\n\n\tif (cl.gametype == GAME_DEATHMATCH)\n\t{\n\t\tSbar_DeathmatchOverlay ();\n\t\treturn;\n\t}\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n\t//muff@yakko.globalnet.co.uk\n\t//dead easy stuff really\n\tpic = Draw_CachePic (\"gfx/complete.lmp\");\n\tDraw_Pic (64, 24, pic);\n\n\tpic = Draw_CachePic (\"gfx/inter.lmp\");\n\tDraw_TransPic (0, 56, pic);\n\n\tdig = cl.completed_time/60;\n\tSbar_IntermissionNumber (152, 64, dig, 3, 0); //johnfitz -- was 160\n\tnum = cl.completed_time - dig*60;\n\n\tDraw_Pic (224,64,sb_colon); //johnfitz -- was 234\n\tDraw_Pic (240,64,sb_nums[0][num/10]); //johnfitz -- was 246\n\tDraw_Pic (264,64,sb_nums[0][num%10]); //johnfitz -- was 266\n\n\tSbar_IntermissionNumber (152, 104, cl.stats[STAT_SECRETS], 3, 0); //johnfitz -- was 160\n\tDraw_Pic (224,104,sb_slash); //johnfitz -- was 232\n\tSbar_IntermissionNumber (240, 104, cl.stats[STAT_TOTALSECRETS], 3, 0); //johnfitz -- was 248\n\n\tSbar_IntermissionNumber (152, 144, cl.stats[STAT_MONSTERS], 3, 0); //johnfitz -- was 160\n\tDraw_Pic (224,144,sb_slash); //johnfitz -- was 232\n\tSbar_IntermissionNumber (240, 144, cl.stats[STAT_TOTALMONSTERS], 3, 0); //johnfitz -- was 248\n\t//end of muff\n\n}\n\n\n/*\n==================\nSbar_FinaleOverlay\n\n==================\n*/\nvoid Sbar_FinaleOverlay (void)\n{\n\tqpic_t\t*pic;\n\n\tscr_copyeverything = 1;\n\t\n\tGL_SetCanvas (CANVAS_MENU); //johnfitz\n\n\tpic = Draw_CachePic (\"gfx/finale.lmp\");\n\tDraw_TransPic ( (320-pic->width)/2, 16, pic);\n}\n"
  },
  {
    "path": "source/sbar.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n// the status bar is only redrawn if something has changed, but if anything\n// does, the entire thing will be redrawn for the next vid.numpages frames.\n\n#define\tSBAR_HEIGHT\t\t24\n\nextern\tint\t\t\tsb_lines;\t\t\t// scan lines to draw\n\nvoid Sbar_Init (void);\n\nvoid Sbar_Changed (void);\n// call whenever any of the client stats represented on the sbar changes\n\nvoid Sbar_Draw (void);\n// called every frame by screen\n\nvoid Sbar_IntermissionOverlay (void);\n// called each frame after the level has been completed\n\nvoid Sbar_FinaleOverlay (void);\n"
  },
  {
    "path": "source/screen.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// screen.h\n\nvoid SCR_Init (void);\n\nvoid SCR_UpdateScreen (void);\n\nvoid SCR_Benchmark (void);\n\nvoid SCR_SizeUp (void);\nvoid SCR_SizeDown (void);\nvoid SCR_BringDownConsole (void);\nvoid SCR_CenterPrint (char *str);\n\nvoid SCR_BeginLoadingPlaque (void);\nvoid SCR_EndLoadingPlaque (void);\n\nint SCR_ModalMessage (char *text);\n\nextern\tfloat\t\tscr_con_current;\nextern\tfloat\t\tscr_conlines;\t\t// lines of console to display\n\nextern\tint\t\t\tscr_fullupdate;\t// set to 0 to force full redraw\nextern\tint\t\t\tsb_lines;\n\nextern\tint\t\t\tclearnotify;\t// set to 0 whenever notify text is drawn\nextern\tbool\tscr_disabled_for_loading;\nextern\tbool\tscr_skipupdate;\n\nextern\tcvar_t\t\tviewsize;\n\n// only the refresh window will be updated unless these variables are flagged \nextern\tint\t\t\tscr_copytop;\nextern\tint\t\t\tscr_copyeverything;\n\nextern bool\t\tblock_drawing;\n\nvoid SCR_UpdateWholeScreen (void);\n"
  },
  {
    "path": "source/server.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// server.h\n\ntypedef struct\n{\n\tint\t\t\tmaxclients;\n\tint\t\t\tmaxclientslimit;\n\tstruct client_s\t*clients;\t\t// [maxclients]\n\tint\t\t\tserverflags;\t\t// episode completion information\n\tbool\tchangelevel_issued;\t// cleared when at SV_SpawnServer\n} server_static_t;\n\n//=============================================================================\n\ntypedef enum {ss_loading, ss_active} server_state_t;\n\ntypedef struct\n{\n\tbool\tactive;\t\t\t\t// false if only a net client\n\n\tbool\tpaused;\n\tbool\tloadgame;\t\t\t// handle connections specially\n\n\tdouble\t\ttime;\n\t\n\tint\t\t\tlastcheck;\t\t\t// used by PF_checkclient\n\tdouble\t\tlastchecktime;\n\t\n\tchar\t\tname[64];\t\t\t// map name\n#ifdef QUAKE2\n\tchar\t\tstartspot[64];\n#endif\n\tchar\t\tmodelname[64];\t\t// maps/<name>.bsp, for model_precache[0]\n\tstruct model_s \t*worldmodel;\n\tchar\t\t*model_precache[MAX_MODELS];\t// NULL terminated\n\tstruct model_s\t*models[MAX_MODELS];\n\tchar\t\t*sound_precache[MAX_SOUNDS];\t// NULL terminated\n\tchar\t\t*lightstyles[MAX_LIGHTSTYLES];\n\tint\t\t\tnum_edicts;\n\tint\t\t\tmax_edicts;\n\tedict_t\t\t*edicts;\t\t\t// can NOT be array indexed, because\n\t\t\t\t\t\t\t\t\t// edict_t is variable sized, but can\n\t\t\t\t\t\t\t\t\t// be used to reference the world ent\n\tserver_state_t\tstate;\t\t\t// some actions are only valid during load\n\n\tsizebuf_t\tdatagram;\n\tbyte\t\tdatagram_buf[MAX_DATAGRAM];\n\n\tsizebuf_t\treliable_datagram;\t// copied to all clients at end of frame\n\tbyte\t\treliable_datagram_buf[MAX_DATAGRAM];\n\n\tsizebuf_t\tsignon;\n\tbyte\t\tsignon_buf[8192];\n} server_t;\n\n\n#define\tNUM_PING_TIMES\t\t16\n#define\tNUM_SPAWN_PARMS\t\t16\n\ntypedef struct client_s\n{\n\tbool\t\tactive;\t\t\t\t// false = client is free\n\tbool\t\tspawned;\t\t\t// false = don't send datagrams\n\tbool\t\tdropasap;\t\t\t// has been told to go to another level\n\tbool\t\tprivileged;\t\t\t// can execute any host command\n\tbool\t\tsendsignon;\t\t\t// only valid before spawned\n\n\tdouble\t\t\tlast_message;\t\t// reliable messages must be sent\n\t\t\t\t\t\t\t\t\t\t// periodically\n\n\tstruct qsocket_s *netconnection;\t// communications handle\n\n\tusercmd_t\t\tcmd;\t\t\t\t// movement\n\tvec3_t\t\t\twishdir;\t\t\t// intended motion calced from cmd\n\n\tsizebuf_t\t\tmessage;\t\t\t// can be added to at any time,\n\t\t\t\t\t\t\t\t\t\t// copied and clear once per frame\n\tbyte\t\t\tmsgbuf[MAX_MSGLEN];\n\tedict_t\t\t\t*edict;\t\t\t\t// EDICT_NUM(clientnum+1)\n\tchar\t\t\tname[32];\t\t\t// for printing to other people\n\tint\t\t\t\tcolors;\n\t\t\n\tfloat\t\t\tping_times[NUM_PING_TIMES];\n\tint\t\t\t\tnum_pings;\t\t\t// ping_times[num_pings%NUM_PING_TIMES]\n\n// spawn parms are carried from level to level\n\tfloat\t\t\tspawn_parms[NUM_SPAWN_PARMS];\n\n// client known data for deltas\t\n\tint\t\t\t\told_frags;\n} client_t;\n\n\n//=============================================================================\n\n// edict->movetype values\n#define\tMOVETYPE_NONE\t\t\t0\t\t// never moves\n#define\tMOVETYPE_ANGLENOCLIP\t1\n#define\tMOVETYPE_ANGLECLIP\t\t2\n#define\tMOVETYPE_WALK\t\t\t3\t\t// gravity\n#define\tMOVETYPE_STEP\t\t\t4\t\t// gravity, special edge handling\n#define\tMOVETYPE_FLY\t\t\t5\n#define\tMOVETYPE_TOSS\t\t\t6\t\t// gravity\n#define\tMOVETYPE_PUSH\t\t\t7\t\t// no clip to world, push and crush\n#define\tMOVETYPE_NOCLIP\t\t\t8\n#define\tMOVETYPE_FLYMISSILE\t\t9\t\t// extra size to monsters\n#define\tMOVETYPE_BOUNCE\t\t\t10\n#ifdef QUAKE2\n#define MOVETYPE_BOUNCEMISSILE\t11\t\t// bounce w/o gravity\n#define MOVETYPE_FOLLOW\t\t\t12\t\t// track movement of aiment\n#endif\n\n// edict->solid values\n#define\tSOLID_NOT\t\t\t\t0\t\t// no interaction with other objects\n#define\tSOLID_TRIGGER\t\t\t1\t\t// touch on edge, but not blocking\n#define\tSOLID_BBOX\t\t\t\t2\t\t// touch on edge, block\n#define\tSOLID_SLIDEBOX\t\t\t3\t\t// touch on edge, but not an onground\n#define\tSOLID_BSP\t\t\t\t4\t\t// bsp clip, touch on edge, block\n\n// edict->deadflag values\n#define\tDEAD_NO\t\t\t\t\t0\n#define\tDEAD_DYING\t\t\t\t1\n#define\tDEAD_DEAD\t\t\t\t2\n\n#define\tDAMAGE_NO\t\t\t\t0\n#define\tDAMAGE_YES\t\t\t\t1\n#define\tDAMAGE_AIM\t\t\t\t2\n\n// edict->flags\n#define\tFL_FLY\t\t\t\t\t1\n#define\tFL_SWIM\t\t\t\t\t2\n//#define\tFL_GLIMPSE\t\t\t\t4\n#define\tFL_CONVEYOR\t\t\t\t4\n#define\tFL_CLIENT\t\t\t\t8\n#define\tFL_INWATER\t\t\t\t16\n#define\tFL_MONSTER\t\t\t\t32\n#define\tFL_GODMODE\t\t\t\t64\n#define\tFL_NOTARGET\t\t\t\t128\n#define\tFL_ITEM\t\t\t\t\t256\n#define\tFL_ONGROUND\t\t\t\t512\n#define\tFL_PARTIALGROUND\t\t1024\t// not all corners are valid\n#define\tFL_WATERJUMP\t\t\t2048\t// player jumping out of water\n#define\tFL_JUMPRELEASED\t\t\t4096\t// for jump debouncing\n#ifdef QUAKE2\n#define FL_FLASHLIGHT\t\t\t8192\n#define FL_ARCHIVE_OVERRIDE\t\t1048576\n#endif\n\n// entity effects\n\n#define\tEF_BRIGHTFIELD\t\t\t1\n#define\tEF_MUZZLEFLASH \t\t\t2\n#define\tEF_BRIGHTLIGHT \t\t\t4\n#define\tEF_DIMLIGHT \t\t\t8\n#define EF_NODRAW\t\t\t\t16\n#ifdef QUAKE2\n#define EF_DARKLIGHT\t\t\t16\n#define EF_DARKFIELD\t\t\t32\n#define EF_LIGHT\t\t\t\t64\n#endif\n\n#define EF_NOMODELFLAGS  0x800000   // indicates the model's .effects should be ignored (allows overriding them)\n#define EF_ROCKET       0x1000000   // leave a trail\n#define EF_GRENADE      0x2000000   // leave a trail\n#define EF_GIB          0x4000000   // leave a trail\n#define EF_ROTATE       0x8000000   // rotate (bonus items)\n#define EF_TRACER      0x10000000   // green split trail\n#define EF_ZOMGIB      0x20000000   // small blood trail\n#define EF_TRACER2     0x40000000   // orange split trail + rotate\n#define EF_TRACER3     0x80000000   // purple trail\n\n#define\tSPAWNFLAG_NOT_EASY\t\t\t256\n#define\tSPAWNFLAG_NOT_MEDIUM\t\t512\n#define\tSPAWNFLAG_NOT_HARD\t\t\t1024\n#define\tSPAWNFLAG_NOT_DEATHMATCH\t2048\n\n#ifdef QUAKE2\n// server flags\n#define\tSFL_EPISODE_1\t\t1\n#define\tSFL_EPISODE_2\t\t2\n#define\tSFL_EPISODE_3\t\t4\n#define\tSFL_EPISODE_4\t\t8\n#define\tSFL_NEW_UNIT\t\t16\n#define\tSFL_NEW_EPISODE\t\t32\n#define\tSFL_CROSS_TRIGGERS\t65280\n#endif\n\n//============================================================================\n\nextern\tcvar_t\tteamplay;\nextern\tcvar_t\tskill;\nextern\tcvar_t\tdeathmatch;\nextern\tcvar_t\tcoop;\nextern\tcvar_t\tfraglimit;\nextern\tcvar_t\ttimelimit;\n\nextern\tserver_static_t\tsvs;\t\t\t\t// persistant server info\nextern\tserver_t\t\tsv;\t\t\t\t\t// local server\n\nextern\tclient_t\t*host_client;\n\nextern\tjmp_buf \thost_abortserver;\n\nextern\tdouble\t\thost_time;\n\nextern\tedict_t\t\t*sv_player;\n\nextern\tcvar_t\tpq_fullpitch; // JPG 2.01\n\n//===========================================================\n\nvoid SV_Init (void);\n\nvoid SV_StartParticle (vec3_t org, vec3_t dir, int color, int count);\nvoid SV_StartSound (edict_t *entity, int channel, char *sample, int volume,\n    float attenuation);\n\nvoid SV_DropClient (bool crash);\n\nvoid SV_SendClientMessages (void);\nvoid SV_ClearDatagram (void);\n\nint SV_ModelIndex (char *name);\n\nvoid SV_SetIdealPitch (void);\n\nvoid SV_AddUpdates (void);\n\nvoid SV_ClientThink (void);\nvoid SV_AddClientToServer (struct qsocket_s\t*ret);\n\nvoid SV_ClientPrintf (const char *fmt, ...);\nvoid SV_BroadcastPrintf (char *fmt, ...);\n\nvoid SV_Physics (void);\n\nbool SV_CheckBottom (edict_t *ent);\nbool SV_movestep (edict_t *ent, vec3_t move, bool relink);\n\nvoid SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg);\n\nvoid SV_MoveToGoal (void);\n\nvoid SV_CheckForNewClients (void);\nvoid SV_RunClients (void);\nvoid SV_SaveSpawnparms ();\n#ifdef QUAKE2\nvoid SV_SpawnServer (char *server, char *startspot);\n#else\nvoid SV_SpawnServer (char *server);\n#endif\n\nvoid Host_Version_f (void);"
  },
  {
    "path": "source/snd_dma.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// snd_dma.c -- main control for any streaming sound output device\n\n#include \"quakedef.h\"\n\nCVAR (bgmvolume, 1, CVAR_ARCHIVE)\nCVAR (volume, 0.7, CVAR_ARCHIVE)\n\nCVAR (nosound, 0, CVAR_ROM) // Ch0wW: since it's not from the CMDLine...\nCVAR (precache, 1, CVAR_ROM)\n\nCVAR(loadas8bit, 0, CVAR_NONE)\nCVAR(bgmbuffer, 4096, CVAR_NONE)\nCVAR(ambient_level, 0.3, CVAR_NONE)\nCVAR(ambient_fade, 100, CVAR_NONE)\nCVAR(snd_noextraupdate, 0, CVAR_NONE)\nCVAR(snd_show, 0, CVAR_NONE)\nCVAR(_snd_mixahead, 0.1, CVAR_NONE)\n\n//----------------------------------------------\n\nvoid S_Play(void);\nvoid S_PlayVol(void);\nvoid S_SoundList(void);\nvoid S_Update_();\nvoid S_StopAllSounds(bool clear);\nvoid S_StopAllSoundsC(void);\n\n// =======================================================================\n// Internal sound data & structures\n// =======================================================================\n\nchannel_t   channels[MAX_CHANNELS];\nint\t\t\ttotal_channels;\n\nint\t\t\t\tsnd_blocked = 0;\nstatic bool\tsnd_ambient = 1;\nbool\t\tsnd_initialized = false;\n\n// pointer should go away\nvolatile dma_t  *shm = 0;\nvolatile dma_t sn;\n\nvec3_t\t\tlistener_origin;\nvec3_t\t\tlistener_forward;\nvec3_t\t\tlistener_right;\nvec3_t\t\tlistener_up;\nvec_t\t\tsound_nominal_clip_dist=1000.0;\n\nint\t\t\tsoundtime;\t\t// sample PAIRS\nint   \t\tpaintedtime; \t// sample PAIRS\n\n\n#define\tMAX_SFX\t\t512\nsfx_t\t\t*known_sfx;\t\t// hunk allocated [MAX_SFX]\nint\t\t\tnum_sfx;\n\nsfx_t\t\t*ambient_sfx[NUM_AMBIENTS];\n\nint \t\tdesired_speed = 11025;\nint \t\tdesired_bits = 16;\n\nint sound_started=0;\n\n// ====================================================================\n// User-setable variables\n// ====================================================================\n\n\n//\n// Fake dma is a synchronous faking of the DMA progress used for\n// isolating performance in the renderer.  The fakedma_updates is\n// number of times S_Update() is called per second.\n//\n\nbool fakedma = false;\nint fakedma_updates = 15;\n\n\nvoid S_AmbientOff (void)\n{\n\tsnd_ambient = false;\n}\n\n\nvoid S_AmbientOn (void)\n{\n\tsnd_ambient = true;\n}\n\n\nvoid S_SoundInfo_f(void)\n{\n\tif (!sound_started || !shm)\n\t{\n\t\tCon_Printf (\"sound system not started\\n\");\n\t\treturn;\n\t}\n\t\n    Con_Printf(\"%5d stereo\\n\", shm->channels - 1);\n    Con_Printf(\"%5d samples\\n\", shm->samples);\n    Con_Printf(\"%5d samplepos\\n\", shm->samplepos);\n    Con_Printf(\"%5d samplebits\\n\", shm->samplebits);\n    Con_Printf(\"%5d submission_chunk\\n\", shm->submission_chunk);\n    Con_Printf(\"%5d speed\\n\", shm->speed);\n    Con_Printf(\"0x%x dma buffer\\n\", shm->buffer);\n\tCon_Printf(\"%5d total_channels\\n\", total_channels);\n}\n\n\n/*\n================\nS_Startup\n================\n*/\n\nvoid S_Startup (void)\n{\n\tint\t\trc;\n\n\tif (!snd_initialized)\n\t\treturn;\n\n\tif (!fakedma)\n\t{\n\t\trc = SNDDMA_Init();\n\n\t\tif (!rc)\n\t\t{\n#ifndef\t_WIN32\n\t\t\tCon_Printf(\"S_Startup: SNDDMA_Init failed.\\n\");\n#endif\n\t\t\tsound_started = 0;\n\t\t\treturn;\n\t\t}\n\t}\n\n\tsound_started = 1;\n}\n\n\n/*\n================\nS_Init\n================\n*/\nvoid S_Init (void)\n{\n\n\tCon_Printf(\"\\nSound Initialization\\n\");\n\n\tif (COM_CheckParm(\"-nosound\"))\n\t\treturn;\n\n\tif (COM_CheckParm(\"-simsound\"))\n\t\tfakedma = true;\n\n\tCmd_AddCommand(\"play\", S_Play);\n\tCmd_AddCommand(\"playvol\", S_PlayVol);\n\tCmd_AddCommand(\"stopsound\", S_StopAllSoundsC);\n\tCmd_AddCommand(\"soundlist\", S_SoundList);\n\tCmd_AddCommand(\"soundinfo\", S_SoundInfo_f);\n\n\tCvar_RegisterVariable(&nosound);\n\tCvar_RegisterVariable(&volume);\n\tCvar_RegisterVariable(&precache);\n\tCvar_RegisterVariable(&loadas8bit);\n\tCvar_RegisterVariable(&bgmvolume);\n\tCvar_RegisterVariable(&bgmbuffer);\n\tCvar_RegisterVariable(&ambient_level);\n\tCvar_RegisterVariable(&ambient_fade);\n\tCvar_RegisterVariable(&snd_noextraupdate);\n\tCvar_RegisterVariable(&snd_show);\n\tCvar_RegisterVariable(&_snd_mixahead);\n\n\tif (host_parms.memsize < 0x800000)\n\t{\n\t\tCvar_Set (\"loadas8bit\", \"1\");\n\t\tCon_Printf (\"loading all sounds as 8bit\\n\");\n\t}\n\n\n\n\tsnd_initialized = true;\n\n\tS_Startup ();\n\n\tSND_InitScaletable ();\n\n\tknown_sfx = Hunk_AllocName (MAX_SFX*sizeof(sfx_t), \"sfx_t\");\n\tnum_sfx = 0;\n\n// create a piece of DMA memory\n\n\tif (fakedma)\n\t{\n\t\tshm = (void *) Hunk_AllocName(sizeof(*shm), \"shm\");\n\t\tshm->splitbuffer = 0;\n\t\tshm->samplebits = 16;\n\t\tshm->speed = 22050;\n\t\tshm->channels = 2;\n\t\tshm->samples = 32768;\n\t\tshm->samplepos = 0;\n\t\tshm->soundalive = true;\n\t\tshm->gamealive = true;\n\t\tshm->submission_chunk = 1;\n\t\tshm->buffer = Hunk_AllocName(1<<16, \"shmbuf\");\n\t}\n\n\tCon_Printf (\"Sound sampling rate: %i\\n\", shm->speed);\n\n\t// provides a tick sound until washed clean\n\n//\tif (shm->buffer)\n//\t\tshm->buffer[4] = shm->buffer[5] = 0x7f;\t// force a pop for debugging\n\n\tambient_sfx[AMBIENT_WATER] = S_PrecacheSound (\"ambience/water1.wav\");\n\tambient_sfx[AMBIENT_SKY] = S_PrecacheSound (\"ambience/wind2.wav\");\n\n\tS_StopAllSounds (true);\n}\n\n\n// =======================================================================\n// Shutdown sound engine\n// =======================================================================\n\nvoid S_Shutdown(void)\n{\n\n\tif (!sound_started)\n\t\treturn;\n\n\tif (shm)\n\t\tshm->gamealive = 0;\n\n\tshm = 0;\n\tsound_started = 0;\n\n\tif (!fakedma)\n\t{\n\t\tSNDDMA_Shutdown();\n\t}\n}\n\n\n// =======================================================================\n// Load a sound\n// =======================================================================\n\n/*\n==================\nS_FindName\n\n==================\n*/\nsfx_t *S_FindName (char *name)\n{\n\tint\t\ti;\n\tsfx_t\t*sfx;\n\n\tif (!name)\n\t\tSys_Error (\"S_FindName: NULL\\n\");\n\n\tif (strlen(name) >= MAX_QPATH)\n\t\tSys_Error (\"Sound name too long: %s\", name);\n\n// see if already loaded\n\tfor (i=0 ; i < num_sfx ; i++)\n\t\tif (!strcmp(known_sfx[i].name, name))\n\t\t{\n\t\t\treturn &known_sfx[i];\n\t\t}\n\n\tif (num_sfx == MAX_SFX)\n\t\tSys_Error (\"S_FindName: out of sfx_t\");\n\t\n\tsfx = &known_sfx[i];\n\tstrcpy (sfx->name, name);\n\n\tnum_sfx++;\n\t\n\treturn sfx;\n}\n\n\n/*\n==================\nS_TouchSound\n\n==================\n*/\nvoid S_TouchSound (char *name)\n{\n\tsfx_t\t*sfx;\n\t\n\tif (!sound_started)\n\t\treturn;\n\n\tsfx = S_FindName (name);\n\tCache_Check (&sfx->cache);\n}\n\n/*\n==================\nS_PrecacheSound\n\n==================\n*/\nsfx_t *S_PrecacheSound (char *name)\n{\n\tsfx_t\t*sfx;\n\n\tif (!sound_started || nosound.value)\n\t\treturn NULL;\n\n\tsfx = S_FindName (name);\n\t\n// cache it in\n\tif (precache.value)\n\t\tS_LoadSound (sfx);\n\t\n\treturn sfx;\n}\n\n\n//=============================================================================\n\n/*\n=================\nSND_PickChannel\n=================\n*/\nchannel_t *SND_PickChannel(int entnum, int entchannel)\n{\n    int ch_idx;\n    int first_to_die;\n    int life_left;\n\n// Check for replacement sound, or find the best one to replace\n    first_to_die = -1;\n    life_left = 0x7fffffff;\n    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++)\n    {\n\t\tif (entchannel != 0\t\t// channel 0 never overrides\n\t\t&& channels[ch_idx].entnum == entnum\n\t\t&& (channels[ch_idx].entchannel == entchannel || entchannel == -1) )\n\t\t{\t// always override sound from same entity\n\t\t\tfirst_to_die = ch_idx;\n\t\t\tbreak;\n\t\t}\n\n\t\t// don't let monster sounds override player sounds\n\t\tif (channels[ch_idx].entnum == cl.viewentity && entnum != cl.viewentity && channels[ch_idx].sfx)\n\t\t\tcontinue;\n\n\t\tif (channels[ch_idx].end - paintedtime < life_left)\n\t\t{\n\t\t\tlife_left = channels[ch_idx].end - paintedtime;\n\t\t\tfirst_to_die = ch_idx;\n\t\t}\n   }\n\n\tif (first_to_die == -1)\n\t\treturn NULL;\n\n\tif (channels[first_to_die].sfx)\n\t\tchannels[first_to_die].sfx = NULL;\n\n    return &channels[first_to_die];    \n}       \n\n/*\n=================\nSND_Spatialize\n=================\n*/\nvoid SND_Spatialize(channel_t *ch)\n{\n    vec_t dot;\n    vec_t ldist, rdist, dist;\n    vec_t lscale, rscale, scale;\n    vec3_t source_vec;\n\tsfx_t *snd;\n\n// anything coming from the view entity will always be full volume\n\tif (ch->entnum == cl.viewentity)\n\t{\n\t\tch->leftvol = ch->master_vol;\n\t\tch->rightvol = ch->master_vol;\n\t\treturn;\n\t}\n\n// calculate stereo seperation and distance attenuation\n\n\tsnd = ch->sfx;\n\tVectorSubtract(ch->origin, listener_origin, source_vec);\n\t\n\tdist = VectorNormalize(source_vec) * ch->dist_mult;\n\t\n\tdot = DotProduct(listener_right, source_vec);\n\n\tif (shm->channels == 1)\n\t{\n\t\trscale = 1.0;\n\t\tlscale = 1.0;\n\t}\n\telse\n\t{\n\t\trscale = 1.0 + dot;\n\t\tlscale = 1.0 - dot;\n\t}\n\n// add in distance effect\n\tscale = (1.0 - dist) * rscale;\n\tch->rightvol = (int) (ch->master_vol * scale);\n\tif (ch->rightvol < 0)\n\t\tch->rightvol = 0;\n\n\tscale = (1.0 - dist) * lscale;\n\tch->leftvol = (int) (ch->master_vol * scale);\n\tif (ch->leftvol < 0)\n\t\tch->leftvol = 0;\n}           \n\n\n// =======================================================================\n// Start a sound effect\n// =======================================================================\n\nvoid S_StartSound(int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol, float attenuation)\n{\n\tchannel_t *target_chan, *check;\n\tsfxcache_t\t*sc;\n\tint\t\tvol;\n\tint\t\tch_idx;\n\tint\t\tskip;\n\n\tif (!sound_started)\n\t\treturn;\n\n\tif (!sfx)\n\t\treturn;\n\n\tif (nosound.value)\n\t\treturn;\n\n\tvol = fvol*255;\n\n// pick a channel to play on\n\ttarget_chan = SND_PickChannel(entnum, entchannel);\n\tif (!target_chan)\n\t\treturn;\n\t\t\n// spatialize\n\tmemset (target_chan, 0, sizeof(*target_chan));\n\tVectorCopy(origin, target_chan->origin);\n\ttarget_chan->dist_mult = attenuation / sound_nominal_clip_dist;\n\ttarget_chan->master_vol = vol;\n\ttarget_chan->entnum = entnum;\n\ttarget_chan->entchannel = entchannel;\n\tSND_Spatialize(target_chan);\n\n\tif (!target_chan->leftvol && !target_chan->rightvol)\n\t\treturn;\t\t// not audible at all\n\n// new channel\n\tsc = S_LoadSound (sfx);\n\tif (!sc)\n\t{\n\t\ttarget_chan->sfx = NULL;\n\t\treturn;\t\t// couldn't load the sound's data\n\t}\n\n\ttarget_chan->sfx = sfx;\n\ttarget_chan->pos = 0.0;\n    target_chan->end = paintedtime + sc->length;\t\n\n// if an identical sound has also been started this frame, offset the pos\n// a bit to keep it from just making the first one louder\n\tcheck = &channels[NUM_AMBIENTS];\n    for (ch_idx=NUM_AMBIENTS ; ch_idx < NUM_AMBIENTS + MAX_DYNAMIC_CHANNELS ; ch_idx++, check++)\n    {\n\t\tif (check == target_chan)\n\t\t\tcontinue;\n\t\tif (check->sfx == sfx && !check->pos)\n\t\t{\n\t\t\tskip = rand () % (int)(0.1*shm->speed);\n\t\t\tif (skip >= target_chan->end)\n\t\t\t\tskip = target_chan->end - 1;\n\t\t\ttarget_chan->pos += skip;\n\t\t\ttarget_chan->end -= skip;\n\t\t\tbreak;\n\t\t}\n\t\t\n\t}\n}\n\nvoid S_StopSound(int entnum, int entchannel)\n{\n\tint i;\n\n\tfor (i=0 ; i<MAX_DYNAMIC_CHANNELS ; i++)\n\t{\n\t\tif (channels[i].entnum == entnum\n\t\t\t&& channels[i].entchannel == entchannel)\n\t\t{\n\t\t\tchannels[i].end = 0;\n\t\t\tchannels[i].sfx = NULL;\n\t\t\treturn;\n\t\t}\n\t}\n}\n\nvoid S_StopAllSounds(bool clear)\n{\n\tint\t\ti;\n\n\tif (!sound_started)\n\t\treturn;\n\n\ttotal_channels = MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;\t// no statics\n\n\tfor (i=0 ; i<MAX_CHANNELS ; i++)\n\t\tif (channels[i].sfx)\n\t\t\tchannels[i].sfx = NULL;\n\n\tmemset(channels, 0, MAX_CHANNELS * sizeof(channel_t));\n\n\tif (clear)\n\t\tS_ClearBuffer ();\n}\n\nvoid S_StopAllSoundsC (void)\n{\n\tS_StopAllSounds (true);\n}\n\nvoid S_ClearBuffer (void)\n{\n\tint\t\tclear;\n\t\t\n#ifdef _WIN32\n\tif (!sound_started || !shm || (!shm->buffer && !pDSBuf))\n#else\n\tif (!sound_started || !shm || !shm->buffer)\n#endif\n\t\treturn;\n\n\tif (shm->samplebits == 8)\n\t\tclear = 0x80;\n\telse\n\t\tclear = 0;\n\n#ifdef _WIN32\n\tif (pDSBuf)\n\t{\n\t\tDWORD\tdwSize;\n\t\tDWORD\t*pData;\n\t\tint\t\treps;\n\t\tHRESULT\thresult;\n\n\t\treps = 0;\n\n\t\twhile ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pData, &dwSize, NULL, NULL, 0)) != DS_OK)\n\t\t{\n\t\t\tif (hresult != DSERR_BUFFERLOST)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_ClearBuffer: DS::Lock Sound Buffer Failed\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (++reps > 10000)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_ClearBuffer: DS: couldn't restore buffer\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\tmemset(pData, clear, shm->samples * shm->samplebits/8);\n\n\t\tpDSBuf->lpVtbl->Unlock(pDSBuf, pData, dwSize, NULL, 0);\n\t\n\t}\n\telse\n#endif\n\t{\n\t\tmemset(shm->buffer, clear, shm->samples * shm->samplebits/8);\n\t}\n}\n\n\n/*\n=================\nS_StaticSound\n=================\n*/\nvoid S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation)\n{\n\tchannel_t\t*ss;\n\tsfxcache_t\t\t*sc;\n\n\tif (!sfx)\n\t\treturn;\n\n\tif (total_channels == MAX_CHANNELS)\n\t{\n\t\tCon_Printf (\"total_channels == MAX_CHANNELS\\n\");\n\t\treturn;\n\t}\n\n\tss = &channels[total_channels];\n\ttotal_channels++;\n\n\tsc = S_LoadSound (sfx);\n\tif (!sc)\n\t\treturn;\n\n\tif (sc->loopstart == -1)\n\t{\n\t\tCon_Printf (\"Sound %s not looped\\n\", sfx->name);\n\t\treturn;\n\t}\n\t\n\tss->sfx = sfx;\n\tVectorCopy (origin, ss->origin);\n\tss->master_vol = vol;\n\tss->dist_mult = (attenuation/64) / sound_nominal_clip_dist;\n    ss->end = paintedtime + sc->length;\t\n\t\n\tSND_Spatialize (ss);\n}\n\n\n//=============================================================================\n\n/*\n===================\nS_UpdateAmbientSounds\n===================\n*/\nvoid S_UpdateAmbientSounds (void)\n{\n\tmleaf_t\t\t*l;\n\tfloat\t\tvol;\n\tint\t\t\tambient_channel;\n\tchannel_t\t*chan;\n\n\tif (!snd_ambient)\n\t\treturn;\n\n// calc ambient sound levels\n\tif (!cl.worldmodel)\n\t\treturn;\n\n\tl = Mod_PointInLeaf (listener_origin, cl.worldmodel);\n\tif (!l || !ambient_level.value)\n\t{\n\t\tfor (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)\n\t\t\tchannels[ambient_channel].sfx = NULL;\n\t\treturn;\n\t}\n\n\tfor (ambient_channel = 0 ; ambient_channel< NUM_AMBIENTS ; ambient_channel++)\n\t{\n\t\tchan = &channels[ambient_channel];\t\n\t\tchan->sfx = ambient_sfx[ambient_channel];\n\t\n\t\tvol = ambient_level.value * l->ambient_sound_level[ambient_channel];\n\t\tif (vol < 8)\n\t\t\tvol = 0;\n\n\t// don't adjust volume too fast\n\t\tif (chan->master_vol < vol)\n\t\t{\n\t\t\tchan->master_vol += host_frametime * ambient_fade.value;\n\t\t\tif (chan->master_vol > vol)\n\t\t\t\tchan->master_vol = vol;\n\t\t}\n\t\telse if (chan->master_vol > vol)\n\t\t{\n\t\t\tchan->master_vol -= host_frametime * ambient_fade.value;\n\t\t\tif (chan->master_vol < vol)\n\t\t\t\tchan->master_vol = vol;\n\t\t}\n\t\t\n\t\tchan->leftvol = chan->rightvol = chan->master_vol;\n\t}\n}\n\n\n/*\n============\nS_Update\n\nCalled once each time through the main loop\n============\n*/\nvoid S_Update(vec3_t origin, vec3_t forward, vec3_t right, vec3_t up)\n{\n\tint\t\t\ti, j;\n\tint\t\t\ttotal;\n\tchannel_t\t*ch;\n\tchannel_t\t*combine;\n\n\tif (!sound_started || (snd_blocked > 0))\n\t\treturn;\n\n\tVectorCopy(origin, listener_origin);\n\tVectorCopy(forward, listener_forward);\n\tVectorCopy(right, listener_right);\n\tVectorCopy(up, listener_up);\n\t\n// update general area ambient sound sources\n\tS_UpdateAmbientSounds ();\n\n\tcombine = NULL;\n\n// update spatialization for static and dynamic sounds\t\n\tch = channels+NUM_AMBIENTS;\n\tfor (i=NUM_AMBIENTS ; i<total_channels; i++, ch++)\n\t{\n\t\tif (!ch->sfx)\n\t\t\tcontinue;\n\t\tSND_Spatialize(ch);         // respatialize channel\n\t\tif (!ch->leftvol && !ch->rightvol)\n\t\t\tcontinue;\n\n\t// try to combine static sounds with a previous channel of the same\n\t// sound effect so we don't mix five torches every frame\n\t\n\t\tif (i >= MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS)\n\t\t{\n\t\t// see if it can just use the last one\n\t\t\tif (combine && combine->sfx == ch->sfx)\n\t\t\t{\n\t\t\t\tcombine->leftvol += ch->leftvol;\n\t\t\t\tcombine->rightvol += ch->rightvol;\n\t\t\t\tch->leftvol = ch->rightvol = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t// search for one\n\t\t\tcombine = channels+MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS;\n\t\t\tfor (j=MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS ; j<i; j++, combine++)\n\t\t\t\tif (combine->sfx == ch->sfx)\n\t\t\t\t\tbreak;\n\t\t\t\t\t\n\t\t\tif (j == total_channels)\n\t\t\t{\n\t\t\t\tcombine = NULL;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (combine != ch)\n\t\t\t\t{\n\t\t\t\t\tcombine->leftvol += ch->leftvol;\n\t\t\t\t\tcombine->rightvol += ch->rightvol;\n\t\t\t\t\tch->leftvol = ch->rightvol = 0;\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t\n\t\t\n\t}\n\n//\n// debugging output\n//\n\tif (snd_show.value)\n\t{\n\t\ttotal = 0;\n\t\tch = channels;\n\t\tfor (i=0 ; i<total_channels; i++, ch++)\n\t\t\tif (ch->sfx && (ch->leftvol || ch->rightvol) )\n\t\t\t{\n\t\t\t\t//Con_Printf (\"%3i %3i %s\\n\", ch->leftvol, ch->rightvol, ch->sfx->name);\n\t\t\t\ttotal++;\n\t\t\t}\n\t\t\n\t\tCon_Printf (\"----(%i)----\\n\", total);\n\t}\n\n// mix some sound\n\tS_Update_();\n}\n\nvoid 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 = shm->samples / shm->channels;\n\n// it is possible to miscount buffers if it has wrapped twice between\n// calls to S_Update.  Oh well.\n#ifdef __sun__\n\tsoundtime = SNDDMA_GetSamples();\n#else\n\tsamplepos = SNDDMA_GetDMAPos();\n\n\n\tif (samplepos < oldsamplepos)\n\t{\n\t\tbuffers++;\t\t\t\t\t// buffer wrapped\n\t\t\n\t\tif (paintedtime > 0x40000000)\n\t\t{\t// time to chop things off to avoid 32 bit limits\n\t\t\tbuffers = 0;\n\t\t\tpaintedtime = fullsamples;\n\t\t\tS_StopAllSounds (true);\n\t\t}\n\t}\n\toldsamplepos = samplepos;\n\n\tsoundtime = buffers*fullsamples + samplepos/shm->channels;\n#endif\n}\n\nvoid S_ExtraUpdate (void)\n{\n\n#ifdef _WIN32\n\tIN_Accumulate ();\n#endif\n\n\tif (snd_noextraupdate.value)\n\t\treturn;\t\t// don't pollute timings\n\tS_Update_();\n}\n\nvoid S_Update_(void)\n{\n\tunsigned        endtime;\n\tint\t\t\t\tsamps;\n\t\n\tif (!sound_started || (snd_blocked > 0))\n\t\treturn;\n\n// Updates DMA time\n\tGetSoundtime();\n\n// check to make sure that we haven't overshot\n\tif (paintedtime < soundtime)\n\t{\n\t\t//Con_Printf (\"S_Update_ : overflow\\n\");\n\t\tpaintedtime = soundtime;\n\t}\n\n// mix ahead of current position\n\tendtime = soundtime + _snd_mixahead.value * shm->speed;\n\tsamps = shm->samples >> (shm->channels-1);\n\tif (endtime - soundtime > samps)\n\t\tendtime = soundtime + samps;\n\n#ifdef _WIN32\n// if the buffer was lost or stopped, restore it and/or restart it\n\t{\n\t\tDWORD\tdwStatus;\n\n\t\tif (pDSBuf)\n\t\t{\n\t\t\tif (pDSBuf->lpVtbl->GetStatus (pDSBuf, &dwStatus) != DD_OK)\n\t\t\t\tCon_Printf (\"Couldn't get sound buffer status\\n\");\n\t\t\t\n\t\t\tif (dwStatus & DSBSTATUS_BUFFERLOST)\n\t\t\t\tpDSBuf->lpVtbl->Restore (pDSBuf);\n\t\t\t\n\t\t\tif (!(dwStatus & DSBSTATUS_PLAYING))\n\t\t\t\tpDSBuf->lpVtbl->Play(pDSBuf, 0, 0, DSBPLAY_LOOPING);\n\t\t}\n\t}\n#endif\n\n\tS_PaintChannels (endtime);\n\n\tSNDDMA_Submit ();\n}\n\n/*\n===============================================================================\n\nconsole functions\n\n===============================================================================\n*/\n\nvoid S_Play(void)\n{\n\tstatic int hash=345;\n\tint \ti;\n\tchar name[256];\n\tsfx_t\t*sfx;\n\t\n\ti = 1;\n\twhile (i<Cmd_Argc())\n\t{\n\t\tif (!strrchr(Cmd_Argv(i), '.'))\n\t\t{\n\t\t\tstrcpy(name, Cmd_Argv(i));\n\t\t\tstrcat(name, \".wav\");\n\t\t}\n\t\telse\n\t\t\tstrcpy(name, Cmd_Argv(i));\n\t\tsfx = S_PrecacheSound(name);\n\t\tS_StartSound(hash++, 0, sfx, listener_origin, 1.0, 1.0);\n\t\ti++;\n\t}\n}\n\nvoid S_PlayVol(void)\n{\n\tstatic int hash=543;\n\tint i;\n\tfloat vol;\n\tchar name[256];\n\tsfx_t\t*sfx;\n\t\n\ti = 1;\n\twhile (i<Cmd_Argc())\n\t{\n\t\tif (!strrchr(Cmd_Argv(i), '.'))\n\t\t{\n\t\t\tstrcpy(name, Cmd_Argv(i));\n\t\t\tstrcat(name, \".wav\");\n\t\t}\n\t\telse\n\t\t\tstrcpy(name, Cmd_Argv(i));\n\t\tsfx = S_PrecacheSound(name);\n\t\tvol = atof(Cmd_Argv(i+1));\n\t\tS_StartSound(hash++, 0, sfx, listener_origin, vol, 1.0);\n\t\ti+=2;\n\t}\n}\n\nvoid S_SoundList(void)\n{\n\tint\t\ti;\n\tsfx_t\t*sfx;\n\tsfxcache_t\t*sc;\n\tint\t\tsize, total;\n\n\ttotal = 0;\n\tfor (sfx=known_sfx, i=0 ; i<num_sfx ; i++, sfx++)\n\t{\n\t\tsc = Cache_Check (&sfx->cache);\n\t\tif (!sc)\n\t\t\tcontinue;\n\t\tsize = sc->length*sc->width*(sc->stereo+1);\n\t\ttotal += size;\n\t\tif (sc->loopstart >= 0)\n\t\t\tCon_Printf (\"L\");\n\t\telse\n\t\t\tCon_Printf (\" \");\n\t\tCon_Printf(\"(%2db) %6i : %s\\n\",sc->width*8,  size, sfx->name);\n\t}\n\tCon_Printf (\"Total resident: %i\\n\", total);\n}\n\n\nvoid S_LocalSound (char *sound)\n{\n\tsfx_t\t*sfx;\n\n\tif (nosound.value)\n\t\treturn;\n\tif (!sound_started)\n\t\treturn;\n\t\t\n\tsfx = S_PrecacheSound (sound);\n\tif (!sfx)\n\t{\n\t\tCon_Printf (\"S_LocalSound: can't cache %s\\n\", sound);\n\t\treturn;\n\t}\n\tS_StartSound (cl.viewentity, -1, sfx, vec3_origin, 1, 1);\n}\n\n\nvoid S_ClearPrecache (void)\n{\n}\n\n\nvoid S_BeginPrecaching (void)\n{\n}\n\n\nvoid S_EndPrecaching (void)\n{\n}\n\n"
  },
  {
    "path": "source/snd_mem.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// snd_mem.c: sound caching\n\n#include \"quakedef.h\"\n\nint\t\t\tcache_full_cycle;\n\nbyte *S_Alloc (int size);\n\n/*\n================\nResampleSfx\n================\n*/\nvoid ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)\n{\n\tint\t\toutcount;\n\tint\t\tsrcsample;\n\tfloat\tstepscale;\n\tint\t\ti;\n\tint\t\tsample, samplefrac, fracstep;\n\tsfxcache_t\t*sc;\n\t\n\tsc = Cache_Check (&sfx->cache);\n\tif (!sc)\n\t\treturn;\n\n\tstepscale = (float)inrate / shm->speed;\t// this is usually 0.5, 1, or 2\n\n\toutcount = sc->length / stepscale;\n\tsc->length = outcount;\n\tif (sc->loopstart != -1)\n\t\tsc->loopstart = sc->loopstart / stepscale;\n\n\tsc->speed = shm->speed;\n\tif (loadas8bit.value)\n\t\tsc->width = 1;\n\telse\n\t\tsc->width = inwidth;\n\tsc->stereo = 0;\n\n// resample / decimate to the current source rate\n\n\tif (stepscale == 1 && inwidth == 1 && sc->width == 1)\n\t{\n// fast special case\n\t\tfor (i=0 ; i<outcount ; i++)\n\t\t\t((signed char *)sc->data)[i]\n\t\t\t= (int)( (unsigned char)(data[i]) - 128);\n\t}\n\telse\n\t{\n// general case\n\t\tsamplefrac = 0;\n\t\tfracstep = stepscale*256;\n\t\tfor (i=0 ; i<outcount ; i++)\n\t\t{\n\t\t\tsrcsample = samplefrac >> 8;\n\t\t\tsamplefrac += fracstep;\n\t\t\tif (inwidth == 2)\n\t\t\t\tsample = LittleShort ( ((short *)data)[srcsample] );\n\t\t\telse\n\t\t\t\tsample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;\n\t\t\tif (sc->width == 2)\n\t\t\t\t((short *)sc->data)[i] = sample;\n\t\t\telse\n\t\t\t\t((signed char *)sc->data)[i] = sample >> 8;\n\t\t}\n\t}\n}\n\n//=============================================================================\n\n/*\n==============\nS_LoadSound\n==============\n*/\nsfxcache_t *S_LoadSound (sfx_t *s)\n{\n    char\tnamebuffer[256];\n\tbyte\t*data;\n\twavinfo_t\tinfo;\n\tint\t\tlen;\n\tfloat\tstepscale;\n\tsfxcache_t\t*sc;\n\tbyte\tstackbuf[1*1024];\t\t// avoid dirtying the cache heap\n\n// see if still in memory\n\tsc = Cache_Check (&s->cache);\n\tif (sc)\n\t\treturn sc;\n\n//Con_Printf (\"S_LoadSound: %x\\n\", (int)stackbuf);\n// load it in\n    strcpy(namebuffer, \"sound/\");\n    strcat(namebuffer, s->name);\n\n//\tCon_Printf (\"loading %s\\n\",namebuffer);\n\n\tdata = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf), NULL);\n\n\tif (!data)\n\t{\n\t\tCon_Printf (\"Couldn't load %s\\n\", namebuffer);\n\t\treturn NULL;\n\t}\n\n\tinfo = GetWavinfo (s->name, data, com_filesize);\n\tif (info.channels != 1)\n\t{\n\t\tCon_Printf (\"%s is a stereo sample\\n\",s->name);\n\t\treturn NULL;\n\t}\n\n\tstepscale = (float)info.rate / shm->speed;\t\n\tlen = info.samples / stepscale;\n\n\tlen = len * info.width * info.channels;\n\n\tsc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);\n\tif (!sc)\n\t\treturn NULL;\n\t\n\tsc->length = info.samples;\n\tsc->loopstart = info.loopstart;\n\tsc->speed = info.rate;\n\tsc->width = info.width;\n\tsc->stereo = info.channels;\n\n\tResampleSfx (s, sc->speed, sc->width, data + info.dataofs);\n\n\treturn sc;\n}\n\n\n\n/*\n===============================================================================\n\nWAV loading\n\n===============================================================================\n*/\n\n\nbyte\t*data_p;\nbyte \t*iff_end;\nbyte \t*last_chunk;\nbyte \t*iff_data;\nint \tiff_chunk_len;\n\n\nshort 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\nint 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\nvoid 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\tif (iff_chunk_len > 1024*1024)\n//\t\t\tSys_Error (\"FindNextChunk: %i length is past the 1 meg sanity limit\", iff_chunk_len);\n\t\tdata_p -= 8;\n\t\tlast_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );\n\t\tif (!strncmp(data_p, name, 4))\n\t\t\treturn;\n\t}\n}\n\nvoid FindChunk(char *name)\n{\n\tlast_chunk = iff_data;\n\tFindNextChunk (name);\n}\n\n\nvoid DumpChunks(void)\n{\n\tchar\tstr[5];\n\t\n\tstr[4] = 0;\n\tdata_p=iff_data;\n\tdo\n\t{\n\t\tmemcpy (str, data_p, 4);\n\t\tdata_p += 4;\n\t\tiff_chunk_len = GetLittleLong();\n\t\tCon_Printf (\"0x%x : %s (%d)\\n\", (int)(data_p - 4), str, iff_chunk_len);\n\t\tdata_p += (iff_chunk_len + 1) & ~1;\n\t} while (data_p < iff_end);\n}\n\n/*\n============\nGetWavinfo\n============\n*/\nwavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)\n{\n\twavinfo_t\tinfo;\n\tint     i;\n\tint     format;\n\tint\t\tsamples;\n\n\tmemset (&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(data_p+8, \"WAVE\", 4)))\n\t{\n\t\tCon_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\tCon_Printf(\"Missing fmt chunk\\n\");\n\t\treturn info;\n\t}\n\tdata_p += 8;\n\tformat = GetLittleShort();\n\tif (format != 1)\n\t{\n\t\tCon_Printf(\"Microsoft PCM format only\\n\");\n\t\treturn info;\n\t}\n\n\tinfo.channels = GetLittleShort();\n\tinfo.rate = GetLittleLong();\n\tdata_p += 4+2;\n\tinfo.width = GetLittleShort() / 8;\n\n// get cue chunk\n\tFindChunk(\"cue \");\n\tif (data_p)\n\t{\n\t\tdata_p += 32;\n\t\tinfo.loopstart = GetLittleLong();\n//\t\tCon_Printf(\"loopstart=%d\\n\", sfx->loopstart);\n\n\t// if the next chunk is a LIST chunk, look for a cue length marker\n\t\tFindNextChunk (\"LIST\");\n\t\tif (data_p)\n\t\t{\n\t\t\tif (!strncmp (data_p + 28, \"mark\", 4))\n\t\t\t{\t// this is not a proper parse, but it works with cooledit...\n\t\t\t\tdata_p += 24;\n\t\t\t\ti = GetLittleLong ();\t// samples in loop\n\t\t\t\tinfo.samples = info.loopstart + i;\n//\t\t\t\tCon_Printf(\"looped length: %i\\n\", i);\n\t\t\t}\n\t\t}\n\t}\n\telse\n\t\tinfo.loopstart = -1;\n\n// find data chunk\n\tFindChunk(\"data\");\n\tif (!data_p)\n\t{\n\t\tCon_Printf(\"Missing data chunk\\n\");\n\t\treturn info;\n\t}\n\n\tdata_p += 4;\n\tsamples = GetLittleLong () / info.width;\n\n\tif (info.samples)\n\t{\n\t\tif (samples < info.samples)\n\t\t\tSys_Error (\"Sound %s has a bad loop length\", name);\n\t}\n\telse\n\t\tinfo.samples = samples;\n\n\tinfo.dataofs = data_p - wav;\n\t\n\treturn info;\n}\n\n"
  },
  {
    "path": "source/snd_mix.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// snd_mix.c -- portable code to mix sounds for snd_dma.c\n\n#include \"quakedef.h\"\n\n#define DWORD\tunsigned long\n\n#define\tPAINTBUFFER_SIZE\t512\nportable_samplepair_t paintbuffer[PAINTBUFFER_SIZE];\nint\t\tsnd_scaletable[32][256];\nint \t*snd_p, snd_linear_count, snd_vol;\nshort\t*snd_out;\n\nvoid Snd_WriteLinearBlastStereo16 (void);\n\n#if\t!id386\nvoid Snd_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]*snd_vol)>>8;\n\t\tif (val > 0x7fff)\n\t\t\tsnd_out[i] = 0x7fff;\n\t\telse if (val < (short)0x8000)\n\t\t\tsnd_out[i] = (short)0x8000;\n\t\telse\n\t\t\tsnd_out[i] = val;\n\n\t\tval = (snd_p[i+1]*snd_vol)>>8;\n\t\tif (val > 0x7fff)\n\t\t\tsnd_out[i+1] = 0x7fff;\n\t\telse if (val < (short)0x8000)\n\t\t\tsnd_out[i+1] = (short)0x8000;\n\t\telse\n\t\t\tsnd_out[i+1] = val;\n\t}\n}\n#endif\n\nvoid S_TransferStereo16 (int endtime)\n{\n\tint\t\tlpos;\n\tint\t\tlpaintedtime;\n\tDWORD\t*pbuf;\n#ifdef _WIN32\n\tint\t\treps;\n\tDWORD\tdwSize,dwSize2;\n\tDWORD\t*pbuf2;\n\tHRESULT\thresult;\n#endif\n\t\n\tsnd_vol = volume.value*256;\n\n\tsnd_p = (int *) paintbuffer;\n\tlpaintedtime = paintedtime;\n\n#ifdef _WIN32\n\tif (pDSBuf)\n\t{\n\t\treps = 0;\n\n\t\twhile ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, \n\t\t\t\t\t\t\t\t\t   &pbuf2, &dwSize2, 0)) != DS_OK)\n\t\t{\n\t\t\tif (hresult != DSERR_BUFFERLOST)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_TransferStereo16: DS::Lock Sound Buffer Failed\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\tS_Startup ();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (++reps > 10000)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_TransferStereo16: DS: couldn't restore buffer\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\tS_Startup ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse\n#endif\n\t{\n\t\tpbuf = (DWORD *)shm->buffer;\n\t}\n\n\twhile (lpaintedtime < endtime)\n\t{\n\t// handle recirculating buffer issues\n\t\tlpos = lpaintedtime & ((shm->samples>>1)-1);\n\n\t\tsnd_out = (short *) pbuf + (lpos<<1);\n\n\t\tsnd_linear_count = (shm->samples>>1) - lpos;\n\t\tif (lpaintedtime + snd_linear_count > endtime)\n\t\t\tsnd_linear_count = endtime - lpaintedtime;\n\n\t\tsnd_linear_count <<= 1;\n\n\t// write a linear blast of samples\n\t\tSnd_WriteLinearBlastStereo16 ();\n\n\t\tsnd_p += snd_linear_count;\n\t\tlpaintedtime += (snd_linear_count>>1);\n\t}\n\n#ifdef _WIN32\n\tif (pDSBuf)\n\t\tpDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);\n#endif\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\tint\t\tsnd_vol;\n\tDWORD\t*pbuf;\n#ifdef _WIN32\n\tint\t\treps;\n\tDWORD\tdwSize,dwSize2;\n\tDWORD\t*pbuf2;\n\tHRESULT\thresult;\n#endif\n\n\tif (shm->samplebits == 16 && shm->channels == 2)\n\t{\n\t\tS_TransferStereo16 (endtime);\n\t\treturn;\n\t}\n\t\n\tp = (int *) paintbuffer;\n\tcount = (endtime - paintedtime) * shm->channels;\n\tout_mask = shm->samples - 1; \n\tout_idx = paintedtime * shm->channels & out_mask;\n\tstep = 3 - shm->channels;\n\tsnd_vol = volume.value*256;\n\n#ifdef _WIN32\n\tif (pDSBuf)\n\t{\n\t\treps = 0;\n\n\t\twhile ((hresult = pDSBuf->lpVtbl->Lock(pDSBuf, 0, gSndBufSize, &pbuf, &dwSize, \n\t\t\t\t\t\t\t\t\t   &pbuf2,&dwSize2, 0)) != DS_OK)\n\t\t{\n\t\t\tif (hresult != DSERR_BUFFERLOST)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_TransferPaintBuffer: DS::Lock Sound Buffer Failed\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\tS_Startup ();\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (++reps > 10000)\n\t\t\t{\n\t\t\t\tCon_Printf (\"S_TransferPaintBuffer: DS: couldn't restore buffer\\n\");\n\t\t\t\tS_Shutdown ();\n\t\t\t\tS_Startup ();\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\t}\n\telse\n#endif\n\t{\n\t\tpbuf = (DWORD *)shm->buffer;\n\t}\n\n\tif (shm->samplebits == 16)\n\t{\n\t\tshort *out = (short *) pbuf;\n\t\twhile (count--)\n\t\t{\n\t\t\tval = (*p * snd_vol) >> 8;\n\t\t\tp+= step;\n\t\t\tif (val > 0x7fff)\n\t\t\t\tval = 0x7fff;\n\t\t\telse if (val < (short)0x8000)\n\t\t\t\tval = (short)0x8000;\n\t\t\tout[out_idx] = val;\n\t\t\tout_idx = (out_idx + 1) & out_mask;\n\t\t}\n\t}\n\telse if (shm->samplebits == 8)\n\t{\n\t\tunsigned char *out = (unsigned char *) pbuf;\n\t\twhile (count--)\n\t\t{\n\t\t\tval = (*p * snd_vol) >> 8;\n\t\t\tp+= step;\n\t\t\tif (val > 0x7fff)\n\t\t\t\tval = 0x7fff;\n\t\t\telse if (val < (short)0x8000)\n\t\t\t\tval = (short)0x8000;\n\t\t\tout[out_idx] = (val>>8) + 128;\n\t\t\tout_idx = (out_idx + 1) & out_mask;\n\t\t}\n\t}\n\n#ifdef _WIN32\n\tif (pDSBuf) {\n\t\tDWORD dwNewpos, dwWrite;\n\t\tint il = paintedtime;\n\t\tint ir = endtime - paintedtime;\n\t\t\n\t\tir += il;\n\n\t\tpDSBuf->lpVtbl->Unlock(pDSBuf, pbuf, dwSize, NULL, 0);\n\n\t\tpDSBuf->lpVtbl->GetCurrentPosition(pDSBuf, &dwNewpos, &dwWrite);\n\n//\t\tif ((dwNewpos >= il) && (dwNewpos <= ir))\n//\t\t\tCon_Printf(\"%d-%d p %d c\\n\", il, ir, dwNewpos);\n\t}\n#endif\n}\n\n\n/*\n===============================================================================\n\nCHANNEL MIXING\n\n===============================================================================\n*/\n\nvoid SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int endtime);\nvoid SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int endtime);\n\nvoid S_PaintChannels(int endtime)\n{\n\tint \ti;\n\tint \tend;\n\tchannel_t *ch;\n\tsfxcache_t\t*sc;\n\tint\t\tltime, count;\n\n\twhile (paintedtime < endtime)\n\t{\n\t// if paintbuffer is smaller than DMA buffer\n\t\tend = endtime;\n\t\tif (endtime - paintedtime > PAINTBUFFER_SIZE)\n\t\t\tend = paintedtime + PAINTBUFFER_SIZE;\n\n\t// clear the paint buffer\n\t\tmemset(paintbuffer, 0, (end - paintedtime) * sizeof(portable_samplepair_t));\n\n\t// paint in the channels.\n\t\tch = channels;\n\t\tfor (i=0; i<total_channels ; i++, ch++)\n\t\t{\n\t\t\tif (!ch->sfx)\n\t\t\t\tcontinue;\n\t\t\tif (!ch->leftvol && !ch->rightvol)\n\t\t\t\tcontinue;\n\t\t\tsc = S_LoadSound (ch->sfx);\n\t\t\tif (!sc)\n\t\t\t\tcontinue;\n\n\t\t\tltime = paintedtime;\n\n\t\t\twhile (ltime < end)\n\t\t\t{\t// paint up to end\n\t\t\t\tif (ch->end < end)\n\t\t\t\t\tcount = ch->end - ltime;\n\t\t\t\telse\n\t\t\t\t\tcount = end - ltime;\n\n\t\t\t\tif (count > 0)\n\t\t\t\t{\t\n\t\t\t\t\tif (sc->width == 1)\n\t\t\t\t\t\tSND_PaintChannelFrom8(ch, sc, count);\n\t\t\t\t\telse\n\t\t\t\t\t\tSND_PaintChannelFrom16(ch, sc, count);\n\t\n\t\t\t\t\tltime += count;\n\t\t\t\t}\n\n\t\t\t// if at end of loop, restart\n\t\t\t\tif (ltime >= ch->end)\n\t\t\t\t{\n\t\t\t\t\tif (sc->loopstart >= 0)\n\t\t\t\t\t{\n\t\t\t\t\t\tch->pos = sc->loopstart;\n\t\t\t\t\t\tch->end = ltime + sc->length - ch->pos;\n\t\t\t\t\t}\n\t\t\t\t\telse\t\t\t\t\n\t\t\t\t\t{\t// channel just stopped\n\t\t\t\t\t\tch->sfx = NULL;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t  \n\t\t}\n\n\t// transfer out according to DMA format\n\t\tS_TransferPaintBuffer(end);\n\t\tpaintedtime = end;\n\t}\n}\n\nvoid SND_InitScaletable (void)\n{\n\tint\t\ti, j;\n\t\n\tfor (i=0 ; i<32 ; i++)\n\t\tfor (j=0 ; j<256 ; j++)\n\t\t\tsnd_scaletable[i][j] = ((signed char)j) * i * 8;\n}\n\n\n#if\t!id386\n\nvoid SND_PaintChannelFrom8 (channel_t *ch, sfxcache_t *sc, int count)\n{\n\tint \tdata;\n\tint\t\t*lscale, *rscale;\n\tunsigned char *sfx;\n\tint\t\ti;\n\n\tif (ch->leftvol > 255)\n\t\tch->leftvol = 255;\n\tif (ch->rightvol > 255)\n\t\tch->rightvol = 255;\n\t\t\n\tlscale = snd_scaletable[ch->leftvol >> 3];\n\trscale = snd_scaletable[ch->rightvol >> 3];\n\tsfx = (signed char *)sc->data + ch->pos;\n\n\tfor (i=0 ; i<count ; i++)\n\t{\n\t\tdata = sfx[i];\n\t\tpaintbuffer[i].left += lscale[data];\n\t\tpaintbuffer[i].right += rscale[data];\n\t}\n\t\n\tch->pos += count;\n}\n\n#endif\t// !id386\n\n\nvoid SND_PaintChannelFrom16 (channel_t *ch, sfxcache_t *sc, int count)\n{\n\tint data;\n\tint left, right;\n\tint leftvol, rightvol;\n\tsigned short *sfx;\n\tint\ti;\n\n\tleftvol = ch->leftvol;\n\trightvol = ch->rightvol;\n\tsfx = (signed short *)sc->data + ch->pos;\n\n\tfor (i=0 ; i<count ; i++)\n\t{\n\t\tdata = sfx[i];\n\t\tleft = (data * leftvol) >> 8;\n\t\tright = (data * rightvol) >> 8;\n\t\tpaintbuffer[i].left += left;\n\t\tpaintbuffer[i].right += right;\n\t}\n\n\tch->pos += count;\n}\n\n"
  },
  {
    "path": "source/snd_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n*/\n#include <stdio.h>\n#include <vitasdk.h>\n#include \"quakedef.h\"\n\n#define u64 uint64_t\n#define u8 uint8_t\n\n#define SAMPLE_RATE (48000)\n#define AUDIOSIZE (16384)\n\nu8 *audiobuffer;\nSceRtcTick initial_tick;\nint snd_inited;\nint chn = -1;\nint stop_audio = false;\n//int update = false;\nfloat tickRate;\n\nstatic int audio_thread(int args, void *argp)\n{\n\tchn = sceAudioOutOpenPort(SCE_AUDIO_OUT_PORT_TYPE_MAIN, AUDIOSIZE / 2, SAMPLE_RATE, SCE_AUDIO_OUT_MODE_MONO);\n\tsceAudioOutSetConfig(chn, -1, -1, -1);\n\tint vol[] = {32767, 32767};\n    sceAudioOutSetVolume(chn, SCE_AUDIO_VOLUME_FLAG_L_CH | SCE_AUDIO_VOLUME_FLAG_R_CH, vol);\n\t\n    while (!stop_audio)\n    {\n\t\tsceAudioOutOutput(chn, audiobuffer);\n    }\n\t \n\tsceAudioOutReleasePort(chn);\n    free(audiobuffer);\n\n    sceKernelExitDeleteThread(0);\n    return 0;\n}\n\nbool SNDDMA_Init(void)\n{\n\taudiobuffer = malloc(AUDIOSIZE);\n\tmemset(audiobuffer, 0, AUDIOSIZE);\n\n\t/* Fill the audio DMA information block */\n\tshm = &sn;\n\tshm->splitbuffer = 0;\n\tshm->samplebits = 16;\n\tshm->speed = SAMPLE_RATE;\n\tshm->channels = 1;\n\tshm->samples = AUDIOSIZE / (shm->samplebits / 8);\n\tshm->samplepos = 0;\n\tshm->submission_chunk = 1;\n\tshm->buffer = audiobuffer;\n\t\n\ttickRate = 1.0f / sceRtcGetTickResolution();\n\t\n\tSceUID audiothread = sceKernelCreateThread(\"Audio Thread\", (void*)&audio_thread, 0x10000100, 0x10000, 0, 0, NULL);\n\tint res = sceKernelStartThread(audiothread, sizeof(audiothread), &audiothread);\n\tif (res != 0){\n\t\tSys_Error(\"Failed to init audio thread (0x%x)\", res);\n\t\treturn 0;\n\t}\n\t\n\tsceRtcGetCurrentTick(&initial_tick);\n\n\tsnd_initialized = 1;\n\treturn 1;\n}\n\nint SNDDMA_GetDMAPos(void)\n{\n\tif (!snd_initialized)\n\t\treturn 0;\n\n\tSceRtcTick tick;\n\tsceRtcGetCurrentTick(&tick);\n\tconst unsigned int deltaTick  = tick.tick - initial_tick.tick;\n\tconst float deltaSecond = deltaTick * tickRate;\n\tu64 samplepos = deltaSecond * SAMPLE_RATE;\n\tshm->samplepos = samplepos;\n\treturn samplepos;\n}\n\nvoid SNDDMA_Shutdown(void)\n{\n\tif(snd_initialized){\n\t\tstop_audio = true;\n\t\tchn = -1;\n\t}\n}\n\n/*\n==============\nSNDDMA_Submit\nSend sound to device if buffer isn't really the dma buffer\n===============\n*/\nvoid SNDDMA_Submit(void)\n{\n  //if(snd_initialized)\n\t//update = true;\n}"
  },
  {
    "path": "source/sound.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sound.h -- client sound i/o functions\n\n#ifndef __SOUND__\n#define __SOUND__\n\n#define DEFAULT_SOUND_PACKET_VOLUME 255\n#define DEFAULT_SOUND_PACKET_ATTENUATION 1.0\n\n// !!! if this is changed, it much be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tint left;\n\tint right;\n} portable_samplepair_t;\n\ntypedef struct sfx_s\n{\n\tchar \tname[MAX_QPATH];\n\tcache_user_t\tcache;\n} sfx_t;\n\n// !!! if this is changed, it much be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tint \tlength;\n\tint \tloopstart;\n\tint \tspeed;\n\tint \twidth;\n\tint \tstereo;\n\tbyte\tdata[1];\t\t// variable sized\n} sfxcache_t;\n\ntypedef struct\n{\n\tbool\t\tgamealive;\n\tbool\t\tsoundalive;\n\tbool\t\tsplitbuffer;\n\tint\t\t\t\tchannels;\n\tint\t\t\t\tsamples;\t\t\t\t// mono samples in buffer\n\tint\t\t\t\tsubmission_chunk;\t\t// don't mix less than this #\n\tint\t\t\t\tsamplepos;\t\t\t\t// in mono samples\n\tint\t\t\t\tsamplebits;\n\tint\t\t\t\tspeed;\n\tunsigned char\t*buffer;\n} dma_t;\n\n// !!! if this is changed, it much be changed in asm_i386.h too !!!\ntypedef struct\n{\n\tsfx_t\t*sfx;\t\t\t// sfx number\n\tint\t\tleftvol;\t\t// 0-255 volume\n\tint\t\trightvol;\t\t// 0-255 volume\n\tint\t\tend;\t\t\t// end time in global paintsamples\n\tint \tpos;\t\t\t// sample position in sfx\n\tint\t\tlooping;\t\t// where to loop, -1 = no looping\n\tint\t\tentnum;\t\t\t// to allow overriding a specific sound\n\tint\t\tentchannel;\t\t//\n\tvec3_t\torigin;\t\t\t// origin of sound effect\n\tvec_t\tdist_mult;\t\t// distance multiplier (attenuation/clipK)\n\tint\t\tmaster_vol;\t\t// 0-255 master volume\n} channel_t;\n\ntypedef struct\n{\n\tint\t\trate;\n\tint\t\twidth;\n\tint\t\tchannels;\n\tint\t\tloopstart;\n\tint\t\tsamples;\n\tint\t\tdataofs;\t\t// chunk starts this many bytes from file start\n} wavinfo_t;\n\nvoid S_Init (void);\nvoid S_Startup (void);\nvoid S_Shutdown (void);\nvoid S_StartSound (int entnum, int entchannel, sfx_t *sfx, vec3_t origin, float fvol,  float attenuation);\nvoid S_StaticSound (sfx_t *sfx, vec3_t origin, float vol, float attenuation);\nvoid S_StopSound (int entnum, int entchannel);\nvoid S_StopAllSounds(bool clear);\nvoid S_ClearBuffer (void);\nvoid S_Update (vec3_t origin, vec3_t v_forward, vec3_t v_right, vec3_t v_up);\nvoid S_ExtraUpdate (void);\n\nsfx_t *S_PrecacheSound (char *sample);\nvoid S_TouchSound (char *sample);\nvoid S_ClearPrecache (void);\nvoid S_BeginPrecaching (void);\nvoid S_EndPrecaching (void);\nvoid S_PaintChannels(int endtime);\nvoid S_InitPaintChannels (void);\n\n// picks a channel based on priorities, empty slots, number of channels\nchannel_t *SND_PickChannel(int entnum, int entchannel);\n\n// spatializes a channel\nvoid SND_Spatialize(channel_t *ch);\n\n// initializes cycling through a DMA buffer and returns information on it\nbool SNDDMA_Init(void);\n\n// gets the current DMA position\nint SNDDMA_GetDMAPos(void);\n\n// shutdown the DMA xfer.\nvoid SNDDMA_Shutdown(void);\n\n// ====================================================================\n// User-setable variables\n// ====================================================================\n\n#define\tMAX_CHANNELS\t\t\t128\n#define\tMAX_DYNAMIC_CHANNELS\t8\n\n\nextern\tchannel_t   channels[MAX_CHANNELS];\n// 0 to MAX_DYNAMIC_CHANNELS-1\t= normal entity sounds\n// MAX_DYNAMIC_CHANNELS to MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS -1 = water, etc\n// MAX_DYNAMIC_CHANNELS + NUM_AMBIENTS to total_channels = static sounds\n\nextern\tint\t\t\ttotal_channels;\n\n//\n// Fake dma is a synchronous faking of the DMA progress used for\n// isolating performance in the renderer.  The fakedma_updates is\n// number of times S_Update() is called per second.\n//\n\nextern bool \t\tfakedma;\nextern int \t\t\tfakedma_updates;\nextern int\t\tpaintedtime;\nextern vec3_t listener_origin;\nextern vec3_t listener_forward;\nextern vec3_t listener_right;\nextern vec3_t listener_up;\nextern volatile dma_t *shm;\nextern volatile dma_t sn;\nextern vec_t sound_nominal_clip_dist;\n\nextern\tcvar_t loadas8bit;\nextern\tcvar_t bgmvolume;\nextern\tcvar_t volume;\n\nextern bool\tsnd_initialized;\n\nextern int\t\tsnd_blocked;\n\nvoid S_LocalSound (char *s);\nsfxcache_t *S_LoadSound (sfx_t *s);\n\nwavinfo_t GetWavinfo (char *name, byte *wav, int wavlength);\n\nvoid SND_InitScaletable (void);\nvoid SNDDMA_Submit(void);\n\nvoid S_AmbientOff (void);\nvoid S_AmbientOn (void);\n\n#endif\n"
  },
  {
    "path": "source/spritegn.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n//\n// spritegn.h: header file for sprite generation program\n//\n\n// **********************************************************\n// * This file must be identical in the spritegen directory *\n// * and in the Quake directory, because it's used to       *\n// * pass data from one to the other via .spr files.        *\n// **********************************************************\n\n//-------------------------------------------------------\n// This program generates .spr sprite package files.\n// The format of the files is as follows:\n//\n// dsprite_t file header structure\n// <repeat dsprite_t.numframes times>\n//   <if spritegroup, repeat dspritegroup_t.numframes times>\n//     dspriteframe_t frame header structure\n//     sprite bitmap\n//   <else (single sprite frame)>\n//     dspriteframe_t frame header structure\n//     sprite bitmap\n// <endrepeat>\n//-------------------------------------------------------\n\n#ifdef INCLUDELIBS\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <math.h>\n#include <string.h>\n\n#include \"cmdlib.h\"\n#include \"scriplib.h\"\n#include \"dictlib.h\"\n#include \"trilib.h\"\n#include \"lbmlib.h\"\n#include \"mathlib.h\"\n\n#endif\n\n#define SPRITE_VERSION\t1\n\n// must match definition in modelgen.h\n#ifndef SYNCTYPE_T\n#define SYNCTYPE_T\ntypedef enum {ST_SYNC=0, ST_RAND } synctype_t;\n#endif\n\n// TODO: shorten these?\ntypedef struct {\n\tint\t\t\tident;\n\tint\t\t\tversion;\n\tint\t\t\ttype;\n\tfloat\t\tboundingradius;\n\tint\t\t\twidth;\n\tint\t\t\theight;\n\tint\t\t\tnumframes;\n\tfloat\t\tbeamlength;\n\tsynctype_t\tsynctype;\n} dsprite_t;\n\n#define SPR_VP_PARALLEL_UPRIGHT\t\t0\n#define SPR_FACING_UPRIGHT\t\t\t1\n#define SPR_VP_PARALLEL\t\t\t\t2\n#define SPR_ORIENTED\t\t\t\t3\n#define SPR_VP_PARALLEL_ORIENTED\t4\n\ntypedef struct {\n\tint\t\t\torigin[2];\n\tint\t\t\twidth;\n\tint\t\t\theight;\n} dspriteframe_t;\n\ntypedef struct {\n\tint\t\t\tnumframes;\n} dspritegroup_t;\n\ntypedef struct {\n\tfloat\tinterval;\n} dspriteinterval_t;\n\ntypedef enum { SPR_SINGLE=0, SPR_GROUP } spriteframetype_t;\n\ntypedef struct {\n\tint\ttype;\n} dspriteframetype_t;\n\n#define IDSPRITEHEADER\t(('P'<<24)+('S'<<16)+('D'<<8)+'I')\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t// little-endian \"IDSP\"\n"
  },
  {
    "path": "source/sv_main.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sv_main.c -- server main program\n\n#include \"quakedef.h\"\n\nserver_t\t\tsv;\nserver_static_t\tsvs;\n\ncvar_t sv_progs = {\"sv_progs\", \"progs.dat\"};\n\n#define MODSTRLEN (sizeof(\"*\" stringify(MAX_MODELS)) / sizeof(char))\nchar localmodels[MAX_MODELS][MODSTRLEN]; // inline model names for precache\n\n//============================================================================\n\n/*\n===============\nSV_Init\n===============\n*/\nvoid SV_Init (void)\n{\n\tint\t\ti;\n\textern\tcvar_t\tsv_maxvelocity;\n\textern\tcvar_t\tsv_gravity;\n\textern\tcvar_t\tsv_nostep;\n\textern\tcvar_t\tsv_friction;\n\textern\tcvar_t\tsv_edgefriction;\n\textern\tcvar_t\tsv_stopspeed;\n\textern\tcvar_t\tsv_maxspeed;\n\textern\tcvar_t\tsv_accelerate;\n\textern\tcvar_t\tsv_idealpitchscale;\n\textern\tcvar_t\tsv_aim;\n\t\n\tCvar_RegisterVariable (&sv_maxvelocity);\n\tCvar_RegisterVariable (&sv_gravity);\n\tCvar_RegisterVariable (&sv_friction);\n\tCvar_RegisterVariable (&sv_edgefriction);\n\tCvar_RegisterVariable (&sv_stopspeed);\n\tCvar_RegisterVariable (&sv_maxspeed);\n\tCvar_RegisterVariable (&sv_accelerate);\n\tCvar_RegisterVariable (&sv_idealpitchscale);\n\tCvar_RegisterVariable (&sv_aim);\n\tCvar_RegisterVariable (&sv_nostep);\n\tCvar_RegisterVariable (&sv_progs);\n\n\tCvar_RegisterVariable(&pq_fullpitch); // JPG 2.01\n\t\n\tfor (i=0 ; i<MAX_MODELS ; i++)\n\t\tsprintf (localmodels[i], \"*%i\", i);\n}\n\n/*\n=============================================================================\n\nEVENT MESSAGES\n\n=============================================================================\n*/\n\n/*  \n==================\nSV_StartParticle\n\nMake sure the event gets sent to all clients\n==================\n*/\nvoid SV_StartParticle (vec3_t org, vec3_t dir, int color, int count)\n{\n\tint\t\ti, v;\n\n\tif (sv.datagram.cursize > MAX_DATAGRAM-16)\n\t\treturn;\t\n\tMSG_WriteByte (&sv.datagram, svc_particle);\n\tMSG_WriteCoord (&sv.datagram, org[0]);\n\tMSG_WriteCoord (&sv.datagram, org[1]);\n\tMSG_WriteCoord (&sv.datagram, org[2]);\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tv = dir[i]*16;\n\t\tif (v > 127)\n\t\t\tv = 127;\n\t\telse if (v < -128)\n\t\t\tv = -128;\n\t\tMSG_WriteChar (&sv.datagram, v);\n\t}\n\tMSG_WriteByte (&sv.datagram, count);\n\tMSG_WriteByte (&sv.datagram, color);\n}\t\t   \n\n/*  \n==================\nSV_StartSound\n\nEach entity can have eight independant sound sources, like voice,\nweapon, feet, etc.\n\nChannel 0 is an auto-allocate channel, the others override anything\nalready running on that entity/channel pair.\n\nAn attenuation of 0 will play full volume everywhere in the level.\nLarger attenuations will drop off.  (max 4 attenuation)\n\n==================\n*/  \nvoid SV_StartSound (edict_t *entity, int channel, char *sample, int volume,\n\tfloat attenuation)\n{\t   \n\tint\t\t sound_num;\n\tint field_mask;\n\tint\t\t\ti;\n\tint\t\t\tent;\n\t\n\tif (volume < 0 || volume > 255)\n\t\tSys_Error (\"SV_StartSound: volume = %i\", volume);\n\n\tif (attenuation < 0 || attenuation > 4)\n\t\tSys_Error (\"SV_StartSound: attenuation = %f\", attenuation);\n\n\tif (channel < 0 || channel > 7)\n\t\tSys_Error (\"SV_StartSound: channel = %i\", channel);\n\n\tif (sv.datagram.cursize > MAX_DATAGRAM-16)\n\t\treturn;\t\n\n// find precache number for sound\n\tfor (sound_num=1 ; sound_num<MAX_SOUNDS\n\t\t&& sv.sound_precache[sound_num] ; sound_num++)\n\t\tif (!strcmp(sample, sv.sound_precache[sound_num]))\n\t\t\tbreak;\n\t\n\tif ( sound_num == MAX_SOUNDS || !sv.sound_precache[sound_num] )\n\t{\n\t\tCon_Printf (\"SV_StartSound: %s not precacheed\\n\", sample);\n\t\treturn;\n\t}\n\t\n\tent = NUM_FOR_EDICT(entity);\n\n\tchannel = (ent<<3) | channel;\n\n\tfield_mask = 0;\n\tif (volume != DEFAULT_SOUND_PACKET_VOLUME)\n\t\tfield_mask |= SND_VOLUME;\n\tif (attenuation != DEFAULT_SOUND_PACKET_ATTENUATION)\n\t\tfield_mask |= SND_ATTENUATION;\n\n// directed messages go only to the entity the are targeted on\n\tMSG_WriteByte (&sv.datagram, svc_sound);\n\tMSG_WriteByte (&sv.datagram, field_mask);\n\tif (field_mask & SND_VOLUME)\n\t\tMSG_WriteByte (&sv.datagram, volume);\n\tif (field_mask & SND_ATTENUATION)\n\t\tMSG_WriteByte (&sv.datagram, attenuation*64);\n\tMSG_WriteShort (&sv.datagram, channel);\n\tMSG_WriteByte (&sv.datagram, sound_num);\n\tfor (i=0 ; i<3 ; i++)\n\t\tMSG_WriteCoord (&sv.datagram, entity->v.origin[i]+0.5*(entity->v.mins[i]+entity->v.maxs[i]));\n}\t\t   \n\n/*\n==============================================================================\n\nCLIENT SPAWNING\n\n==============================================================================\n*/\n\n/*\n================\nSV_SendServerinfo\n\nSends the first message from the server to a connected client.\nThis will be sent on the initial connection and upon each server load.\n================\n*/\nvoid SV_SendServerinfo (client_t *client)\n{\n\tchar\t\t\t**s;\n\tchar*\t\t\tmessage = Sys_BigStackAlloc(2048, \"SV_SendServerinfo\");\n\n\tif (svs.maxclients > 1)\n\t{\n\t\tMSG_WriteByte(&client->message, svc_print);\n\t\tsnprintf(message, sizeof(message), \"\\n\\35\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\36\\37\\n\"\n\t\t\t\"\\n   \\01\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\02\\03\");\n\t\tMSG_WriteString(&client->message, message);\n\t\tMSG_WriteByte(&client->message, svc_print);\n\t\tsnprintf(message, sizeof(message), \"\\02\\n   \\04ProQuake Server Version %4.2f\\06\"\n\t\t\t\"\\n   \\07\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\10\\11\", VERSION_PROQUAKE);\n\t\tMSG_WriteString(&client->message, message);\n\t}\n\n\tMSG_WriteByte (&client->message, svc_serverinfo);\n\tMSG_WriteLong (&client->message, PROTOCOL_NETQUAKE);\n\tMSG_WriteByte (&client->message, svs.maxclients);\n\n\tif (!coop.value && deathmatch.value)\n\t\tMSG_WriteByte (&client->message, GAME_DEATHMATCH);\n\telse\n\t\tMSG_WriteByte (&client->message, GAME_COOP);\n\n\tsprintf (message, pr_strings+sv.edicts->v.message);\n\n\tMSG_WriteString (&client->message,message);\n\n\tfor (s = sv.model_precache+1 ; *s ; s++)\n\t\tMSG_WriteString (&client->message, *s);\n\tMSG_WriteByte (&client->message, 0);\n\n\tfor (s = sv.sound_precache+1 ; *s ; s++)\n\t\tMSG_WriteString (&client->message, *s);\n\tMSG_WriteByte (&client->message, 0);\n\n// send music\n\tMSG_WriteByte (&client->message, svc_cdtrack);\n\tMSG_WriteByte (&client->message, sv.edicts->v.sounds);\n\tMSG_WriteByte (&client->message, sv.edicts->v.sounds);\n\n// set view\t\n\tMSG_WriteByte (&client->message, svc_setview);\n\tMSG_WriteShort (&client->message, NUM_FOR_EDICT(client->edict));\n\n\tif (!pq_fullpitch.value && client->netconnection->proquake_connection != MOD_QSMACK) {\t// Ch0wW: Re-add it \n\t\tMSG_WriteByte(&client->message, svc_stufftext);\n\t\tMSG_WriteString(&client->message, \"pq_fullpitch 0; cl_fullpitch 0\\n\");\n}\n\t\n\tMSG_WriteByte (&client->message, svc_signonnum);\n\tMSG_WriteByte (&client->message, 1);\n\n\tclient->sendsignon = true;\n\tclient->spawned = false;\t\t// need prespawn, spawn, etc\n\tSys_BigStackFree(2048, \"SV_SendServerinfo\");\n}\n\n/*\n================\nSV_ConnectClient\n\nInitializes a client_t for a new net connection.  This will only be called\nonce for a player each game, not once for each level change.\n================\n*/\nvoid SV_ConnectClient (int clientnum)\n{\n\tedict_t\t\t\t*ent;\n\tclient_t\t\t*client;\n\tint\t\t\t\tedictnum;\n\tstruct qsocket_s *netconnection;\n\tint\t\t\t\ti;\n\tfloat\t\t\tspawn_parms[NUM_SPAWN_PARMS];\n\n\tclient = svs.clients + clientnum;\n\n\tif (client->netconnection->proquake_connection == MOD_PROQUAKE)\n\t\tCon_DPrintf(\"ProQuake Client %s connected\\n\", client->netconnection->address);\n\telse\n\t\tCon_DPrintf (\"Client %s connected\\n\", client->netconnection->address);\n\n\tedictnum = clientnum+1;\n\n\tent = EDICT_NUM(edictnum);\n\t\n// set up the client_t\n\tnetconnection = client->netconnection;\n\t\n\tif (sv.loadgame)\n\t\tmemcpy (spawn_parms, client->spawn_parms, sizeof(spawn_parms));\n\tmemset (client, 0, sizeof(*client));\n\tclient->netconnection = netconnection;\n\n\tstrcpy (client->name, \"unconnected\");\n\tclient->active = true;\n\tclient->spawned = false;\n\tclient->edict = ent;\n\tclient->message.data = client->msgbuf;\n\tclient->message.maxsize = sizeof(client->msgbuf);\n\tclient->message.allowoverflow = true;\t\t// we can catch it\n\n#ifdef IDGODS\n\tclient->privileged = IsID(&client->netconnection->addr);\n#else\t\n\tclient->privileged = false;\t\t\t\t\n#endif\n\n\tif (sv.loadgame)\n\t\tmemcpy (client->spawn_parms, spawn_parms, sizeof(spawn_parms));\n\telse\n\t{\n\t// call the progs to get default spawn parms for the new client\n\t\tPR_ExecuteProgram (pr_global_struct->SetNewParms);\n\t\tfor (i=0 ; i<NUM_SPAWN_PARMS ; i++)\n\t\t\tclient->spawn_parms[i] = (&pr_global_struct->parm1)[i];\n\t}\n\n\tSV_SendServerinfo (client);\n}\n\n\n/*\n===================\nSV_CheckForNewClients\n\n===================\n*/\nvoid SV_CheckForNewClients (void)\n{\n\tstruct qsocket_s\t*ret;\n\tint\t\t\t\ti;\n\t\t\n//\n// check for new connections\n//\n\twhile (1)\n\t{\n\t\tret = NET_CheckNewConnections ();\n\t\tif (!ret)\n\t\t\tbreak;\n\n\t// \n\t// init a new client structure\n\t//\t\n\t\tfor (i=0 ; i<svs.maxclients ; i++)\n\t\t\tif (!svs.clients[i].active)\n\t\t\t\tbreak;\n\t\tif (i == svs.maxclients)\n\t\t\tSys_Error (\"Host_CheckForNewClients: no free clients\");\n\t\t\n\t\tsvs.clients[i].netconnection = ret;\n\t\tSV_ConnectClient (i);\t\n\t\n\t\tnet_activeconnections++;\n\t}\n}\n\n\n\n/*\n===============================================================================\n\nFRAME UPDATES\n\n===============================================================================\n*/\n\n/*\n==================\nSV_ClearDatagram\n\n==================\n*/\nvoid SV_ClearDatagram (void)\n{\n\tSZ_Clear (&sv.datagram);\n}\n\n/*\n=============================================================================\n\nThe PVS must include a small area around the client to allow head bobbing\nor other small motion on the client side.  Otherwise, a bob might cause an\nentity that should be visible to not show up, especially when the bob\ncrosses a waterline.\n\n=============================================================================\n*/\n\nint\t\tfatbytes;\nbyte\tfatpvs[MAX_MAP_LEAFS/8];\n\nvoid SV_AddToFatPVS (vec3_t org, mnode_t *node)\n{\n\tint\t\ti;\n\tbyte\t*pvs;\n\tmplane_t\t*plane;\n\tfloat\td;\n\n\twhile (1)\n\t{\n\t// if this is a leaf, accumulate the pvs bits\n\t\tif (node->contents < 0)\n\t\t{\n\t\t\tif (node->contents != CONTENTS_SOLID)\n\t\t\t{\n\t\t\t\tpvs = Mod_LeafPVS ( (mleaf_t *)node, sv.worldmodel);\n\t\t\t\tfor (i=0 ; i<fatbytes ; i++)\n\t\t\t\t\tfatpvs[i] |= pvs[i];\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\n\t\tplane = node->plane;\n\t\td = DotProduct (org, plane->normal) - plane->dist;\n\t\tif (d > 8)\n\t\t\tnode = node->children[0];\n\t\telse if (d < -8)\n\t\t\tnode = node->children[1];\n\t\telse\n\t\t{\t// go down both\n\t\t\tSV_AddToFatPVS (org, node->children[0]);\n\t\t\tnode = node->children[1];\n\t\t}\n\t}\n}\n\n/*\n=============\nSV_FatPVS\n\nCalculates a PVS that is the inclusive or of all leafs within 8 pixels of the\ngiven point.\n=============\n*/\nbyte *SV_FatPVS (vec3_t org)\n{\n\tfatbytes = (sv.worldmodel->numleafs+31)>>3;\n\tmemset (fatpvs, 0, fatbytes);\n\tSV_AddToFatPVS (org, sv.worldmodel->nodes);\n\treturn fatpvs;\n}\n\n//=============================================================================\n\n/*\n=============\nSV_WriteEntitiesToClient\n\n=============\n*/\nvoid SV_WriteEntitiesToClient (edict_t\t*clent, sizebuf_t *msg)\n{\n\tint\t\te, i;\n\tint\t\tbits;\n\tbyte\t*pvs;\n\tvec3_t\torg;\n\tfloat\tmiss, alpha;\n\tedict_t\t*ent;\n\teval_t\t*val;\n\tint clentnum;\n\t\n// find the client's PVS\n\tVectorAdd (clent->v.origin, clent->v.view_ofs, org);\n\tpvs = SV_FatPVS (org);\n\t\n\tclentnum = EDICT_TO_PROG(clent); // LordHavoc: for comparison purposes\n\t\n// send over all entities (excpet the client) that touch the pvs\n\tent = NEXT_EDICT(sv.edicts);\n\tfor (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))\n\t{\n\t\t// don't send if flagged for NODRAW and there are no lighting effects\n\t\tif (ent->v.effects == EF_NODRAW)\n\t\t\tcontinue;\n\n// ignore if not touching a PV leaf\n\t\tif (ent != clent)\t// clent is ALWAYS sent\n\t\t{\n// ignore ents without visible models\n\t\t\tif (!ent->v.modelindex || !pr_strings[ent->v.model])\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tif ((val = GETEDICTFIELDVALUE(ent, eval_drawonlytoclient)) && val->edict && val->edict != clentnum)\n\t\t\t\tcontinue;\n\t\t\t\n\t\t\tif ((val = GETEDICTFIELDVALUE(ent, eval_nodrawtoclient)) && val->edict == clentnum)\n\t\t\t\tcontinue;\n\n\t\t\tfor (i=0 ; i < ent->num_leafs ; i++)\n\t\t\t\tif (pvs[ent->leafnums[i] >> 3] & (1 << (ent->leafnums[i]&7) ))\n\t\t\t\t\tbreak;\n\t\t\t\t\n\t\t\tif (i == ent->num_leafs)\n\t\t\t\tcontinue;\t\t// not visible\n\t\t\t\n\t\t}\n\n\t\tif (msg->cursize + 24 > msg->maxsize)\n\t\t{\n\t\t\tCon_Printf (\"packet overflow\\n\");\n\t\t\treturn;\n\t\t}\n\n// send an update\n\t\tbits = 0;\n\t\t\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\tmiss = ent->v.origin[i] - ent->baseline.origin[i];\n\t\t\tif ( miss < -0.1 || miss > 0.1 )\n\t\t\t\tbits |= U_ORIGIN1<<i;\n\t\t}\n\n\t\tif ( ent->v.angles[0] != ent->baseline.angles[0] )\n\t\t\tbits |= U_ANGLE1;\n\t\t\t\n\t\tif ( ent->v.angles[1] != ent->baseline.angles[1] )\n\t\t\tbits |= U_ANGLE2;\n\t\t\t\n\t\tif ( ent->v.angles[2] != ent->baseline.angles[2] )\n\t\t\tbits |= U_ANGLE3;\n\t\t\t\n\t\tif (ent->v.movetype == MOVETYPE_STEP)\n\t\t\tbits |= U_NOLERP;\t// don't mess up the step animation\n\t\n\t\tif (ent->baseline.colormap != ent->v.colormap)\n\t\t\tbits |= U_COLORMAP;\n\t\t\t\n\t\tif (ent->baseline.skin != ent->v.skin)\n\t\t\tbits |= U_SKIN;\n\t\t\t\n\t\tif (ent->baseline.frame != ent->v.frame)\n\t\t\tbits |= U_FRAME;\n\t\t\n\t\tif ((val = GetEdictFieldValue(ent, \"modelflags\")))\n\t\t{\n\t\t\ti= (unsigned int)ent->v.effects;\n\t\t\ti |= ((unsigned int)val->_float & 0xff) << 24;\n\t\t\tent->v.effects = i;\n\t\t}\n\t\t\n\t\tif (ent->baseline.effects != ent->v.effects)\n\t\t\tbits |= U_EFFECTS;\n\t\t\n\t\tif (ent->baseline.modelindex != ent->v.modelindex)\n\t\t\tbits |= U_MODEL;\n\t\t\n\t\tif (val = GETEDICTFIELDVALUE(ent, eval_alpha))\n\t\t{\n\t\t\tif ((val->_float < 1.0f) && (val->_float > 0.0f))\n\t\t\t{\n\t\t\t\talpha = val->_float;\n\t\t\t\tbits |= U_ALPHA;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (val = GETEDICTFIELDVALUE(ent, eval_renderamt))\n\t\t{\n\t\t\tif ((val->_float < 255.0f) && (val->_float > 0.0f))\n\t\t\t{\n\t\t\t\talpha = val->_float;\n\t\t\t\tbits |= U_RENDERAMT;\n\t\t\t}\n\t\t}\n\t\t\n\t\tif (e >= 256)\n\t\t\tbits |= U_LONGENTITY;\n\t\t\t\n\t\tif (bits >= 0x100)\n\t\t\tbits |= U_MOREBITS;\n\t\t\n\t\tif (bits >= 0x10000)\n\t\t\tbits |= U_EXTEND1;\n\t\t\n\t\tif (bits >= 0x1000000)\n\t\t\tbits |= U_EXTEND2;\n\n\t//\n\t// write the message\n\t//\n\t\tMSG_WriteByte (msg,bits | U_SIGNAL);\n\t\t\n\t\tif (bits & U_MOREBITS)\n\t\t\tMSG_WriteByte (msg, bits>>8);\n\t\tif (bits & U_EXTEND1)\n\t\t\tMSG_WriteByte (msg, bits>>16);\n        if (bits & U_EXTEND2)\n\t\t\tMSG_WriteByte (msg, bits>>24);\n\t\tif (bits & U_LONGENTITY)\n\t\t\tMSG_WriteShort (msg,e);\n\t\telse\n\t\t\tMSG_WriteByte (msg,e);\n\n\t\tif (bits & U_MODEL)\n\t\t\tMSG_WriteByte (msg,\tent->v.modelindex);\n\t\tif (bits & U_FRAME)\n\t\t\tMSG_WriteByte (msg, ent->v.frame);\n\t\tif (bits & U_COLORMAP)\n\t\t\tMSG_WriteByte (msg, ent->v.colormap);\n\t\tif (bits & U_SKIN)\n\t\t\tMSG_WriteByte (msg, ent->v.skin);\n\t\tif (bits & U_EFFECTS)\n\t\t\tMSG_WriteByte (msg, ent->v.effects);\n\t\tif (bits & U_ORIGIN1)\n\t\t\tMSG_WriteCoord (msg, ent->v.origin[0]);\t\t\n\t\tif (bits & U_ANGLE1)\n\t\t\tMSG_WriteAngle(msg, ent->v.angles[0]);\n\t\tif (bits & U_ORIGIN2)\n\t\t\tMSG_WriteCoord (msg, ent->v.origin[1]);\n\t\tif (bits & U_ANGLE2)\n\t\t\tMSG_WriteAngle(msg, ent->v.angles[1]);\n\t\tif (bits & U_ORIGIN3)\n\t\t\tMSG_WriteCoord (msg, ent->v.origin[2]);\n\t\tif (bits & U_ANGLE3)\n\t\t\tMSG_WriteAngle(msg, ent->v.angles[2]);\n\t\tif (bits & U_ALPHA)\n\t\t\tMSG_WriteByte(msg, (int)(alpha * 255));\n\t\tif (bits & U_RENDERAMT)\n\t\t\tMSG_WriteByte(msg, (int)(alpha));\n\t}\n}\n\n/*\n=============\nSV_CleanupEnts\n\n=============\n*/\nvoid SV_CleanupEnts (void)\n{\n\tint\t\te;\n\tedict_t\t*ent;\n\t\n\tent = NEXT_EDICT(sv.edicts);\n\tfor (e=1 ; e<sv.num_edicts ; e++, ent = NEXT_EDICT(ent))\n\t{\n\t\tent->v.effects = (int)ent->v.effects & ~EF_MUZZLEFLASH;\n\t}\n\n}\n\n/*\n==================\nSV_WriteClientdataToMessage\n\n==================\n*/\nvoid SV_WriteClientdataToMessage (edict_t *ent, sizebuf_t *msg)\n{\n\tint\t\tbits;\n\tint\t\ti;\n\tedict_t\t*other;\n\tint\t\titems;\n#ifndef QUAKE2\n\teval_t\t*val;\n#endif\n\n//\n// send a damage message\n//\n\tif (ent->v.dmg_take || ent->v.dmg_save)\n\t{\n\t\tother = PROG_TO_EDICT(ent->v.dmg_inflictor);\n\t\tMSG_WriteByte (msg, svc_damage);\n\t\tMSG_WriteByte (msg, ent->v.dmg_save);\n\t\tMSG_WriteByte (msg, ent->v.dmg_take);\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t\tMSG_WriteCoord (msg, other->v.origin[i] + 0.5*(other->v.mins[i] + other->v.maxs[i]));\n\t\n\t\tent->v.dmg_take = 0;\n\t\tent->v.dmg_save = 0;\n\t}\n\n//\n// send the current viewpos offset from the view entity\n//\n\tSV_SetIdealPitch ();\t\t// how much to look up / down ideally\n\n// a fixangle might get lost in a dropped packet.  Oh well.\n\tif ( ent->v.fixangle )\n\t{\n\t\tMSG_WriteByte (msg, svc_setangle);\n\t\tfor (i=0 ; i < 3 ; i++)\n\t\t\tMSG_WriteAngle (msg, ent->v.angles[i] );\n\t\tent->v.fixangle = 0;\n\t}\n\n\tbits = 0;\n\t\n\tif (ent->v.view_ofs[2] != DEFAULT_VIEWHEIGHT)\n\t\tbits |= SU_VIEWHEIGHT;\n\t\t\n\tif (ent->v.idealpitch)\n\t\tbits |= SU_IDEALPITCH;\n\n// stuff the sigil bits into the high bits of items for sbar, or else\n// mix in items2\n#ifdef QUAKE2\n\titems = (int)ent->v.items | ((int)ent->v.items2 << 23);\n#else\n\tval = GetEdictFieldValue(ent, \"items2\");\n\n\tif (val)\n\t\titems = (int)ent->v.items | ((int)val->_float << 23);\n\telse\n\t\titems = (int)ent->v.items | ((int)pr_global_struct->serverflags << 28);\n#endif\n\n\tbits |= SU_ITEMS;\n\t\n\tif ( (int)ent->v.flags & FL_ONGROUND)\n\t\tbits |= SU_ONGROUND;\n\t\n\tif ( ent->v.waterlevel >= 2)\n\t\tbits |= SU_INWATER;\n\t\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (ent->v.punchangle[i])\n\t\t\tbits |= (SU_PUNCH1<<i);\n\t\tif (ent->v.velocity[i])\n\t\t\tbits |= (SU_VELOCITY1<<i);\n\t}\n\t\n\tif (ent->v.weaponframe)\n\t\tbits |= SU_WEAPONFRAME;\n\n\tif (ent->v.armorvalue)\n\t\tbits |= SU_ARMOR;\n\n//\tif (ent->v.weapon)\n\t\tbits |= SU_WEAPON;\n\n// send the data\n\n\tMSG_WriteByte (msg, svc_clientdata);\n\tMSG_WriteShort (msg, bits);\n\n\tif (bits & SU_VIEWHEIGHT)\n\t\tMSG_WriteChar (msg, ent->v.view_ofs[2]);\n\n\tif (bits & SU_IDEALPITCH)\n\t\tMSG_WriteChar (msg, ent->v.idealpitch);\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (bits & (SU_PUNCH1<<i))\n\t\t\tMSG_WriteChar (msg, ent->v.punchangle[i]);\n\t\tif (bits & (SU_VELOCITY1<<i))\n\t\t\tMSG_WriteChar (msg, ent->v.velocity[i]/16);\n\t}\n\n// [always sent]\tif (bits & SU_ITEMS)\n\tMSG_WriteLong (msg, items);\n\n\tif (bits & SU_WEAPONFRAME)\n\t\tMSG_WriteByte (msg, ent->v.weaponframe);\n\tif (bits & SU_ARMOR)\n\t\tMSG_WriteByte (msg, ent->v.armorvalue);\n\tif (bits & SU_WEAPON)\n\t\tMSG_WriteByte (msg, SV_ModelIndex(pr_strings+ent->v.weaponmodel));\n\t\n\tMSG_WriteShort (msg, ent->v.health);\n\tMSG_WriteByte (msg, ent->v.currentammo);\n\tMSG_WriteByte (msg, ent->v.ammo_shells);\n\tMSG_WriteByte (msg, ent->v.ammo_nails);\n\tMSG_WriteByte (msg, ent->v.ammo_rockets);\n\tMSG_WriteByte (msg, ent->v.ammo_cells);\n\n\tif (standard_quake)\n\t{\n\t\tMSG_WriteByte (msg, ent->v.weapon);\n\t}\n\telse\n\t{\n\t\tfor(i=0;i<32;i++)\n\t\t{\n\t\t\tif ( ((int)ent->v.weapon) & (1<<i) )\n\t\t\t{\n\t\t\t\tMSG_WriteByte (msg, i);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n}\n\n/*\n=======================\nSV_SendClientDatagram\n=======================\n*/\nbool SV_SendClientDatagram (client_t *client)\n{\n\tbyte\t\tbuf[MAX_DATAGRAM];\n\tsizebuf_t\tmsg;\n\t\n\tmsg.data = buf;\n\tmsg.maxsize = sizeof(buf);\n\tmsg.cursize = 0;\n\n\tMSG_WriteByte (&msg, svc_time);\n\tMSG_WriteFloat (&msg, sv.time);\n\n// add the client specific data to the datagram\n\tSV_WriteClientdataToMessage (client->edict, &msg);\n\n\tSV_WriteEntitiesToClient (client->edict, &msg);\n\n// copy the server datagram if there is space\n\tif (msg.cursize + sv.datagram.cursize < msg.maxsize)\n\t\tSZ_Write (&msg, sv.datagram.data, sv.datagram.cursize);\n\n// send the datagram\n\tif (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)\n\t{\n\t\tSV_DropClient (true);// if the message couldn't send, kick off\n\t\treturn false;\n\t}\n\t\n\treturn true;\n}\n\n/*\n=======================\nSV_UpdateToReliableMessages\n=======================\n*/\nvoid SV_UpdateToReliableMessages (void)\n{\n\tint\t\t\ti, j;\n\tclient_t *client;\n\n// check for changes to be sent over the reliable streams\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t{\n\t\tif (host_client->old_frags != host_client->edict->v.frags)\n\t\t{\n\t\t\tfor (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)\n\t\t\t{\n\t\t\t\tif (!client->active)\n\t\t\t\t\tcontinue;\n\t\t\t\tMSG_WriteByte (&client->message, svc_updatefrags);\n\t\t\t\tMSG_WriteByte (&client->message, i);\n\t\t\t\tMSG_WriteShort (&client->message, host_client->edict->v.frags);\n\t\t\t}\n\n\t\t\thost_client->old_frags = host_client->edict->v.frags;\n\t\t}\n\t}\n\t\n\tfor (j=0, client = svs.clients ; j<svs.maxclients ; j++, client++)\n\t{\n\t\tif (!client->active)\n\t\t\tcontinue;\n\t\tSZ_Write (&client->message, sv.reliable_datagram.data, sv.reliable_datagram.cursize);\n\t}\n\n\tSZ_Clear (&sv.reliable_datagram);\n}\n\n\n/*\n=======================\nSV_SendNop\n\nSend a nop message without trashing or sending the accumulated client\nmessage buffer\n=======================\n*/\nvoid SV_SendNop (client_t *client)\n{\n\tsizebuf_t\tmsg;\n\tbyte\t\tbuf[4];\n\t\n\tmsg.data = buf;\n\tmsg.maxsize = sizeof(buf);\n\tmsg.cursize = 0;\n\n\tMSG_WriteChar (&msg, svc_nop);\n\n\tif (NET_SendUnreliableMessage (client->netconnection, &msg) == -1)\n\t\tSV_DropClient (true);\t// if the message couldn't send, kick off\n\tclient->last_message = realtime;\n}\n\n/*\n=======================\nSV_SendClientMessages\n=======================\n*/\nvoid SV_SendClientMessages (void)\n{\n\tint\t\t\ti;\n\t\n// update frags, names, etc\n\tSV_UpdateToReliableMessages ();\n\n// build individual updates\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t{\n\t\tif (!host_client->active)\n\t\t\tcontinue;\n\n\t\tif (host_client->spawned)\n\t\t{\n\t\t\tif (!SV_SendClientDatagram (host_client))\n\t\t\t\tcontinue;\n\t\t}\n\t\telse\n\t\t{\n\t\t// the player isn't totally in the game yet\n\t\t// send small keepalive messages if too much time has passed\n\t\t// send a full message when the next signon stage has been requested\n\t\t// some other message data (name changes, etc) may accumulate \n\t\t// between signon stages\n\t\t\tif (!host_client->sendsignon)\n\t\t\t{\n\t\t\t\tif (realtime - host_client->last_message > 5)\n\t\t\t\t\tSV_SendNop (host_client);\n\t\t\t\tcontinue;\t// don't send out non-signon messages\n\t\t\t}\n\t\t}\n\n\t\t// ProQuake - NAT fix for servers.\n\t\tif (host_client->netconnection->net_wait)\n\t\t\tcontinue;\n\n\t\t// check for an overflowed message.  Should only happen\n\t\t// on a very fucked up connection that backs up a lot, then\n\t\t// changes level\n\t\tif (host_client->message.overflowed)\n\t\t{\n\t\t\tSV_DropClient (true);\n\t\t\thost_client->message.overflowed = false;\n\t\t\tcontinue;\n\t\t}\n\t\t\t\n\t\tif (host_client->message.cursize || host_client->dropasap)\n\t\t{\n\t\t\tif (!NET_CanSendMessage (host_client->netconnection))\n\t\t\t{\n//\t\t\t\tI_Printf (\"can't write\\n\");\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (host_client->dropasap)\n\t\t\t\tSV_DropClient (false);\t// went to another level\n\t\t\telse\n\t\t\t{\n\t\t\t\tif (NET_SendMessage (host_client->netconnection\n\t\t\t\t, &host_client->message) == -1)\n\t\t\t\t\tSV_DropClient (true);\t// if the message couldn't send, kick off\n\t\t\t\tSZ_Clear (&host_client->message);\n\t\t\t\thost_client->last_message = realtime;\n\t\t\t\thost_client->sendsignon = false;\n\t\t\t}\n\t\t}\n\t}\n\t\n\t\n// clear muzzle flashes\n\tSV_CleanupEnts ();\n}\n\n\n/*\n==============================================================================\n\nSERVER SPAWNING\n\n==============================================================================\n*/\n\n/*\n================\nSV_ModelIndex\n\n================\n*/\nint SV_ModelIndex (char *name)\n{\n\tint\t\ti;\n\t\n\tif (!name || !name[0])\n\t\treturn 0;\n\n\tfor (i=0 ; i<MAX_MODELS && sv.model_precache[i] ; i++)\n\t\tif (!strcmp(sv.model_precache[i], name))\n\t\t\treturn i;\n\tif (i==MAX_MODELS || !sv.model_precache[i])\n\t\tSys_Error (\"SV_ModelIndex: model %s not precached\", name);\n\treturn i;\n}\n\n/*\n================\nSV_CreateBaseline\n\n================\n*/\nvoid SV_CreateBaseline (void)\n{\n\tint\t\t\ti;\n\tedict_t\t\t\t*svent;\n\tint\t\t\t\tentnum;\t\n\t\t\n\tfor (entnum = 0; entnum < sv.num_edicts ; entnum++)\n\t{\n\t// get the current server version\n\t\tsvent = EDICT_NUM(entnum);\n\t\tif (svent->free)\n\t\t\tcontinue;\n\t\tif (entnum > svs.maxclients && !svent->v.modelindex)\n\t\t\tcontinue;\n\n\t//\n\t// create entity baseline\n\t//\n\t\tVectorCopy (svent->v.origin, svent->baseline.origin);\n\t\tVectorCopy (svent->v.angles, svent->baseline.angles);\n\t\tsvent->baseline.frame = svent->v.frame;\n\t\tsvent->baseline.skin = svent->v.skin;\n\t\tif (entnum > 0 && entnum <= svs.maxclients)\n\t\t{\n\t\t\tsvent->baseline.colormap = entnum;\n\t\t\tsvent->baseline.modelindex = SV_ModelIndex(\"progs/player.mdl\");\n\t\t}\n\t\telse\n\t\t{\n\t\t\tsvent->baseline.colormap = 0;\n\t\t\tsvent->baseline.modelindex =\n\t\t\t\tSV_ModelIndex(pr_strings + svent->v.model);\n\t\t}\n\t\t\n\t//\n\t// add to the message\n\t//\n\t\tMSG_WriteByte (&sv.signon,svc_spawnbaseline);\t\t\n\t\tMSG_WriteShort (&sv.signon,entnum);\n\n\t\tMSG_WriteByte (&sv.signon, svent->baseline.modelindex);\n\t\tMSG_WriteByte (&sv.signon, svent->baseline.frame);\n\t\tMSG_WriteByte (&sv.signon, svent->baseline.colormap);\n\t\tMSG_WriteByte (&sv.signon, svent->baseline.skin);\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t{\n\t\t\tMSG_WriteCoord(&sv.signon, svent->baseline.origin[i]);\n\t\t\tMSG_WriteAngle(&sv.signon, svent->baseline.angles[i]);\n\t\t}\n\t}\n}\n\n\n/*\n================\nSV_SendReconnect\n\nTell all the clients that the server is changing levels\n================\n*/\nvoid SV_SendReconnect (void)\n{\n\tchar\tdata[128];\n\tsizebuf_t\tmsg;\n\n\tmsg.data = data;\n\tmsg.cursize = 0;\n\tmsg.maxsize = sizeof(data);\n\n\tMSG_WriteChar (&msg, svc_stufftext);\n\tMSG_WriteString (&msg, \"reconnect\\n\");\n\tNET_SendToAll (&msg, 5);\n\t\n\tif (cls.state != ca_dedicated)\n#ifdef QUAKE2\n\t\tCbuf_InsertText (\"reconnect\\n\");\n#else\n\t\tCmd_ExecuteString (\"reconnect\\n\", src_command);\n#endif\n}\n\n\n/*\n================\nSV_SaveSpawnparms\n\nGrabs the current state of each client for saving across the\ntransition to another level\n================\n*/\nvoid SV_SaveSpawnparms (void)\n{\n\tint\t\ti, j;\n\n\tsvs.serverflags = pr_global_struct->serverflags;\n\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t{\n\t\tif (!host_client->active)\n\t\t\tcontinue;\n\n\t// call the progs to get default spawn parms for the new client\n\t\tpr_global_struct->self = EDICT_TO_PROG(host_client->edict);\n\t\tPR_ExecuteProgram (pr_global_struct->SetChangeParms);\n\t\tfor (j=0 ; j<NUM_SPAWN_PARMS ; j++)\n\t\t\thost_client->spawn_parms[j] = (&pr_global_struct->parm1)[j];\n\t}\n}\n\n\n/*\n================\nSV_SpawnServer\n\nThis is called at the start of each level\n================\n*/\nextern float\t\tscr_centertime_off;\n\n#ifdef QUAKE2\nvoid SV_SpawnServer (char *server, char *startspot)\n#else\nvoid SV_SpawnServer (char *server)\n#endif\n{\n\tedict_t\t\t*ent;\n\tint\t\t\ti;\n\n\n\n\t// let's not have any servers with no name\n\tif (hostname.string[0] == 0)\n\t\tCvar_Set (\"hostname\", \"UNNAMED\");\n\tscr_centertime_off = 0;\n\n\tCon_DPrintf (\"SpawnServer: %s\\n\",server);\n\tsvs.changelevel_issued = false;\t\t// now safe to issue another\n\n//\n// tell all connected clients that we are going to a new level\n//\n\tif (sv.active)\n\t{\n\t\tSV_SendReconnect ();\n\t}\n\n//\n// make cvars consistant\n//\n\tif (coop.value)\n\t\tCvar_SetValue (\"deathmatch\", 0);\n\tcurrent_skill = (int)(skill.value + 0.5);\n\tif (current_skill < 0)\n\t\tcurrent_skill = 0;\n\tif (current_skill > 3)\n\t\tcurrent_skill = 3;\n\n\tCvar_SetValue (\"skill\", (float)current_skill);\n\t\n//\n// set up the new server\n//\n\tHost_ClearMemory ();\n\n\tmemset (&sv, 0, sizeof(sv));\n\n\tstrcpy (sv.name, server);\n#ifdef QUAKE2\n\tif (startspot)\n\t\tstrcpy(sv.startspot, startspot);\n#endif\n\n// load progs to get entity field count\n\tPR_LoadProgs (sv_progs.string);\n\n// allocate server memory\n\tsv.max_edicts = MAX_EDICTS;\n\t\n\tsv.edicts = Hunk_AllocName (sv.max_edicts*pr_edict_size, \"edicts\");\n\n\tsv.datagram.maxsize = sizeof(sv.datagram_buf);\n\tsv.datagram.cursize = 0;\n\tsv.datagram.data = sv.datagram_buf;\n\t\n\tsv.reliable_datagram.maxsize = sizeof(sv.reliable_datagram_buf);\n\tsv.reliable_datagram.cursize = 0;\n\tsv.reliable_datagram.data = sv.reliable_datagram_buf;\n\t\n\tsv.signon.maxsize = sizeof(sv.signon_buf);\n\tsv.signon.cursize = 0;\n\tsv.signon.data = sv.signon_buf;\n\t\n// leave slots at start for clients only\n\tsv.num_edicts = svs.maxclients+1;\n\tfor (i=0 ; i<svs.maxclients ; i++)\n\t{\n\t\tent = EDICT_NUM(i+1);\n\t\tsvs.clients[i].edict = ent;\n\t}\n\t\n\tsv.state = ss_loading;\n\tsv.paused = false;\n\n\tsv.time = 1.0;\n\t\n\tstrcpy (sv.name, server);\n\tsprintf (sv.modelname,\"maps/%s.bsp\", server);\n\tsv.worldmodel = Mod_ForName (sv.modelname, false);\n\tif (!sv.worldmodel)\n\t{\n\t\tCon_Printf (\"Couldn't spawn server %s\\n\", sv.modelname);\n\t\tsv.active = false;\n\t\treturn;\n\t}\n\tsv.models[1] = sv.worldmodel;\n\t\n//\n// clear world interaction links\n//\n\tSV_ClearWorld ();\n\t\n\tsv.sound_precache[0] = pr_strings;\n\n\tsv.model_precache[0] = pr_strings;\n\tsv.model_precache[1] = sv.modelname;\n\tfor (i=1 ; i<sv.worldmodel->numsubmodels ; i++)\n\t{\n\t\tsv.model_precache[1+i] = localmodels[i];\n\t\tsv.models[i+1] = Mod_ForName (localmodels[i], false);\n\t}\n\n//\n// load the rest of the entities\n//\t\n\tent = EDICT_NUM(0);\n\tmemset (&ent->v, 0, progs->entityfields * 4);\n\tent->free = false;\n\tent->v.model = sv.worldmodel->name - pr_strings;\n\tent->v.modelindex = 1;\t\t// world model\n\tent->v.solid = SOLID_BSP;\n\tent->v.movetype = MOVETYPE_PUSH;\n\n\tif (coop.value)\n\t\tpr_global_struct->coop = coop.value;\n\telse\n\t\tpr_global_struct->deathmatch = deathmatch.value;\n\n\tpr_global_struct->mapname = sv.name - pr_strings;\n#ifdef QUAKE2\n\tpr_global_struct->startspot = sv.startspot - pr_strings;\n#endif\n\n// serverflags are for cross level information (sigils)\n\tpr_global_struct->serverflags = svs.serverflags;\n\t\n\tED_LoadFromFile (sv.worldmodel->entities);\n\n\tsv.active = true;\n\n// all setup is completed, any further precache statements are errors\n\tsv.state = ss_active;\n\t\n// run two frames to allow everything to settle\n\thost_frametime = 0.1;\n\tSV_Physics ();\n\tSV_Physics ();\n\n// create a baseline for more efficient communications\n\tSV_CreateBaseline ();\n\n// send serverinfo to all connected clients\n\tfor (i=0,host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t\tif (host_client->active)\n\t\t\tSV_SendServerinfo (host_client);\n\t\n\tCon_DPrintf (\"Server spawned.\\n\");\n}\n\n"
  },
  {
    "path": "source/sv_move.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sv_move.c -- monster movement\n\n#include \"quakedef.h\"\n\n#define\tSTEPSIZE\t18\n\n/*\n=============\nSV_CheckBottom\n\nReturns false if any part of the bottom of the entity is off an edge that\nis not a staircase.\n\n=============\n*/\nint c_yes, c_no;\n\nbool SV_CheckBottom (edict_t *ent)\n{\n\tvec3_t\tmins, maxs, start, stop;\n\ttrace_t\ttrace;\n\tint\t\tx, y;\n\tfloat\tmid, bottom;\n\t\n\tVectorAdd (ent->v.origin, ent->v.mins, mins);\n\tVectorAdd (ent->v.origin, ent->v.maxs, maxs);\n\n// if all of the points under the corners are solid world, don't bother\n// with the tougher checks\n// the corners must be within 16 of the midpoint\n\tstart[2] = mins[2] - 1;\n\tfor\t(x=0 ; x<=1 ; x++)\n\t\tfor\t(y=0 ; y<=1 ; y++)\n\t\t{\n\t\t\tstart[0] = x ? maxs[0] : mins[0];\n\t\t\tstart[1] = y ? maxs[1] : mins[1];\n\t\t\tif (SV_PointContents (start) != CONTENTS_SOLID)\n\t\t\t\tgoto realcheck;\n\t\t}\n\n\tc_yes++;\n\treturn true;\t\t// we got out easy\n\nrealcheck:\n\tc_no++;\n//\n// check it for real...\n//\n\tstart[2] = mins[2];\n\t\n// the midpoint must be within 16 of the bottom\n\tstart[0] = stop[0] = (mins[0] + maxs[0])*0.5;\n\tstart[1] = stop[1] = (mins[1] + maxs[1])*0.5;\n\tstop[2] = start[2] - 2*STEPSIZE;\n\ttrace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);\n\n\tif (trace.fraction == 1.0)\n\t\treturn false;\n\tmid = bottom = trace.endpos[2];\n\t\n// the corners must be within 16 of the midpoint\t\n\tfor\t(x=0 ; x<=1 ; x++)\n\t\tfor\t(y=0 ; y<=1 ; y++)\n\t\t{\n\t\t\tstart[0] = stop[0] = x ? maxs[0] : mins[0];\n\t\t\tstart[1] = stop[1] = y ? maxs[1] : mins[1];\n\t\t\t\n\t\t\ttrace = SV_Move (start, vec3_origin, vec3_origin, stop, true, ent);\n\t\t\t\n\t\t\tif (trace.fraction != 1.0 && trace.endpos[2] > bottom)\n\t\t\t\tbottom = trace.endpos[2];\n\t\t\tif (trace.fraction == 1.0 || mid - trace.endpos[2] > STEPSIZE)\n\t\t\t\treturn false;\n\t\t}\n\n\tc_yes++;\n\treturn true;\n}\n\n\n/*\n=============\nSV_movestep\n\nCalled by monster program code.\nThe move will be adjusted for slopes and stairs, but if the move isn't\npossible, no move is done, false is returned, and\npr_global_struct->trace_normal is set to the normal of the blocking wall\n=============\n*/\nbool SV_movestep (edict_t *ent, vec3_t move, bool relink)\n{\n\tfloat\t\tdz;\n\tvec3_t\t\toldorg, neworg, end;\n\ttrace_t\t\ttrace;\n\tint\t\t\ti;\n\tedict_t\t\t*enemy;\n\n// try the move\t\n\tVectorCopy (ent->v.origin, oldorg);\n\tVectorAdd (ent->v.origin, move, neworg);\n\n// flying monsters don't step up\n\tif ( (int)ent->v.flags & (FL_SWIM | FL_FLY) )\n\t{\n\t// try one move with vertical motion, then one without\n\t\tfor (i=0 ; i<2 ; i++)\n\t\t{\n\t\t\tVectorAdd (ent->v.origin, move, neworg);\n\t\t\tenemy = PROG_TO_EDICT(ent->v.enemy);\n\t\t\tif (i == 0 && enemy != sv.edicts)\n\t\t\t{\n\t\t\t\tdz = ent->v.origin[2] - PROG_TO_EDICT(ent->v.enemy)->v.origin[2];\n\t\t\t\tif (dz > 40)\n\t\t\t\t\tneworg[2] -= 8;\n\t\t\t\tif (dz < 30)\n\t\t\t\t\tneworg[2] += 8;\n\t\t\t}\n\t\t\ttrace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, neworg, false, ent);\n\t\n\t\t\tif (trace.fraction == 1)\n\t\t\t{\n\t\t\t\tif ( ((int)ent->v.flags & FL_SWIM) && SV_PointContents(trace.endpos) == CONTENTS_EMPTY )\n\t\t\t\t\treturn false;\t// swim monster left water\n\t\n\t\t\t\tVectorCopy (trace.endpos, ent->v.origin);\n\t\t\t\tif (relink)\n\t\t\t\t\tSV_LinkEdict (ent, true);\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\t\n\t\t\tif (enemy == sv.edicts)\n\t\t\t\tbreak;\n\t\t}\n\t\t\n\t\treturn false;\n\t}\n\n// push down from a step height above the wished position\n\tneworg[2] += STEPSIZE;\n\tVectorCopy (neworg, end);\n\tend[2] -= STEPSIZE*2;\n\n\ttrace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);\n\n\tif (trace.allsolid)\n\t\treturn false;\n\n\tif (trace.startsolid)\n\t{\n\t\tneworg[2] -= STEPSIZE;\n\t\ttrace = SV_Move (neworg, ent->v.mins, ent->v.maxs, end, false, ent);\n\t\tif (trace.allsolid || trace.startsolid)\n\t\t\treturn false;\n\t}\n\tif (trace.fraction == 1)\n\t{\n\t// if monster had the ground pulled out, go ahead and fall\n\t\tif ( (int)ent->v.flags & FL_PARTIALGROUND )\n\t\t{\n\t\t\tVectorAdd (ent->v.origin, move, ent->v.origin);\n\t\t\tif (relink)\n\t\t\t\tSV_LinkEdict (ent, true);\n\t\t\tent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;\n//\tCon_Printf (\"fall down\\n\"); \n\t\t\treturn true;\n\t\t}\n\t\n\t\treturn false;\t\t// walked off an edge\n\t}\n\n// check point traces down for dangling corners\n\tVectorCopy (trace.endpos, ent->v.origin);\n\t\n\tif (!SV_CheckBottom (ent))\n\t{\n\t\tif ( (int)ent->v.flags & FL_PARTIALGROUND )\n\t\t{\t// entity had floor mostly pulled out from underneath it\n\t\t\t// and is trying to correct\n\t\t\tif (relink)\n\t\t\t\tSV_LinkEdict (ent, true);\n\t\t\treturn true;\n\t\t}\n\t\tVectorCopy (oldorg, ent->v.origin);\n\t\treturn false;\n\t}\n\n\tif ( (int)ent->v.flags & FL_PARTIALGROUND )\n\t{\n//\t\tCon_Printf (\"back on ground\\n\"); \n\t\tent->v.flags = (int)ent->v.flags & ~FL_PARTIALGROUND;\n\t}\n\tent->v.groundentity = EDICT_TO_PROG(trace.ent);\n\n// the move is ok\n\tif (relink)\n\t\tSV_LinkEdict (ent, true);\n\treturn true;\n}\n\n\n//============================================================================\n\n/*\n======================\nSV_StepDirection\n\nTurns to the movement direction, and walks the current distance if\nfacing it.\n\n======================\n*/\nvoid PF_changeyaw (void);\nbool SV_StepDirection (edict_t *ent, float yaw, float dist)\n{\n\tvec3_t\t\tmove, oldorigin;\n\tfloat\t\tdelta;\n\t\n\tent->v.ideal_yaw = yaw;\n\tPF_changeyaw();\n\t\n\tyaw = yaw*M_PI*2 / 360;\n\tmove[0] = cosf(yaw)*dist;\n\tmove[1] = sinf(yaw)*dist;\n\tmove[2] = 0;\n\n\tVectorCopy (ent->v.origin, oldorigin);\n\tif (SV_movestep (ent, move, false))\n\t{\n\t\tdelta = ent->v.angles[YAW] - ent->v.ideal_yaw;\n\t\tif (delta > 45 && delta < 315)\n\t\t{\t\t// not turned far enough, so don't take the step\n\t\t\tVectorCopy (oldorigin, ent->v.origin);\n\t\t}\n\t\tSV_LinkEdict (ent, true);\n\t\treturn true;\n\t}\n\tSV_LinkEdict (ent, true);\n\t\t\n\treturn false;\n}\n\n/*\n======================\nSV_FixCheckBottom\n\n======================\n*/\nvoid SV_FixCheckBottom (edict_t *ent)\n{\n//\tCon_Printf (\"SV_FixCheckBottom\\n\");\n\t\n\tent->v.flags = (int)ent->v.flags | FL_PARTIALGROUND;\n}\n\n\n\n/*\n================\nSV_NewChaseDir\n\n================\n*/\n#define\tDI_NODIR\t-1\nvoid SV_NewChaseDir (edict_t *actor, edict_t *enemy, float dist)\n{\n\tfloat\t\tdeltax,deltay;\n\tfloat\t\t\td[3];\n\tfloat\t\ttdir, olddir, turnaround;\n\n\tolddir = anglemod( (int)(actor->v.ideal_yaw/45)*45 );\n\tturnaround = anglemod(olddir - 180);\n\n\tdeltax = enemy->v.origin[0] - actor->v.origin[0];\n\tdeltay = enemy->v.origin[1] - actor->v.origin[1];\n\tif (deltax>10)\n\t\td[1]= 0;\n\telse if (deltax<-10)\n\t\td[1]= 180;\n\telse\n\t\td[1]= DI_NODIR;\n\tif (deltay<-10)\n\t\td[2]= 270;\n\telse if (deltay>10)\n\t\td[2]= 90;\n\telse\n\t\td[2]= DI_NODIR;\n\n// try direct route\n\tif (d[1] != DI_NODIR && d[2] != DI_NODIR)\n\t{\n\t\tif (d[1] == 0)\n\t\t\ttdir = d[2] == 90 ? 45 : 315;\n\t\telse\n\t\t\ttdir = d[2] == 90 ? 135 : 215;\n\t\t\t\n\t\tif (tdir != turnaround && SV_StepDirection(actor, tdir, dist))\n\t\t\treturn;\n\t}\n\n// try other directions\n\tif ( ((rand()&3) & 1) ||  abs(deltay)>abs(deltax))\n\t{\n\t\ttdir=d[1];\n\t\td[1]=d[2];\n\t\td[2]=tdir;\n\t}\n\n\tif (d[1]!=DI_NODIR && d[1]!=turnaround \n\t&& SV_StepDirection(actor, d[1], dist))\n\t\t\treturn;\n\n\tif (d[2]!=DI_NODIR && d[2]!=turnaround\n\t&& SV_StepDirection(actor, d[2], dist))\n\t\t\treturn;\n\n/* there is no direct path to the player, so pick another direction */\n\n\tif (olddir!=DI_NODIR && SV_StepDirection(actor, olddir, dist))\n\t\t\treturn;\n\n\tif (rand()&1) \t/*randomly determine direction of search*/\n\t{\n\t\tfor (tdir=0 ; tdir<=315 ; tdir += 45)\n\t\t\tif (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )\n\t\t\t\t\treturn;\n\t}\n\telse\n\t{\n\t\tfor (tdir=315 ; tdir >=0 ; tdir -= 45)\n\t\t\tif (tdir!=turnaround && SV_StepDirection(actor, tdir, dist) )\n\t\t\t\t\treturn;\n\t}\n\n\tif (turnaround != DI_NODIR && SV_StepDirection(actor, turnaround, dist) )\n\t\t\treturn;\n\n\tactor->v.ideal_yaw = olddir;\t\t// can't move\n\n// if a bridge was pulled out from underneath a monster, it may not have\n// a valid standing position at all\n\n\tif (!SV_CheckBottom (actor))\n\t\tSV_FixCheckBottom (actor);\n\n}\n\n/*\n======================\nSV_CloseEnough\n\n======================\n*/\nbool SV_CloseEnough (edict_t *ent, edict_t *goal, float dist)\n{\n\tint\t\ti;\n\t\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (goal->v.absmin[i] > ent->v.absmax[i] + dist)\n\t\t\treturn false;\n\t\tif (goal->v.absmax[i] < ent->v.absmin[i] - dist)\n\t\t\treturn false;\n\t}\n\treturn true;\n}\n\n/*\n======================\nSV_MoveToGoal\n\n======================\n*/\nvoid SV_MoveToGoal (void)\n{\n\tedict_t\t\t*ent, *goal;\n\tfloat\t\tdist;\n#ifdef QUAKE2\n\tedict_t\t\t*enemy;\n#endif\n\n\tent = PROG_TO_EDICT(pr_global_struct->self);\n\tgoal = PROG_TO_EDICT(ent->v.goalentity);\n\tdist = G_FLOAT(OFS_PARM0);\n\n\tif ( !( (int)ent->v.flags & (FL_ONGROUND|FL_FLY|FL_SWIM) ) )\n\t{\n\t\tG_FLOAT(OFS_RETURN) = 0;\n\t\treturn;\n\t}\n\n// if the next step hits the enemy, return immediately\n#ifdef QUAKE2\n\tenemy = PROG_TO_EDICT(ent->v.enemy);\n\tif (enemy != sv.edicts &&  SV_CloseEnough (ent, enemy, dist) )\n#else\n\tif ( PROG_TO_EDICT(ent->v.enemy) != sv.edicts &&  SV_CloseEnough (ent, goal, dist) )\n#endif\n\t\treturn;\n\n// bump around...\n\tif ( (rand()&3)==1 ||\n\t!SV_StepDirection (ent, ent->v.ideal_yaw, dist))\n\t{\n\t\tSV_NewChaseDir (ent, goal, dist);\n\t}\n}\n\n"
  },
  {
    "path": "source/sv_phys.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sv_phys.c\n\n#include \"quakedef.h\"\n\nCVAR (sv_friction, 4, CVAR_SERVERINFO)\nCVAR(sv_gravity, 800, CVAR_SERVERINFO)\nCVAR(sv_stopspeed, 100, CVAR_NONE)\nCVAR(sv_maxvelocity, 2000, CVAR_NONE)\nCVAR(sv_nostep, 0, CVAR_NONE)\n\n//----------------------------------------------\n\n/*\n\npushmove objects do not obey gravity, and do not interact with each other or trigger fields, but block normal movement and push normal objects when they move.\n\nonground is set for toss objects when they come to a complete rest.  it is set for steping or walking objects\n\ndoors, plats, etc are SOLID_BSP, and MOVETYPE_PUSH\nbonus items are SOLID_TRIGGER touch, and MOVETYPE_TOSS\ncorpses are SOLID_NOT and MOVETYPE_TOSS\ncrates are SOLID_BBOX and MOVETYPE_TOSS\nwalking monsters are SOLID_SLIDEBOX and MOVETYPE_STEP\nflying/floating monsters are SOLID_SLIDEBOX and MOVETYPE_FLY\n\nsolid_edge items only clip against bsp models.\n\n*/\n\n\n#ifdef QUAKE2\nstatic\tvec3_t\tvec_origin = {0.0, 0.0, 0.0};\n#endif\n\n#define\tMOVE_EPSILON\t0.01\n\nvoid SV_Physics_Toss (edict_t *ent);\n\n/*\n================\nSV_CheckAllEnts\n================\n*/\nvoid SV_CheckAllEnts (void)\n{\n\tint\t\t\te;\n\tedict_t\t\t*check;\n\n// see if any solid entities are inside the final position\n\tcheck = NEXT_EDICT(sv.edicts);\n\tfor (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))\n\t{\n\t\tif (check->free)\n\t\t\tcontinue;\n\t\tif (check->v.movetype == MOVETYPE_PUSH\n\t\t|| check->v.movetype == MOVETYPE_NONE\n#ifdef QUAKE2\n\t\t|| check->v.movetype == MOVETYPE_FOLLOW\n#endif\n\t\t|| check->v.movetype == MOVETYPE_NOCLIP)\n\t\t\tcontinue;\n\n\t\tif (SV_TestEntityPosition (check))\n\t\t\tCon_Printf (\"entity in invalid position\\n\");\n\t}\n}\n\n/*\n================\nSV_CheckVelocity\n================\n*/\nvoid SV_CheckVelocity (edict_t *ent)\n{\n\tint\t\ti;\n\n//\n// bound velocity\n//\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tif (isnan(ent->v.velocity[i]))\n\t\t{\n\t\t\tCon_Printf (\"Got a NaN velocity on %s\\n\", pr_strings + ent->v.classname);\n\t\t\tent->v.velocity[i] = 0;\n\t\t}\n\t\tif (isnan(ent->v.origin[i]))\n\t\t{\n\t\t\tCon_Printf (\"Got a NaN origin on %s\\n\", pr_strings + ent->v.classname);\n\t\t\tent->v.origin[i] = 0;\n\t\t}\n\t\tif (ent->v.velocity[i] > sv_maxvelocity.value)\n\t\t\tent->v.velocity[i] = sv_maxvelocity.value;\n\t\telse if (ent->v.velocity[i] < -sv_maxvelocity.value)\n\t\t\tent->v.velocity[i] = -sv_maxvelocity.value;\n\t}\n}\n\n/*\n=============\nSV_RunThink\n\nRuns thinking code if time.  There is some play in the exact time the think\nfunction will be called, because it is called before any movement is done\nin a frame.  Not used for pushmove objects, because they must be exact.\nReturns false if the entity removed itself.\n=============\n*/\nbool SV_RunThink (edict_t *ent)\n{\n\tfloat\tthinktime;\n\n\tthinktime = ent->v.nextthink;\n\tif (thinktime <= 0 || thinktime > sv.time + host_frametime)\n\t\treturn true;\n\n\tif (thinktime < sv.time)\n\t\tthinktime = sv.time;\t// don't let things stay in the past.\n\t\t\t\t\t\t\t\t// it is possible to start that way\n\t\t\t\t\t\t\t\t// by a trigger with a local time.\n\tent->v.nextthink = 0;\n\tpr_global_struct->time = thinktime;\n\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\tpr_global_struct->other = EDICT_TO_PROG(sv.edicts);\n\tPR_ExecuteProgram (ent->v.think);\n\treturn !ent->free;\n}\n\n/*\n==================\nSV_Impact\n\nTwo entities have touched, so run their touch functions\n==================\n*/\nvoid SV_Impact (edict_t *e1, edict_t *e2)\n{\n\tint\t\told_self, old_other;\n\n\told_self = pr_global_struct->self;\n\told_other = pr_global_struct->other;\n\n\tpr_global_struct->time = sv.time;\n\tif (e1->v.touch && e1->v.solid != SOLID_NOT)\n\t{\n\t\tpr_global_struct->self = EDICT_TO_PROG(e1);\n\t\tpr_global_struct->other = EDICT_TO_PROG(e2);\n\t\tPR_ExecuteProgram (e1->v.touch);\n\t}\n\n\tif (e2->v.touch && e2->v.solid != SOLID_NOT)\n\t{\n\t\tpr_global_struct->self = EDICT_TO_PROG(e2);\n\t\tpr_global_struct->other = EDICT_TO_PROG(e1);\n\t\tPR_ExecuteProgram (e2->v.touch);\n\t}\n\n\tpr_global_struct->self = old_self;\n\tpr_global_struct->other = old_other;\n}\n\n\n/*\n==================\nClipVelocity\n\nSlide off of the impacting object\nreturns the blocked flags (1 = floor, 2 = step / wall)\n==================\n*/\n#define\tSTOP_EPSILON\t0.1\n\nint ClipVelocity (vec3_t in, vec3_t normal, vec3_t out, float overbounce)\n{\n\tfloat\tbackoff;\n\tfloat\tchange;\n\tint\t\ti, blocked;\n\n\tblocked = 0;\n\tif (normal[2] > 0)\n\t\tblocked |= 1;\t\t// floor\n\tif (!normal[2])\n\t\tblocked |= 2;\t\t// step\n\n\tbackoff = DotProduct (in, normal) * overbounce;\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tchange = normal[i]*backoff;\n\t\tout[i] = in[i] - change;\n\t\tif (out[i] > -STOP_EPSILON && out[i] < STOP_EPSILON)\n\t\t\tout[i] = 0;\n\t}\n\n\treturn blocked;\n}\n\n\n/*\n============\nSV_FlyMove\n\nThe basic solid body movement clip that slides along multiple planes\nReturns the clipflags if the velocity was modified (hit something solid)\n1 = floor\n2 = wall / step\n4 = dead stop\nIf steptrace is not NULL, the trace of any vertical wall hit will be stored\n============\n*/\n#define\tMAX_CLIP_PLANES\t5\nint SV_FlyMove (edict_t *ent, float time, trace_t *steptrace)\n{\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, original_velocity, new_velocity;\n\tint\t\t\ti, j;\n\ttrace_t\t\ttrace;\n\tvec3_t\t\tend;\n\tfloat\t\ttime_left;\n\tint\t\t\tblocked;\n\n\tnumbumps = 4;\n\n\tblocked = 0;\n\tVectorCopy (ent->v.velocity, original_velocity);\n\tVectorCopy (ent->v.velocity, primal_velocity);\n\tnumplanes = 0;\n\n\ttime_left = time;\n\n\tfor (bumpcount=0 ; bumpcount<numbumps ; bumpcount++)\n\t{\n\t\tif (!ent->v.velocity[0] && !ent->v.velocity[1] && !ent->v.velocity[2])\n\t\t\tbreak;\n\n\t\tfor (i=0 ; i<3 ; i++)\n\t\t\tend[i] = ent->v.origin[i] + time_left * ent->v.velocity[i];\n\n\t\ttrace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, false, ent);\n\n\t\tif (trace.allsolid)\n\t\t{\t// entity is trapped in another solid\n\t\t\tVectorCopy (vec3_origin, ent->v.velocity);\n\t\t\treturn 3;\n\t\t}\n\n\t\tif (trace.fraction > 0)\n\t\t{\t// actually covered some distance\n\t\t\tVectorCopy (trace.endpos, ent->v.origin);\n\t\t\tVectorCopy (ent->v.velocity, original_velocity);\n\t\t\tnumplanes = 0;\n\t\t}\n\n\t\tif (trace.fraction == 1)\n\t\t\t break;\t\t// moved the entire distance\n\n\t\tif (!trace.ent)\n\t\t\tSys_Error (\"SV_FlyMove: !trace.ent\");\n\n\t\tif (trace.plane.normal[2] > 0.7)\n\t\t{\n\t\t\tblocked |= 1;\t\t// floor\n\t\t\tif (trace.ent->v.solid == SOLID_BSP)\n\t\t\t{\n\t\t\t\tent->v.flags =\t(int)ent->v.flags | FL_ONGROUND;\n\t\t\t\tent->v.groundentity = EDICT_TO_PROG(trace.ent);\n\t\t\t}\n\t\t}\n\t\tif (!trace.plane.normal[2])\n\t\t{\n\t\t\tblocked |= 2;\t\t// step\n\t\t\tif (steptrace)\n\t\t\t\t*steptrace = trace;\t// save for player extrafriction\n\t\t}\n\n//\n// run the impact function\n//\n\t\tSV_Impact (ent, trace.ent);\n\t\tif (ent->free)\n\t\t\tbreak;\t\t// removed by the impact function\n\n\n\t\ttime_left -= time_left * trace.fraction;\n\n\t// cliped to another plane\n\t\tif (numplanes >= MAX_CLIP_PLANES)\n\t\t{\t// this shouldn't really happen\n\t\t\tVectorCopy (vec3_origin, ent->v.velocity);\n\t\t\treturn 3;\n\t\t}\n\n\t\tVectorCopy (trace.plane.normal, planes[numplanes]);\n\t\tnumplanes++;\n\n//\n// modify original_velocity so it parallels all of the clip planes\n//\n\t\tfor (i=0 ; i<numplanes ; i++)\n\t\t{\n\t\t\tClipVelocity (original_velocity, planes[i], new_velocity, 1);\n\t\t\tfor (j=0 ; j<numplanes ; j++)\n\t\t\t\tif (j != i)\n\t\t\t\t{\n\t\t\t\t\tif (DotProduct (new_velocity, planes[j]) < 0)\n\t\t\t\t\t\tbreak;\t// not ok\n\t\t\t\t}\n\t\t\tif (j == numplanes)\n\t\t\t\tbreak;\n\t\t}\n\n\t\tif (i != numplanes)\n\t\t{\t// go along this plane\n\t\t\tVectorCopy (new_velocity, ent->v.velocity);\n\t\t}\n\t\telse\n\t\t{\t// go along the crease\n\t\t\tif (numplanes != 2)\n\t\t\t{\n//\t\t\t\tCon_Printf (\"clip velocity, numplanes == %i\\n\",numplanes);\n\t\t\t\tVectorCopy (vec3_origin, ent->v.velocity);\n\t\t\t\treturn 7;\n\t\t\t}\n\t\t\tCrossProduct (planes[0], planes[1], dir);\n\t\t\td = DotProduct (dir, ent->v.velocity);\n\t\t\tVectorScale (dir, d, ent->v.velocity);\n\t\t}\n\n//\n// if original velocity is against the original velocity, stop dead\n// to avoid tiny occilations in sloping corners\n//\n\t\tif (DotProduct (ent->v.velocity, primal_velocity) <= 0)\n\t\t{\n\t\t\tVectorCopy (vec3_origin, ent->v.velocity);\n\t\t\treturn blocked;\n\t\t}\n\t}\n\n\treturn blocked;\n}\n\n\n/*\n============\nSV_AddGravity\n\n============\n*/\nvoid SV_AddGravity (edict_t *ent)\n{\n\tfloat\tent_gravity;\n\n#ifdef QUAKE2\n\tif (ent->v.gravity)\n\t\tent_gravity = ent->v.gravity;\n\telse\n\t\tent_gravity = 1.0;\n#else\n\teval_t\t*val;\n\n\tval = GetEdictFieldValue(ent, \"gravity\");\n\tif (val && val->_float)\n\t\tent_gravity = val->_float;\n\telse\n\t\tent_gravity = 1.0;\n#endif\n\tent->v.velocity[2] -= ent_gravity * sv_gravity.value * host_frametime;\n}\n\n\n/*\n===============================================================================\n\nPUSHMOVE\n\n===============================================================================\n*/\n\n/*\n============\nSV_PushEntity\n\nDoes not change the entities velocity at all\n============\n*/\ntrace_t SV_PushEntity (edict_t *ent, vec3_t push)\n{\n\ttrace_t\ttrace;\n\tvec3_t\tend;\n\n\tVectorAdd (ent->v.origin, push, end);\n\n\tif (ent->v.movetype == MOVETYPE_FLYMISSILE)\n\t\ttrace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_MISSILE, ent);\n\telse if (ent->v.solid == SOLID_TRIGGER || ent->v.solid == SOLID_NOT)\n\t// only clip against bmodels\n\t\ttrace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NOMONSTERS, ent);\n\telse\n\t\ttrace = SV_Move (ent->v.origin, ent->v.mins, ent->v.maxs, end, MOVE_NORMAL, ent);\n\n\tVectorCopy (trace.endpos, ent->v.origin);\n\tSV_LinkEdict (ent, true);\n\n\tif (trace.ent)\n\t\tSV_Impact (ent, trace.ent);\n\n\treturn trace;\n}\n\n\n/*\n============\nSV_PushMove\n\n============\n*/\nvoid SV_PushMove (edict_t *pusher, float movetime)\n{\n\tint\t\t\ti, e;\n\tedict_t\t\t*check, *block;\n\tvec3_t\t\tmins, maxs, move;\n\tvec3_t\t\tentorig, pushorig;\n\tint\t\t\tnum_moved;\n\tedict_t\t\t*moved_edict[MAX_EDICTS];\n\tvec3_t\t\tmoved_from[MAX_EDICTS];\n\n\tif (!pusher->v.velocity[0] && !pusher->v.velocity[1] && !pusher->v.velocity[2])\n\t{\n\t\tpusher->v.ltime += movetime;\n\t\treturn;\n\t}\n\n\tfor (i=0 ; i<3 ; i++)\n\t{\n\t\tmove[i] = pusher->v.velocity[i] * movetime;\n\t\tmins[i] = pusher->v.absmin[i] + move[i];\n\t\tmaxs[i] = pusher->v.absmax[i] + move[i];\n\t}\n\n\tVectorCopy (pusher->v.origin, pushorig);\n\n// move the pusher to it's final position\n\n\tVectorAdd (pusher->v.origin, move, pusher->v.origin);\n\tpusher->v.ltime += movetime;\n\tSV_LinkEdict (pusher, false);\n\n\n// see if any solid entities are inside the final position\n\tnum_moved = 0;\n\tcheck = NEXT_EDICT(sv.edicts);\n\tfor (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))\n\t{\n\t\tif (check->free)\n\t\t\tcontinue;\n\t\tif (check->v.movetype == MOVETYPE_PUSH\n\t\t|| check->v.movetype == MOVETYPE_NONE\n#ifdef QUAKE2\n\t\t|| check->v.movetype == MOVETYPE_FOLLOW\n#endif\n\t\t|| check->v.movetype == MOVETYPE_NOCLIP)\n\t\t\tcontinue;\n\n\t// if the entity is standing on the pusher, it will definately be moved\n\t\tif ( ! ( ((int)check->v.flags & FL_ONGROUND)\n\t\t&& PROG_TO_EDICT(check->v.groundentity) == pusher) )\n\t\t{\n\t\t\tif ( check->v.absmin[0] >= maxs[0]\n\t\t\t|| check->v.absmin[1] >= maxs[1]\n\t\t\t|| check->v.absmin[2] >= maxs[2]\n\t\t\t|| check->v.absmax[0] <= mins[0]\n\t\t\t|| check->v.absmax[1] <= mins[1]\n\t\t\t|| check->v.absmax[2] <= mins[2] )\n\t\t\t\tcontinue;\n\n\t\t// see if the ent's bbox is inside the pusher's final position\n\t\t\tif (!SV_TestEntityPosition (check))\n\t\t\t\tcontinue;\n\t\t}\n\n\t// remove the onground flag for non-players\n\t\tif (check->v.movetype != MOVETYPE_WALK)\n\t\t\tcheck->v.flags = (int)check->v.flags & ~FL_ONGROUND;\n\n\t\tVectorCopy (check->v.origin, entorig);\n\t\tVectorCopy (check->v.origin, moved_from[num_moved]);\n\t\tmoved_edict[num_moved] = check;\n\t\tnum_moved++;\n\n\t\t// try moving the contacted entity\n\t\tpusher->v.solid = SOLID_NOT;\n\t\tSV_PushEntity (check, move);\n\t\tpusher->v.solid = SOLID_BSP;\n\n\t// if it is still inside the pusher, block\n\t\tblock = SV_TestEntityPosition (check);\n\t\tif (block)\n\t\t{\t// fail the move\n\t\t\tif (check->v.mins[0] == check->v.maxs[0])\n\t\t\t\tcontinue;\n\t\t\tif (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)\n\t\t\t{\t// corpse\n\t\t\t\tcheck->v.mins[0] = check->v.mins[1] = 0;\n\t\t\t\tVectorCopy (check->v.mins, check->v.maxs);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tVectorCopy (entorig, check->v.origin);\n\t\t\tSV_LinkEdict (check, true);\n\n\t\t\tVectorCopy (pushorig, pusher->v.origin);\n\t\t\tSV_LinkEdict (pusher, false);\n\t\t\tpusher->v.ltime -= movetime;\n\n\t\t\t// if the pusher has a \"blocked\" function, call it\n\t\t\t// otherwise, just stay in place until the obstacle is gone\n\t\t\tif (pusher->v.blocked)\n\t\t\t{\n\t\t\t\tpr_global_struct->self = EDICT_TO_PROG(pusher);\n\t\t\t\tpr_global_struct->other = EDICT_TO_PROG(check);\n\t\t\t\tPR_ExecuteProgram (pusher->v.blocked);\n\t\t\t}\n\n\t\t// move back any entities we already moved\n\t\t\tfor (i=0 ; i<num_moved ; i++)\n\t\t\t{\n\t\t\t\tVectorCopy (moved_from[i], moved_edict[i]->v.origin);\n\t\t\t\tSV_LinkEdict (moved_edict[i], false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n\n}\n\n#ifdef QUAKE2\n/*\n============\nSV_PushRotate\n\n============\n*/\nvoid SV_PushRotate (edict_t *pusher, float movetime)\n{\n\tint\t\t\ti, e;\n\tedict_t\t\t*check, *block;\n\tvec3_t\t\tmove, a, amove;\n\tvec3_t\t\tentorig, pushorig;\n\tint\t\t\tnum_moved;\n\tedict_t\t\t*moved_edict[MAX_EDICTS];\n\tvec3_t\t\tmoved_from[MAX_EDICTS];\n\tvec3_t\t\torg, org2;\n\tvec3_t\t\tforward, right, up;\n\n\tif (!pusher->v.avelocity[0] && !pusher->v.avelocity[1] && !pusher->v.avelocity[2])\n\t{\n\t\tpusher->v.ltime += movetime;\n\t\treturn;\n\t}\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tamove[i] = pusher->v.avelocity[i] * movetime;\n\n\tVectorSubtract (vec3_origin, amove, a);\n\tAngleVectors (a, forward, right, up);\n\n\tVectorCopy (pusher->v.angles, pushorig);\n\n// move the pusher to it's final position\n\n\tVectorAdd (pusher->v.angles, amove, pusher->v.angles);\n\tpusher->v.ltime += movetime;\n\tSV_LinkEdict (pusher, false);\n\n\n// see if any solid entities are inside the final position\n\tnum_moved = 0;\n\tcheck = NEXT_EDICT(sv.edicts);\n\tfor (e=1 ; e<sv.num_edicts ; e++, check = NEXT_EDICT(check))\n\t{\n\t\tif (check->free)\n\t\t\tcontinue;\n\t\tif (check->v.movetype == MOVETYPE_PUSH\n\t\t|| check->v.movetype == MOVETYPE_NONE\n\t\t|| check->v.movetype == MOVETYPE_FOLLOW\n\t\t|| check->v.movetype == MOVETYPE_NOCLIP)\n\t\t\tcontinue;\n\n\t// if the entity is standing on the pusher, it will definately be moved\n\t\tif ( ! ( ((int)check->v.flags & FL_ONGROUND)\n\t\t&& PROG_TO_EDICT(check->v.groundentity) == pusher) )\n\t\t{\n\t\t\tif ( check->v.absmin[0] >= pusher->v.absmax[0]\n\t\t\t|| check->v.absmin[1] >= pusher->v.absmax[1]\n\t\t\t|| check->v.absmin[2] >= pusher->v.absmax[2]\n\t\t\t|| check->v.absmax[0] <= pusher->v.absmin[0]\n\t\t\t|| check->v.absmax[1] <= pusher->v.absmin[1]\n\t\t\t|| check->v.absmax[2] <= pusher->v.absmin[2] )\n\t\t\t\tcontinue;\n\n\t\t// see if the ent's bbox is inside the pusher's final position\n\t\t\tif (!SV_TestEntityPosition (check))\n\t\t\t\tcontinue;\n\t\t}\n\n\t// remove the onground flag for non-players\n\t\tif (check->v.movetype != MOVETYPE_WALK)\n\t\t\tcheck->v.flags = (int)check->v.flags & ~FL_ONGROUND;\n\n\t\tVectorCopy (check->v.origin, entorig);\n\t\tVectorCopy (check->v.origin, moved_from[num_moved]);\n\t\tmoved_edict[num_moved] = check;\n\t\tnum_moved++;\n\n\t\t// calculate destination position\n\t\tVectorSubtract (check->v.origin, pusher->v.origin, org);\n\t\torg2[0] = DotProduct (org, forward);\n\t\torg2[1] = -DotProduct (org, right);\n\t\torg2[2] = DotProduct (org, up);\n\t\tVectorSubtract (org2, org, move);\n\n\t\t// try moving the contacted entity\n\t\tpusher->v.solid = SOLID_NOT;\n\t\tSV_PushEntity (check, move);\n\t\tpusher->v.solid = SOLID_BSP;\n\n\t// if it is still inside the pusher, block\n\t\tblock = SV_TestEntityPosition (check);\n\t\tif (block)\n\t\t{\t// fail the move\n\t\t\tif (check->v.mins[0] == check->v.maxs[0])\n\t\t\t\tcontinue;\n\t\t\tif (check->v.solid == SOLID_NOT || check->v.solid == SOLID_TRIGGER)\n\t\t\t{\t// corpse\n\t\t\t\tcheck->v.mins[0] = check->v.mins[1] = 0;\n\t\t\t\tVectorCopy (check->v.mins, check->v.maxs);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tVectorCopy (entorig, check->v.origin);\n\t\t\tSV_LinkEdict (check, true);\n\n\t\t\tVectorCopy (pushorig, pusher->v.angles);\n\t\t\tSV_LinkEdict (pusher, false);\n\t\t\tpusher->v.ltime -= movetime;\n\n\t\t\t// if the pusher has a \"blocked\" function, call it\n\t\t\t// otherwise, just stay in place until the obstacle is gone\n\t\t\tif (pusher->v.blocked)\n\t\t\t{\n\t\t\t\tpr_global_struct->self = EDICT_TO_PROG(pusher);\n\t\t\t\tpr_global_struct->other = EDICT_TO_PROG(check);\n\t\t\t\tPR_ExecuteProgram (pusher->v.blocked);\n\t\t\t}\n\n\t\t// move back any entities we already moved\n\t\t\tfor (i=0 ; i<num_moved ; i++)\n\t\t\t{\n\t\t\t\tVectorCopy (moved_from[i], moved_edict[i]->v.origin);\n\t\t\t\tVectorSubtract (moved_edict[i]->v.angles, amove, moved_edict[i]->v.angles);\n\t\t\t\tSV_LinkEdict (moved_edict[i], false);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tVectorAdd (check->v.angles, amove, check->v.angles);\n\t\t}\n\t}\n\n\n}\n#endif\n\n/*\n================\nSV_Physics_Pusher\n\n================\n*/\nvoid SV_Physics_Pusher (edict_t *ent)\n{\n\tfloat\tthinktime;\n\tfloat\toldltime;\n\tfloat\tmovetime;\n\n\toldltime = ent->v.ltime;\n\n\tthinktime = ent->v.nextthink;\n\tif (thinktime < ent->v.ltime + host_frametime)\n\t{\n\t\tmovetime = thinktime - ent->v.ltime;\n\t\tif (movetime < 0)\n\t\t\tmovetime = 0;\n\t}\n\telse\n\t\tmovetime = host_frametime;\n\n\tif (movetime)\n\t{\n#ifdef QUAKE2\n\t\tif (ent->v.avelocity[0] || ent->v.avelocity[1] || ent->v.avelocity[2])\n\t\t\tSV_PushRotate (ent, movetime);\n\t\telse\n#endif\n\t\t\tSV_PushMove (ent, movetime);\t// advances ent->v.ltime if not blocked\n\t}\n\n\tif (thinktime > oldltime && thinktime <= ent->v.ltime)\n\t{\n\t\tent->v.nextthink = 0;\n\t\tpr_global_struct->time = sv.time;\n\t\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\t\tpr_global_struct->other = EDICT_TO_PROG(sv.edicts);\n\t\tPR_ExecuteProgram (ent->v.think);\n\t\tif (ent->free)\n\t\t\treturn;\n\t}\n\n}\n\n\n/*\n===============================================================================\n\nCLIENT MOVEMENT\n\n===============================================================================\n*/\n\n/*\n=============\nSV_CheckStuck\n\nThis is a big hack to try and fix the rare case of getting stuck in the world\nclipping hull.\n=============\n*/\nvoid SV_CheckStuck (edict_t *ent)\n{\n\tint\t\ti, j;\n\tint\t\tz;\n\tvec3_t\torg;\n\n\tif (!SV_TestEntityPosition(ent))\n\t{\n\t\tVectorCopy (ent->v.origin, ent->v.oldorigin);\n\t\treturn;\n\t}\n\n\tVectorCopy (ent->v.origin, org);\n\tVectorCopy (ent->v.oldorigin, ent->v.origin);\n\tif (!SV_TestEntityPosition(ent))\n\t{\n\t\tCon_DPrintf (\"Unstuck.\\n\");\n\t\tSV_LinkEdict (ent, true);\n\t\treturn;\n\t}\n\n\tfor (z=0 ; z< 18 ; z++)\n\t\tfor (i=-1 ; i <= 1 ; i++)\n\t\t\tfor (j=-1 ; j <= 1 ; j++)\n\t\t\t{\n\t\t\t\tent->v.origin[0] = org[0] + i;\n\t\t\t\tent->v.origin[1] = org[1] + j;\n\t\t\t\tent->v.origin[2] = org[2] + z;\n\t\t\t\tif (!SV_TestEntityPosition(ent))\n\t\t\t\t{\n\t\t\t\t\tCon_DPrintf (\"Unstuck.\\n\");\n\t\t\t\t\tSV_LinkEdict (ent, true);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\tVectorCopy (org, ent->v.origin);\n\tCon_DPrintf (\"player is stuck.\\n\");\n}\n\n\n/*\n=============\nSV_CheckWater\n=============\n*/\nbool SV_CheckWater (edict_t *ent)\n{\n\tvec3_t\tpoint;\n\tint\t\tcont;\n#ifdef QUAKE2\n\tint\t\ttruecont;\n#endif\n\n\tpoint[0] = ent->v.origin[0];\n\tpoint[1] = ent->v.origin[1];\n\tpoint[2] = ent->v.origin[2] + ent->v.mins[2] + 1;\n\n\tent->v.waterlevel = 0;\n\tent->v.watertype = CONTENTS_EMPTY;\n\tcont = SV_PointContents (point);\n\tif (cont <= CONTENTS_WATER)\n\t{\n#ifdef QUAKE2\n\t\ttruecont = SV_TruePointContents (point);\n#endif\n\t\tent->v.watertype = cont;\n\t\tent->v.waterlevel = 1;\n\t\tpoint[2] = ent->v.origin[2] + (ent->v.mins[2] + ent->v.maxs[2])*0.5;\n\t\tcont = SV_PointContents (point);\n\t\tif (cont <= CONTENTS_WATER)\n\t\t{\n\t\t\tent->v.waterlevel = 2;\n\t\t\tpoint[2] = ent->v.origin[2] + ent->v.view_ofs[2];\n\t\t\tcont = SV_PointContents (point);\n\t\t\tif (cont <= CONTENTS_WATER)\n\t\t\t\tent->v.waterlevel = 3;\n\t\t}\n#ifdef QUAKE2\n\t\tif (truecont <= CONTENTS_CURRENT_0 && truecont >= CONTENTS_CURRENT_DOWN)\n\t\t{\n\t\t\tstatic vec3_t current_table[] =\n\t\t\t{\n\t\t\t\t{1, 0, 0},\n\t\t\t\t{0, 1, 0},\n\t\t\t\t{-1, 0, 0},\n\t\t\t\t{0, -1, 0},\n\t\t\t\t{0, 0, 1},\n\t\t\t\t{0, 0, -1}\n\t\t\t};\n\n\t\t\tVectorMA (ent->v.basevelocity, 150.0*ent->v.waterlevel/3.0, current_table[CONTENTS_CURRENT_0 - truecont], ent->v.basevelocity);\n\t\t}\n#endif\n\t}\n\n\treturn ent->v.waterlevel > 1;\n}\n\n/*\n============\nSV_WallFriction\n\n============\n*/\nvoid SV_WallFriction (edict_t *ent, trace_t *trace)\n{\n\tvec3_t\t\tforward, right, up;\n\tfloat\t\td, i;\n\tvec3_t\t\tinto, side;\n\n\tAngleVectors (ent->v.v_angle, forward, right, up);\n\td = DotProduct (trace->plane.normal, forward);\n\n\td += 0.5;\n\tif (d >= 0)\n\t\treturn;\n\n// cut the tangential velocity\n\ti = DotProduct (trace->plane.normal, ent->v.velocity);\n\tVectorScale (trace->plane.normal, i, into);\n\tVectorSubtract (ent->v.velocity, into, side);\n\n\tent->v.velocity[0] = side[0] * (1 + d);\n\tent->v.velocity[1] = side[1] * (1 + d);\n}\n\n/*\n=====================\nSV_TryUnstick\n\nPlayer has come to a dead stop, possibly due to the problem with limited\nfloat precision at some angle joins in the BSP hull.\n\nTry fixing by pushing one pixel in each direction.\n\nThis is a hack, but in the interest of good gameplay...\n======================\n*/\nint SV_TryUnstick (edict_t *ent, vec3_t oldvel)\n{\n\tint\t\ti;\n\tvec3_t\toldorg;\n\tvec3_t\tdir;\n\tint\t\tclip;\n\ttrace_t\tsteptrace;\n\n\tVectorCopy (ent->v.origin, oldorg);\n\tVectorCopy (vec3_origin, dir);\n\n\tfor (i=0 ; i<8 ; i++)\n\t{\n// try pushing a little in an axial direction\n\t\tswitch (i)\n\t\t{\n\t\t\tcase 0:\tdir[0] = 2; dir[1] = 0; break;\n\t\t\tcase 1:\tdir[0] = 0; dir[1] = 2; break;\n\t\t\tcase 2:\tdir[0] = -2; dir[1] = 0; break;\n\t\t\tcase 3:\tdir[0] = 0; dir[1] = -2; break;\n\t\t\tcase 4:\tdir[0] = 2; dir[1] = 2; break;\n\t\t\tcase 5:\tdir[0] = -2; dir[1] = 2; break;\n\t\t\tcase 6:\tdir[0] = 2; dir[1] = -2; break;\n\t\t\tcase 7:\tdir[0] = -2; dir[1] = -2; break;\n\t\t}\n\n\t\tSV_PushEntity (ent, dir);\n\n// retry the original move\n\t\tent->v.velocity[0] = oldvel[0];\n\t\tent->v. velocity[1] = oldvel[1];\n\t\tent->v. velocity[2] = 0;\n\t\tclip = SV_FlyMove (ent, 0.1, &steptrace);\n\n\t\tif ( fabs(oldorg[1] - ent->v.origin[1]) > 4\n\t\t|| fabs(oldorg[0] - ent->v.origin[0]) > 4 )\n\t\t{\n//Con_DPrintf (\"unstuck!\\n\");\n\t\t\treturn clip;\n\t\t}\n\n// go back to the original pos and try again\n\t\tVectorCopy (oldorg, ent->v.origin);\n\t}\n\n\tVectorCopy (vec3_origin, ent->v.velocity);\n\treturn 7;\t\t// still not moving\n}\n\n/*\n=====================\nSV_WalkMove\n\nOnly used by players\n======================\n*/\n#define\tSTEPSIZE\t18\nvoid SV_WalkMove (edict_t *ent)\n{\n\tvec3_t\t\tupmove, downmove;\n\tvec3_t\t\toldorg, oldvel;\n\tvec3_t\t\tnosteporg, nostepvel;\n\tint\t\t\tclip;\n\tint\t\t\toldonground;\n\ttrace_t\t\tsteptrace, downtrace;\n\n//\n// do a regular slide move unless it looks like you ran into a step\n//\n\toldonground = (int)ent->v.flags & FL_ONGROUND;\n\tent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;\n\n\tVectorCopy (ent->v.origin, oldorg);\n\tVectorCopy (ent->v.velocity, oldvel);\n\n\tclip = SV_FlyMove (ent, host_frametime, &steptrace);\n\n\tif ( !(clip & 2) )\n\t\treturn;\t\t// move didn't block on a step\n\n\tif (!oldonground && ent->v.waterlevel == 0)\n\t\treturn;\t\t// don't stair up while jumping\n\n\tif (ent->v.movetype != MOVETYPE_WALK)\n\t\treturn;\t\t// gibbed by a trigger\n\n\tif (sv_nostep.value)\n\t\treturn;\n\n\tif ( (int)sv_player->v.flags & FL_WATERJUMP )\n\t\treturn;\n\n\tVectorCopy (ent->v.origin, nosteporg);\n\tVectorCopy (ent->v.velocity, nostepvel);\n\n//\n// try moving up and forward to go up a step\n//\n\tVectorCopy (oldorg, ent->v.origin);\t// back to start pos\n\n\tVectorCopy (vec3_origin, upmove);\n\tVectorCopy (vec3_origin, downmove);\n\tupmove[2] = STEPSIZE;\n\tdownmove[2] = -STEPSIZE + oldvel[2]*host_frametime;\n\n// move up\n\tSV_PushEntity (ent, upmove);\t// FIXME: don't link?\n\n// move forward\n\tent->v.velocity[0] = oldvel[0];\n\tent->v. velocity[1] = oldvel[1];\n\tent->v. velocity[2] = 0;\n\tclip = SV_FlyMove (ent, host_frametime, &steptrace);\n\n// check for stuckness, possibly due to the limited precision of floats\n// in the clipping hulls\n\tif (clip)\n\t{\n\t\tif ( fabs(oldorg[1] - ent->v.origin[1]) < 0.03125\n\t\t&& fabs(oldorg[0] - ent->v.origin[0]) < 0.03125 )\n\t\t{\t// stepping up didn't make any progress\n\t\t\tclip = SV_TryUnstick (ent, oldvel);\n\t\t}\n\t}\n\n// extra friction based on view angle\n\tif ( clip & 2 )\n\t\tSV_WallFriction (ent, &steptrace);\n\n// move down\n\tdowntrace = SV_PushEntity (ent, downmove);\t// FIXME: don't link?\n\n\tif (downtrace.plane.normal[2] > 0.7)\n\t{\n\t\tif (ent->v.solid == SOLID_BSP)\n\t\t{\n\t\t\tent->v.flags =\t(int)ent->v.flags | FL_ONGROUND;\n\t\t\tent->v.groundentity = EDICT_TO_PROG(downtrace.ent);\n\t\t}\n\t}\n\telse\n\t{\n// if the push down didn't end up on good ground, use the move without\n// the step up.  This happens near wall / slope combinations, and can\n// cause the player to hop up higher on a slope too steep to climb\n\t\tVectorCopy (nosteporg, ent->v.origin);\n\t\tVectorCopy (nostepvel, ent->v.velocity);\n\t}\n}\n\n\n/*\n================\nSV_Physics_Client\n\nPlayer character actions\n================\n*/\nvoid SV_Physics_Client (edict_t\t*ent, int num)\n{\n\tif ( ! svs.clients[num-1].active )\n\t\treturn;\t\t// unconnected slot\n\n//\n// call standard client pre-think\n//\n\tpr_global_struct->time = sv.time;\n\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\tPR_ExecuteProgram (pr_global_struct->PlayerPreThink);\n\n//\n// do a move\n//\n\tSV_CheckVelocity (ent);\n\n//\n// decide which move function to call\n//\n\tswitch ((int)ent->v.movetype)\n\t{\n\tcase MOVETYPE_NONE:\n\t\tif (!SV_RunThink (ent))\n\t\t\treturn;\n\t\tbreak;\n\n\tcase MOVETYPE_WALK:\n\t\tif (!SV_RunThink (ent))\n\t\t\treturn;\n\t\tif (!SV_CheckWater (ent) && ! ((int)ent->v.flags & FL_WATERJUMP) )\n\t\t\tSV_AddGravity (ent);\n\t\tSV_CheckStuck (ent);\n#ifdef QUAKE2\n\t\tVectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n#endif\n\t\tSV_WalkMove (ent);\n\n#ifdef QUAKE2\n\t\tVectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n#endif\n\t\tbreak;\n\n\tcase MOVETYPE_TOSS:\n\tcase MOVETYPE_BOUNCE:\n\t\tSV_Physics_Toss (ent);\n\t\tbreak;\n\n\tcase MOVETYPE_FLY:\n\t\tif (!SV_RunThink (ent))\n\t\t\treturn;\n\t\tSV_FlyMove (ent, host_frametime, NULL);\n\t\tbreak;\n\n\tcase MOVETYPE_NOCLIP:\n\t\tif (!SV_RunThink (ent))\n\t\t\treturn;\n\t\tVectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);\n\t\tbreak;\n\n\tdefault:\n\t\tSys_Error (\"SV_Physics_client: bad movetype %i\", (int)ent->v.movetype);\n\t}\n\n//\n// call standard player post-think\n//\n\tSV_LinkEdict (ent, true);\n\n\tpr_global_struct->time = sv.time;\n\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\tPR_ExecuteProgram (pr_global_struct->PlayerPostThink);\n}\n\n//============================================================================\n\n/*\n=============\nSV_Physics_None\n\nNon moving objects can only think\n=============\n*/\nvoid SV_Physics_None (edict_t *ent)\n{\n// regular thinking\n\tSV_RunThink (ent);\n}\n\n#ifdef QUAKE2\n/*\n=============\nSV_Physics_Follow\n\nEntities that are \"stuck\" to another entity\n=============\n*/\nvoid SV_Physics_Follow (edict_t *ent)\n{\n// regular thinking\n\tSV_RunThink (ent);\n\tVectorAdd (PROG_TO_EDICT(ent->v.aiment)->v.origin, ent->v.v_angle, ent->v.origin);\n\tSV_LinkEdict (ent, true);\n}\n#endif\n\n/*\n=============\nSV_Physics_Noclip\n\nA moving object that doesn't obey physics\n=============\n*/\nvoid SV_Physics_Noclip (edict_t *ent)\n{\n// regular thinking\n\tif (!SV_RunThink (ent))\n\t\treturn;\n\n\tVectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);\n\tVectorMA (ent->v.origin, host_frametime, ent->v.velocity, ent->v.origin);\n\n\tSV_LinkEdict (ent, false);\n}\n\n/*\n==============================================================================\n\nTOSS / BOUNCE\n\n==============================================================================\n*/\n\n/*\n=============\nSV_CheckWaterTransition\n\n=============\n*/\nvoid SV_CheckWaterTransition (edict_t *ent)\n{\n\tint\t\tcont;\n#ifdef QUAKE2\n\tvec3_t\tpoint;\n\n\tpoint[0] = ent->v.origin[0];\n\tpoint[1] = ent->v.origin[1];\n\tpoint[2] = ent->v.origin[2] + ent->v.mins[2] + 1;\n\tcont = SV_PointContents (point);\n#else\n\tcont = SV_PointContents (ent->v.origin);\n#endif\n\tif (!ent->v.watertype)\n\t{\t// just spawned here\n\t\tent->v.watertype = cont;\n\t\tent->v.waterlevel = 1;\n\t\treturn;\n\t}\n\n\tif (cont <= CONTENTS_WATER)\n\t{\n\t\tif (ent->v.watertype == CONTENTS_EMPTY)\n\t\t{\t// just crossed into water\n\t\t\tSV_StartSound (ent, 0, \"misc/h2ohit1.wav\", 255, 1);\n\t\t}\n\t\tent->v.watertype = cont;\n\t\tent->v.waterlevel = 1;\n\t}\n\telse\n\t{\n\t\tif (ent->v.watertype != CONTENTS_EMPTY)\n\t\t{\t// just crossed into water\n\t\t\tSV_StartSound (ent, 0, \"misc/h2ohit1.wav\", 255, 1);\n\t\t}\n\t\tent->v.watertype = CONTENTS_EMPTY;\n\t\tent->v.waterlevel = cont;\n\t}\n}\n\n/*\n=============\nSV_Physics_Toss\n\nToss, bounce, and fly movement.  When onground, do nothing.\n=============\n*/\nvoid SV_Physics_Toss (edict_t *ent)\n{\n\ttrace_t\ttrace;\n\tvec3_t\tmove;\n\tfloat\tbackoff;\n#ifdef QUAKE2\n\tedict_t\t*groundentity;\n\n\tgroundentity = PROG_TO_EDICT(ent->v.groundentity);\n\tif ((int)groundentity->v.flags & FL_CONVEYOR)\n\t\tVectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);\n\telse\n\t\tVectorCopy(vec_origin, ent->v.basevelocity);\n\tSV_CheckWater (ent);\n#endif\n\t// regular thinking\n\tif (!SV_RunThink (ent))\n\t\treturn;\n\n#ifdef QUAKE2\n\tif (ent->v.velocity[2] > 0)\n\t\tent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;\n\n\tif ( ((int)ent->v.flags & FL_ONGROUND) )\n//@@\n\t\tif (VectorCompare(ent->v.basevelocity, vec_origin))\n\t\t\treturn;\n\n\tSV_CheckVelocity (ent);\n\n// add gravity\n\tif (! ((int)ent->v.flags & FL_ONGROUND)\n\t\t&& ent->v.movetype != MOVETYPE_FLY\n\t\t&& ent->v.movetype != MOVETYPE_BOUNCEMISSILE\n\t\t&& ent->v.movetype != MOVETYPE_FLYMISSILE)\n\t\t\tSV_AddGravity (ent);\n\n#else\n// if onground, return without moving\n\tif ( ((int)ent->v.flags & FL_ONGROUND) )\n\t\treturn;\n\n\tSV_CheckVelocity (ent);\n\n// add gravity\n\tif (ent->v.movetype != MOVETYPE_FLY\n\t&& ent->v.movetype != MOVETYPE_FLYMISSILE)\n\t\tSV_AddGravity (ent);\n#endif\n\n// move angles\n\tVectorMA (ent->v.angles, host_frametime, ent->v.avelocity, ent->v.angles);\n\n// move origin\n#ifdef QUAKE2\n\tVectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n#endif\n\tVectorScale (ent->v.velocity, host_frametime, move);\n\ttrace = SV_PushEntity (ent, move);\n#ifdef QUAKE2\n\tVectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n#endif\n\tif (trace.fraction == 1)\n\t\treturn;\n\tif (ent->free)\n\t\treturn;\n\n\tif (ent->v.movetype == MOVETYPE_BOUNCE)\n\t\tbackoff = 1.5;\n#ifdef QUAKE2\n\telse if (ent->v.movetype == MOVETYPE_BOUNCEMISSILE)\n\t\tbackoff = 2.0;\n#endif\n\telse\n\t\tbackoff = 1;\n\n\tClipVelocity (ent->v.velocity, trace.plane.normal, ent->v.velocity, backoff);\n\n// stop if on ground\n\tif (trace.plane.normal[2] > 0.7)\n\t{\n#ifdef QUAKE2\n\t\tif (ent->v.velocity[2] < 60 || (ent->v.movetype != MOVETYPE_BOUNCE && ent->v.movetype != MOVETYPE_BOUNCEMISSILE))\n#else\n\t\tif (ent->v.velocity[2] < 60 || ent->v.movetype != MOVETYPE_BOUNCE)\n#endif\n\t\t{\n\t\t\tent->v.flags = (int)ent->v.flags | FL_ONGROUND;\n\t\t\tent->v.groundentity = EDICT_TO_PROG(trace.ent);\n\t\t\tVectorCopy (vec3_origin, ent->v.velocity);\n\t\t\tVectorCopy (vec3_origin, ent->v.avelocity);\n\t\t}\n\t}\n\n// check for in water\n\tSV_CheckWaterTransition (ent);\n}\n\n/*\n===============================================================================\n\nSTEPPING MOVEMENT\n\n===============================================================================\n*/\n\n/*\n=============\nSV_Physics_Step\n\nMonsters freefall when they don't have a ground entity, otherwise\nall movement is done with discrete steps.\n\nThis is also used for objects that have become still on the ground, but\nwill fall if the floor is pulled out from under them.\n=============\n*/\n#ifdef QUAKE2\nvoid SV_Physics_Step (edict_t *ent)\n{\n\tbool\twasonground;\n\tbool\tinwater;\n\tbool\thitsound = false;\n\tfloat\t\t*vel;\n\tfloat\t\tspeed, newspeed, control;\n\tfloat\t\tfriction;\n\tedict_t\t\t*groundentity;\n\n\tgroundentity = PROG_TO_EDICT(ent->v.groundentity);\n\tif ((int)groundentity->v.flags & FL_CONVEYOR)\n\t\tVectorScale(groundentity->v.movedir, groundentity->v.speed, ent->v.basevelocity);\n\telse\n\t\tVectorCopy(vec_origin, ent->v.basevelocity);\n//@@\n\tpr_global_struct->time = sv.time;\n\tpr_global_struct->self = EDICT_TO_PROG(ent);\n\tPF_WaterMove();\n\n\tSV_CheckVelocity (ent);\n\n\twasonground = (int)ent->v.flags & FL_ONGROUND;\n//\tent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;\n\n\t// add gravity except:\n\t//   flying monsters\n\t//   swimming monsters who are in the water\n\tinwater = SV_CheckWater(ent);\n\tif (! wasonground)\n\t\tif (!((int)ent->v.flags & FL_FLY))\n\t\t\tif (!(((int)ent->v.flags & FL_SWIM) && (ent->v.waterlevel > 0)))\n\t\t\t{\n\t\t\t\tif (ent->v.velocity[2] < sv_gravity.value*-0.1)\n\t\t\t\t\thitsound = true;\n\t\t\t\tif (!inwater)\n\t\t\t\t\tSV_AddGravity (ent);\n\t\t\t}\n\n\tif (!VectorCompare(ent->v.velocity, vec_origin) || !VectorCompare(ent->v.basevelocity, vec_origin))\n\t{\n\t\tent->v.flags = (int)ent->v.flags & ~FL_ONGROUND;\n\t\t// apply friction\n\t\t// let dead monsters who aren't completely onground slide\n\t\tif (wasonground)\n\t\t\tif (!(ent->v.health <= 0.0 && !SV_CheckBottom(ent)))\n\t\t\t{\n\t\t\t\tvel = ent->v.velocity;\n\t\t\t\tspeed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);\n\t\t\t\tif (speed)\n\t\t\t\t{\n\t\t\t\t\tfriction = sv_friction.value;\n\n\t\t\t\t\tcontrol = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;\n\t\t\t\t\tnewspeed = speed - host_frametime*control*friction;\n\n\t\t\t\t\tif (newspeed < 0)\n\t\t\t\t\t\tnewspeed = 0;\n\t\t\t\t\tnewspeed /= speed;\n\n\t\t\t\t\tvel[0] = vel[0] * newspeed;\n\t\t\t\t\tvel[1] = vel[1] * newspeed;\n\t\t\t\t}\n\t\t\t}\n\n\t\tVectorAdd (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n\t\tSV_FlyMove (ent, host_frametime, NULL);\n\t\tVectorSubtract (ent->v.velocity, ent->v.basevelocity, ent->v.velocity);\n\n\t\t// determine if it's on solid ground at all\n\t\t{\n\t\t\tvec3_t\tmins, maxs, point;\n\t\t\tint\t\tx, y;\n\n\t\t\tVectorAdd (ent->v.origin, ent->v.mins, mins);\n\t\t\tVectorAdd (ent->v.origin, ent->v.maxs, maxs);\n\n\t\t\tpoint[2] = mins[2] - 1;\n\t\t\tfor\t(x=0 ; x<=1 ; x++)\n\t\t\t\tfor\t(y=0 ; y<=1 ; y++)\n\t\t\t\t{\n\t\t\t\t\tpoint[0] = x ? maxs[0] : mins[0];\n\t\t\t\t\tpoint[1] = y ? maxs[1] : mins[1];\n\t\t\t\t\tif (SV_PointContents (point) == CONTENTS_SOLID)\n\t\t\t\t\t{\n\t\t\t\t\t\tent->v.flags = (int)ent->v.flags | FL_ONGROUND;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t}\n\n\t\tSV_LinkEdict (ent, true);\n\n\t\tif ((int)ent->v.flags & FL_ONGROUND)\n\t\t\tif (!wasonground)\n\t\t\t\tif (hitsound)\n\t\t\t\t\tSV_StartSound (ent, 0, \"demon/dland2.wav\", 255, 1);\n\t}\n\n// regular thinking\n\tSV_RunThink (ent);\n\tSV_CheckWaterTransition (ent);\n}\n#else\nvoid SV_Physics_Step (edict_t *ent)\n{\n\tbool\thitsound;\n\n// freefall if not onground\n\tif ( ! ((int)ent->v.flags & (FL_ONGROUND | FL_FLY | FL_SWIM) ) )\n\t{\n\t\tif (ent->v.velocity[2] < sv_gravity.value*-0.1)\n\t\t\thitsound = true;\n\t\telse\n\t\t\thitsound = false;\n\n\t\tSV_AddGravity (ent);\n\t\tSV_CheckVelocity (ent);\n\t\tSV_FlyMove (ent, host_frametime, NULL);\n\t\tSV_LinkEdict (ent, true);\n\n\t\tif ( (int)ent->v.flags & FL_ONGROUND )\t// just hit ground\n\t\t{\n\t\t\tif (hitsound)\n\t\t\t\tSV_StartSound (ent, 0, \"demon/dland2.wav\", 255, 1);\n\t\t}\n\t}\n\n// regular thinking\n\tSV_RunThink (ent);\n\n\tSV_CheckWaterTransition (ent);\n}\n#endif\n\n//============================================================================\n\n/*\n================\nSV_Physics\n\n================\n*/\nvoid SV_Physics (void)\n{\n\tint\t\ti;\n\tedict_t\t*ent;\n\textern dfunction_t *EndFrameQC;\n\n// let the progs know that a new frame has started\n\tpr_global_struct->self = EDICT_TO_PROG(sv.edicts);\n\tpr_global_struct->other = EDICT_TO_PROG(sv.edicts);\n\tpr_global_struct->time = sv.time;\n\tPR_ExecuteProgram (pr_global_struct->StartFrame);\n\n//SV_CheckAllEnts ();\n\n//\n// treat each object in turn\n//\n\tent = sv.edicts;\n\tfor (i=0 ; i<sv.num_edicts ; i++, ent = NEXT_EDICT(ent))\n\t{\n\t\tif (ent->free)\n\t\t\tcontinue;\n\n\t\tif (pr_global_struct->force_retouch)\n\t\t{\n\t\t\tSV_LinkEdict (ent, true);\t// force retouch even for stationary\n\t\t}\n\n\t\tif (i > 0 && i <= svs.maxclients)\n\t\t\tSV_Physics_Client (ent, i);\n\t\telse if (ent->v.movetype == MOVETYPE_PUSH)\n\t\t\tSV_Physics_Pusher (ent);\n\t\telse if (ent->v.movetype == MOVETYPE_NONE)\n\t\t\tSV_Physics_None (ent);\n#ifdef QUAKE2\n\t\telse if (ent->v.movetype == MOVETYPE_FOLLOW)\n\t\t\tSV_Physics_Follow (ent);\n#endif\n\t\telse if (ent->v.movetype == MOVETYPE_NOCLIP)\n\t\t\tSV_Physics_Noclip (ent);\n\t\telse if (ent->v.movetype == MOVETYPE_STEP)\n\t\t\tSV_Physics_Step (ent);\n\t\telse if (ent->v.movetype == MOVETYPE_TOSS\n\t\t|| ent->v.movetype == MOVETYPE_BOUNCE\n#ifdef QUAKE2\n\t\t|| ent->v.movetype == MOVETYPE_BOUNCEMISSILE\n#endif\n\t\t|| ent->v.movetype == MOVETYPE_FLY\n\t\t|| ent->v.movetype == MOVETYPE_FLYMISSILE)\n\t\t\tSV_Physics_Toss (ent);\n\t\telse\n\t\t\tSys_Error (\"SV_Physics: bad movetype %i\", (int)ent->v.movetype);\n\t}\n\n\tif (pr_global_struct->force_retouch)\n\t\tpr_global_struct->force_retouch--;\n\t\n\t// LordHavoc: endframe support\n\tif (EndFrameQC)\n\t{\n\t\tpr_global_struct->self = EDICT_TO_PROG(sv.edicts);\n\t\tpr_global_struct->other = EDICT_TO_PROG(sv.edicts);\n\t\tpr_global_struct->time = sv.time;\n\t\tPR_ExecuteProgram ((func_t)(EndFrameQC - pr_functions));\n\t}\n\n\tsv.time += host_frametime;\n}\n\n\n#ifdef QUAKE2\ntrace_t SV_Trace_Toss (edict_t *ent, edict_t *ignore)\n{\n\tedict_t\ttempent, *tent;\n\ttrace_t\ttrace;\n\tvec3_t\tmove;\n\tvec3_t\tend;\n\tdouble\tsave_frametime;\n//\textern particle_t\t*active_particles, *free_particles;\n//\tparticle_t\t*p;\n\n\n\tsave_frametime = host_frametime;\n\thost_frametime = 0.05;\n\n\tmemcpy(&tempent, ent, sizeof(edict_t));\n\ttent = &tempent;\n\n\twhile (1)\n\t{\n\t\tSV_CheckVelocity (tent);\n\t\tSV_AddGravity (tent);\n\t\tVectorMA (tent->v.angles, host_frametime, tent->v.avelocity, tent->v.angles);\n\t\tVectorScale (tent->v.velocity, host_frametime, move);\n\t\tVectorAdd (tent->v.origin, move, end);\n\t\ttrace = SV_Move (tent->v.origin, tent->v.mins, tent->v.maxs, end, MOVE_NORMAL, tent);\n\t\tVectorCopy (trace.endpos, tent->v.origin);\n\n//\t\tp = free_particles;\n//\t\tif (p)\n//\t\t{\n//\t\t\tfree_particles = p->next;\n//\t\t\tp->next = active_particles;\n//\t\t\tactive_particles = p;\n//\n//\t\t\tp->die = 256;\n//\t\t\tp->color = 15;\n//\t\t\tp->type = pt_static;\n//\t\t\tVectorCopy (vec3_origin, p->vel);\n//\t\t\tVectorCopy (tent->v.origin, p->org);\n//\t\t}\n\n\t\tif (trace.ent)\n\t\t\tif (trace.ent != ignore)\n\t\t\t\tbreak;\n\t}\n//\tp->color = 224;\n\thost_frametime = save_frametime;\n\treturn trace;\n}\n#endif\n"
  },
  {
    "path": "source/sv_user.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sv_user.c -- server code for moving users\n\n#include \"quakedef.h\"\n\nedict_t\t*sv_player;\n\nCVAR(pq_fullpitch, 0, CVAR_ARCHIVE)\nCVAR(sv_idealpitchscale, 0.8, CVAR_NONE)\nCVAR(sv_edgefriction, 2, CVAR_NONE)\n\nCVAR(sv_maxspeed, 320, CVAR_SERVERINFO)\nCVAR(sv_accelerate, 10, CVAR_NONE)\n\nextern\tcvar_t\tsv_friction;\nextern\tcvar_t\tsv_stopspeed;\n\n//----------------------------------------------\n\nstatic\tvec3_t\t\tforward, right, up;\n\nvec3_t\twishdir;\nfloat\twishspeed;\n\n// world\nfloat\t*angles;\nfloat\t*origin;\nfloat\t*velocity;\n\nbool\tonground;\n\nusercmd_t\tcmd;\n\n/*\n===============\nSV_SetIdealPitch\n===============\n*/\n#define\tMAX_FORWARD\t6\nvoid SV_SetIdealPitch (void)\n{\n\tfloat\tangleval, sinval, cosval;\n\ttrace_t\ttr;\n\tvec3_t\ttop, bottom;\n\tfloat\tz[MAX_FORWARD];\n\tint\t\ti, j;\n\tint\t\tstep, dir, steps;\n\n\tif (!((int)sv_player->v.flags & FL_ONGROUND))\n\t\treturn;\n\n\tangleval = sv_player->v.angles[YAW] * M_PI*2 / 360;\n\tsinval = sinf(angleval);\n\tcosval = cosf(angleval);\n\n\tfor (i=0 ; i<MAX_FORWARD ; i++)\n\t{\n\t\ttop[0] = sv_player->v.origin[0] + cosval*(i+3)*12;\n\t\ttop[1] = sv_player->v.origin[1] + sinval*(i+3)*12;\n\t\ttop[2] = sv_player->v.origin[2] + sv_player->v.view_ofs[2];\n\n\t\tbottom[0] = top[0];\n\t\tbottom[1] = top[1];\n\t\tbottom[2] = top[2] - 160;\n\n\t\ttr = SV_Move (top, vec3_origin, vec3_origin, bottom, 1, sv_player);\n\t\tif (tr.allsolid)\n\t\t\treturn;\t// looking at a wall, leave ideal the way is was\n\n\t\tif (tr.fraction == 1)\n\t\t\treturn;\t// near a dropoff\n\n\t\tz[i] = top[2] + tr.fraction*(bottom[2]-top[2]);\n\t}\n\n\tdir = 0;\n\tsteps = 0;\n\tfor (j=1 ; j<i ; j++)\n\t{\n\t\tstep = z[j] - z[j-1];\n\t\tif (step > -ON_EPSILON && step < ON_EPSILON)\n\t\t\tcontinue;\n\n\t\tif (dir && ( step-dir > ON_EPSILON || step-dir < -ON_EPSILON ) )\n\t\t\treturn;\t\t// mixed changes\n\n\t\tsteps++;\n\t\tdir = step;\n\t}\n\n\tif (!dir)\n\t{\n\t\tsv_player->v.idealpitch = 0;\n\t\treturn;\n\t}\n\n\tif (steps < 2)\n\t\treturn;\n\tsv_player->v.idealpitch = -dir * sv_idealpitchscale.value;\n}\n\n\n/*\n==================\nSV_UserFriction\n\n==================\n*/\nvoid SV_UserFriction (void)\n{\n\tfloat\t*vel;\n\tfloat\tspeed, newspeed, control;\n\tvec3_t\tstart, stop;\n\tfloat\tfriction;\n\ttrace_t\ttrace;\n\n\tvel = velocity;\n\n\tspeed = sqrt(vel[0]*vel[0] +vel[1]*vel[1]);\n\tif (!speed)\n\t\treturn;\n\n// if the leading edge is over a dropoff, increase friction\n\tstart[0] = stop[0] = origin[0] + vel[0]/speed*16;\n\tstart[1] = stop[1] = origin[1] + vel[1]/speed*16;\n\tstart[2] = origin[2] + sv_player->v.mins[2];\n\tstop[2] = start[2] - 34;\n\n\ttrace = SV_Move (start, vec3_origin, vec3_origin, stop, true, sv_player);\n\n\tif (trace.fraction == 1.0)\n\t\tfriction = sv_friction.value*sv_edgefriction.value;\n\telse\n\t\tfriction = sv_friction.value;\n\n// apply friction\n\tcontrol = speed < sv_stopspeed.value ? sv_stopspeed.value : speed;\n\tnewspeed = speed - host_frametime*control*friction;\n\n\tif (newspeed < 0)\n\t\tnewspeed = 0;\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==============\nSV_Accelerate\n==============\n*/\nvoid SV_Accelerate (void)\n{\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\taccelspeed = sv_accelerate.value*host_frametime*wishspeed;\n\tif (accelspeed > addspeed)\n\t\taccelspeed = addspeed;\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tvelocity[i] += accelspeed*wishdir[i];\n}\n\nvoid SV_AirAccelerate (vec3_t wishveloc)\n{\n\tint\t\t\ti;\n\tfloat\t\taddspeed, wishspd, accelspeed, currentspeed;\n\n\twishspd = VectorNormalize (wishveloc);\n\tif (wishspd > 30)\n\t\twishspd = 30;\n\tcurrentspeed = DotProduct (velocity, wishveloc);\n\taddspeed = wishspd - currentspeed;\n\tif (addspeed <= 0)\n\t\treturn;\n//\taccelspeed = sv_accelerate.value * host_frametime;\n\taccelspeed = sv_accelerate.value*wishspeed * host_frametime;\n\tif (accelspeed > addspeed)\n\t\taccelspeed = addspeed;\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tvelocity[i] += accelspeed*wishveloc[i];\n}\n\n\nvoid DropPunchAngle (void)\n{\n\tfloat\tlen;\n\n\tlen = VectorNormalize (sv_player->v.punchangle);\n\n\tlen -= 10*host_frametime;\n\tif (len < 0)\n\t\tlen = 0;\n\tVectorScale (sv_player->v.punchangle, len, sv_player->v.punchangle);\n}\n\n/*\n===================\nSV_WaterMove\n\n===================\n*/\nvoid SV_WaterMove (void)\n{\n\tint\t\ti;\n\tvec3_t\twishvel;\n\tfloat\tspeed, newspeed, wishspeed, addspeed, accelspeed;\n\n//\n// user intentions\n//\n\tAngleVectors (sv_player->v.v_angle, forward, right, up);\n\n\tfor (i=0 ; i<3 ; i++)\n\t\twishvel[i] = forward[i]*cmd.forwardmove + right[i]*cmd.sidemove;\n\n\tif (!cmd.forwardmove && !cmd.sidemove && !cmd.upmove)\n\t\twishvel[2] -= 60;\t\t// drift towards bottom\n\telse\n\t\twishvel[2] += cmd.upmove;\n\n\twishspeed = Length(wishvel);\n\tif (wishspeed > sv_maxspeed.value)\n\t{\n\t\tVectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);\n\t\twishspeed = sv_maxspeed.value;\n\t}\n\twishspeed *= 0.7;\n\n//\n// water friction\n//\n\tspeed = Length (velocity);\n\tif (speed)\n\t{\n\t\tnewspeed = speed - host_frametime * speed * sv_friction.value;\n\t\tif (newspeed < 0)\n\t\t\tnewspeed = 0;\n\t\tVectorScale (velocity, newspeed/speed, velocity);\n\t}\n\telse\n\t\tnewspeed = 0;\n\n//\n// water acceleration\n//\n\tif (!wishspeed)\n\t\treturn;\n\n\taddspeed = wishspeed - newspeed;\n\tif (addspeed <= 0)\n\t\treturn;\n\n\tVectorNormalize (wishvel);\n\taccelspeed = sv_accelerate.value * wishspeed * host_frametime;\n\tif (accelspeed > addspeed)\n\t\taccelspeed = addspeed;\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tvelocity[i] += accelspeed * wishvel[i];\n}\n\nvoid SV_WaterJump (void)\n{\n\tif (sv.time > sv_player->v.teleport_time\n\t|| !sv_player->v.waterlevel)\n\t{\n\t\tsv_player->v.flags = (int)sv_player->v.flags & ~FL_WATERJUMP;\n\t\tsv_player->v.teleport_time = 0;\n\t}\n\tsv_player->v.velocity[0] = sv_player->v.movedir[0];\n\tsv_player->v.velocity[1] = sv_player->v.movedir[1];\n}\n\n\n/*\n===================\nSV_AirMove\n\n===================\n*/\nvoid SV_AirMove (void)\n{\n\tint\t\t\ti;\n\tvec3_t\t\twishvel;\n\tfloat\t\tfmove, smove;\n\n\tAngleVectors (sv_player->v.angles, forward, right, up);\n\n\tfmove = cmd.forwardmove;\n\tsmove = cmd.sidemove;\n\n// hack to not let you back into teleporter\n\tif (sv.time < sv_player->v.teleport_time && fmove < 0)\n\t\tfmove = 0;\n\n\tfor (i=0 ; i<3 ; i++)\n\t\twishvel[i] = forward[i]*fmove + right[i]*smove;\n\n\tif ( (int)sv_player->v.movetype != MOVETYPE_WALK)\n\t\twishvel[2] = cmd.upmove;\n\telse\n\t\twishvel[2] = 0;\n\n\tVectorCopy (wishvel, wishdir);\n\twishspeed = VectorNormalize(wishdir);\n\tif (wishspeed > sv_maxspeed.value)\n\t{\n\t\tVectorScale (wishvel, sv_maxspeed.value/wishspeed, wishvel);\n\t\twishspeed = sv_maxspeed.value;\n\t}\n\n\tif ( sv_player->v.movetype == MOVETYPE_NOCLIP)\n\t{\t// noclip\n\t\tVectorCopy (wishvel, velocity);\n\t}\n\telse if ( (int)sv_player->v.flags & FL_ONGROUND )\n\t{\n\t\tSV_UserFriction ();\n\t\tSV_Accelerate ();\n\t}\n\telse\n\t{\t// not on ground, so little effect on velocity\n\t\tSV_AirAccelerate (wishvel);\n\t}\n}\n\n/*\n===================\nSV_ClientThink\n\nthe move fields specify an intended velocity in pix/sec\nthe angle fields specify an exact angular motion in degrees\n===================\n*/\nvoid SV_ClientThink (void)\n{\n\tvec3_t\t\tv_angle;\n\n\tif (sv_player->v.movetype == MOVETYPE_NONE)\n\t\treturn;\n\n\tonground = (int)sv_player->v.flags & FL_ONGROUND;\n\n\torigin = sv_player->v.origin;\n\tvelocity = sv_player->v.velocity;\n\n\tDropPunchAngle ();\n\n//\n// if dead, behave differently\n//\n\tif (sv_player->v.health <= 0)\n\t\treturn;\n\n//\n// angles\n// show 1/3 the pitch angle and all the roll angle\n\tcmd = host_client->cmd;\n\tangles = sv_player->v.angles;\n\n\tVectorAdd (sv_player->v.v_angle, sv_player->v.punchangle, v_angle);\n\tangles[ROLL] = V_CalcRoll (sv_player->v.angles, sv_player->v.velocity)*4;\n\tif (!sv_player->v.fixangle)\n\t{\n\t\tangles[PITCH] = -v_angle[PITCH]/3;\n\t\tangles[YAW] = v_angle[YAW];\n\t}\n\n\tif ( (int)sv_player->v.flags & FL_WATERJUMP )\n\t{\n\t\tSV_WaterJump ();\n\t\treturn;\n\t}\n//\n// walk\n//\n\tif ( (sv_player->v.waterlevel >= 2)\n\t&& (sv_player->v.movetype != MOVETYPE_NOCLIP) )\n\t{\n\t\tSV_WaterMove ();\n\t\treturn;\n\t}\n\n\tSV_AirMove ();\n}\n\n\n/*\n===================\nSV_ReadClientMove\n===================\n*/\nvoid SV_ReadClientMove (usercmd_t *move)\n{\n\tint\t\ti;\n\tvec3_t\tangle;\n\tint\t\tbits;\n\n// read ping time\n\thost_client->ping_times[host_client->num_pings%NUM_PING_TIMES]\n\t\t= sv.time - MSG_ReadFloat ();\n\thost_client->num_pings++;\n\n// read current angles\n\tif (host_client->netconnection->proquake_connection == MOD_PROQUAKE) \n\t{\n\t\tfor (i = 0; i<3; i++)\n\t\t\tangle[i] = MSG_ReadPreciseAngle();\n\t}\n\telse\n\t{\n\t\tfor (i = 0; i<3; i++)\n\t\t\tangle[i] = MSG_ReadAngle();\n\t}\n\n// ProQuake - server-side fullpitch fix\n\tif (!pq_fullpitch.value)\n\t{\n\t\tif (angle[PITCH] > 80 || angle[PITCH] < -70)\n\t\t{\n\t\t\tangle[PITCH] = COM_Clamp(angle[PITCH], -70, 80);\n\n\t\t\tMSG_WriteByte (&host_client->message, svc_setangle);\n\t\t\tfor (i=0 ; i < 3 ; i++)\n\t\t\t\tMSG_WriteAngle (&host_client->message, angle[i] );\n\t\t}\n\t}\n\t\n\tVectorCopy (angle, host_client->edict->v.v_angle);\n\n// read movement\n\tmove->forwardmove = MSG_ReadShort ();\n\tmove->sidemove = MSG_ReadShort ();\n\tmove->upmove = MSG_ReadShort ();\n\n// read buttons\n\tbits = MSG_ReadByte ();\n\thost_client->edict->v.button0 = bits & 1;\n\thost_client->edict->v.button2 = (bits & 2)>>1;\n\n\ti = MSG_ReadByte ();\n\tif (i)\n\t\thost_client->edict->v.impulse = i;\n\n#ifdef QUAKE2\n// read light level\n\thost_client->edict->v.light_level = MSG_ReadByte ();\n#endif\n}\n\n/*\n===================\nSV_ReadClientMessage\n\nReturns false if the client should be killed\n===================\n*/\nbool SV_ReadClientMessage (void)\n{\n\tint\t\tret;\n\tint\t\tcmd;\n\tchar\t\t*s;\n\n\tdo\n\t{\nnextmsg:\n\t\tret = NET_GetMessage (host_client->netconnection);\n\t\tif (ret == -1)\n\t\t{\n\t\t\tSys_Printf (\"SV_ReadClientMessage: NET_GetMessage failed\\n\");\n\t\t\treturn false;\n\t\t}\n\t\tif (!ret)\n\t\t\treturn true;\n\n\t\tMSG_BeginReading ();\n\n\t\twhile (1)\n\t\t{\n\t\t\tif (!host_client->active)\n\t\t\t\treturn false;\t// a command caused an error\n\n\t\t\tif (msg_badread)\n\t\t\t{\n\t\t\t\tSys_Printf (\"SV_ReadClientMessage: badread\\n\");\n\t\t\t\treturn false;\n\t\t\t}\n\n\t\t\tcmd = MSG_ReadChar ();\n\n\t\t\tswitch (cmd)\n\t\t\t{\n\t\t\tcase -1:\n\t\t\t\tgoto nextmsg;\t\t// end of message\n\n\t\t\tdefault:\n\t\t\t\tSys_Printf (\"SV_ReadClientMessage: unknown command char\\n\");\n\t\t\t\treturn false;\n\n\t\t\tcase clc_nop:\n//\t\t\t\tSys_Printf (\"clc_nop\\n\");\n\t\t\t\tbreak;\n\n\t\t\tcase clc_stringcmd:\n\t\t\t\ts = MSG_ReadString ();\n\t\t\t\tif (host_client->privileged)\n\t\t\t\t\tret = 2;\n\t\t\t\telse\n\t\t\t\t\tret = 0;\n\t\t\t\tif (strncasecmp(s, \"status\", 6) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"god\", 3) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"notarget\", 8) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"fly\", 3) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"name\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"noclip\", 6) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"say\", 3) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"say_team\", 8) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"tell\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"color\", 5) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"kill\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"pause\", 5) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"spawn\", 5) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"begin\", 5) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"prespawn\", 8) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"kick\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"ping\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"give\", 4) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\telse if (strncasecmp(s, \"ban\", 3) == 0)\n\t\t\t\t\tret = 1;\n\t\t\t\tif (ret == 2)\n\t\t\t\t\tCbuf_InsertText (s);\n\t\t\t\telse if (ret == 1)\n\t\t\t\t\tCmd_ExecuteString (s, src_client);\n\t\t\t\telse\n\t\t\t\t\tCon_DPrintf(\"%s tried to %s\\n\", host_client->name, s);\n\t\t\t\tbreak;\n\n\t\t\tcase clc_disconnect:\n//\t\t\t\tSys_Printf (\"SV_ReadClientMessage: client disconnected\\n\");\n\t\t\t\treturn false;\n\n\t\t\tcase clc_move:\n\t\t\t\tSV_ReadClientMove (&host_client->cmd);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t} while (ret == 1);\n\n\treturn true;\n}\n\n\n/*\n==================\nSV_RunClients\n==================\n*/\nvoid SV_RunClients (void)\n{\n\tint\t\t\t\ti;\n\n\tfor (i=0, host_client = svs.clients ; i<svs.maxclients ; i++, host_client++)\n\t{\n\t\tif (!host_client->active)\n\t\t\tcontinue;\n\n\t\tsv_player = host_client->edict;\n\n\t\tif (!SV_ReadClientMessage ())\n\t\t{\n\t\t\tSV_DropClient (false);\t// client misbehaved...\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!host_client->spawned)\n\t\t{\n\t\t// clear client movement until a new packet is received\n\t\t\tmemset (&host_client->cmd, 0, sizeof(host_client->cmd));\n\t\t\tcontinue;\n\t\t}\n\n// always pause in single player if in console or menus\n\t\tif (!sv.paused && (svs.maxclients > 1 || key_dest == key_game) )\n\t\t\tSV_ClientThink ();\n\t}\n}\n"
  },
  {
    "path": "source/sys.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// sys.h -- non-portable functions\n\n//\n// file IO\n//\n\n// returns the file size\n// return -1 if file is not present\n// the file should be in BINARY mode for stupid OSs that care\nint Sys_FileOpenRead (char *path, int *hndl);\n\nint Sys_FileOpenWrite (char *path);\nvoid Sys_FileClose (int handle);\nvoid Sys_FileSeek (int handle, int position);\nint Sys_FileRead (int handle, void *dest, int count);\nint Sys_FileWrite (int handle, void *data, int count);\nint\tSys_FileTime (char *path);\nvoid Sys_mkdir (char *path);\n\n//\n// memory protection\n//\nvoid Sys_MakeCodeWriteable (unsigned long startaddr, unsigned long length);\n\n//\n// system IO\n//\nvoid Sys_DebugLog(char *file, char *fmt, ...);\n\nvoid Sys_Error (const char *error, ...);\n// an error will cause the entire program to exit\n\nvoid Sys_Printf (char *fmt, ...);\n// send text to the console\n\nvoid Sys_Quit (void);\n\ndouble Sys_FloatTime (void);\n\nchar *Sys_ConsoleInput (void);\n\nvoid Sys_Sleep (void);\n// called to yield for a little bit so as\n// not to hog cpu when paused or debugging\n\nvoid Sys_SendKeyEvents (void);\n// Perform Key_Event () callbacks until the input que is empty\n\nvoid Sys_LowFPPrecision (void);\nvoid Sys_HighFPPrecision (void);\nvoid Sys_SetFPCW (void);\n\n// >>> FIX: For Nintendo Wii using devkitPPC / libogc\n// New functions for big stack handling:\nvoid* Sys_BigStackAlloc(int size, char* purpose);\nvoid Sys_BigStackFree(int size, char* purpose);\nvoid Sys_BigStackRewind(void);\n// <<< FIX"
  },
  {
    "path": "source/sys_psp2.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\nCopyright (C) 2020 Asakura Reiko\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n\n#include \"quakedef.h\"\n#include \"errno.h\"\n#include \"net_dgrm.h\"\n#include <vitasdk.h>\n\n#define BIGSTACK_SIZE 20 * 1024 * 1024\nbyte sys_bigstack[BIGSTACK_SIZE];\nint sys_bigstack_cursize;\n\nuint8_t is_uma0 = 0;\nint tex_cache = 1;\n\nextern int antialiasing;\nextern uint8_t netcheck_dialog_running;\nextern uint8_t proto_idx;\nextern int gl_ssaa;\n\n// Mods support\nint max_mod_idx = -1;\n\nModsList *mods = NULL;\n\nModsList *addMod(char* name, ModsList* db){\n\tModsList* entry = (ModsList*)malloc(sizeof(ModsList));\n\tstrcpy(entry->name, name);\n\tentry->next = NULL;\n\tif (db == NULL)\n\t\treturn entry;\n\telse {\n\t\tModsList* ptr = db;\n\t\twhile (ptr->next != NULL) {\n\t\t\tptr = ptr->next;\n\t\t}\n\t\tptr->next = entry;\n\t\treturn db;\n\t}\n}\n\n\nint old_char;\nextern int setup_cursor;\nextern int lanConfig_cursor;\nint isKeyboard;\nextern uint32_t rumble_tick;\nextern cvar_t psvita_touchmode;\nextern cvar_t vid_vsync;\nextern int scr_width;\nextern int scr_height;\nextern int cfg_width;\nextern int cfg_height;\n\nbool isDedicated;\nuint64_t initialTime = 0;\nint hostInitialized = 0;\nSceCtrlData pad, oldpad;\n/*\n===============================================================================\n\nFILE IO\n\n===============================================================================\n*/\n\n#define PLATFORM_PSVITA\t0x00010000\n\n#define MAX_HANDLES             10\nFILE    *sys_handles[MAX_HANDLES];\n\nint Sys_FindHandle(void)\n{\n\tint i;\n\n\tfor (i=1;i<MAX_HANDLES;i++)\n\t\tif (!sys_handles[i]) return i;\n\tSys_Error(\"out of handles\");\n\treturn -1;\n}\n\nvoid Log(const char *format, ...) {\n#ifdef DEBUG\n\t__gnuc_va_list arg;\n\tint done;\n\tva_start(arg, format);\n\tchar msg[512];\n\tdone = vsprintf(msg, format, arg);\n\tva_end(arg);\n\tint i;\n\tsprintf(msg, \"%s\\n\", msg);\n\tFILE* f = NULL;\n\tif (is_uma0) f = fopen(\"uma0:/data/Quake/log.txt\", \"a+\");\n\telse f = fopen(\"ux0:/data/Quake/log.txt\", \"a+\");\n\tif (log != NULL) {\n\t\tfwrite(msg, 1, strlen(msg), log);\n\t\tfclose(log);\n\t}\n#endif\n}\n\nint Sys_FileLength(FILE *f)\n{\n\tint             pos;\n\tint             end;\n\n\tpos = ftell(f);\n\tfseek(f, 0, SEEK_END);\n\tend = ftell(f);\n\tfseek(f, pos, SEEK_SET);\n\n\treturn end;\n}\n\nint Sys_FileOpenRead(char *path, int *hndl)\n{\n\tFILE    *f;\n\tint             i;\n\n\ti = Sys_FindHandle();\n\n\tf = fopen(path, \"rb\");\n\tif (!f)\n\t{\n\t\t*hndl = -1;\n\t\treturn -1;\n\t}\n\tsys_handles[i] = f;\n\t*hndl = i;\n\n\treturn Sys_FileLength(f);\n}\n\nint Sys_FileOpenWrite(char *path)\n{\n\tFILE    *f;\n\tint             i;\n\n\ti = Sys_FindHandle();\n\n\tf = fopen(path, \"wb\");\n\tif (!f)\n\t\tSys_Error(\"Error opening %s: %s\", path, strerror(errno));\n\tsys_handles[i] = f;\n\n\treturn i;\n}\n\nvoid Sys_FileClose(int handle)\n{\n\tfclose(sys_handles[handle]);\n\tsys_handles[handle] = NULL;\n}\n\nvoid Sys_FileSeek(int handle, int position)\n{\n\tfseek(sys_handles[handle], position, SEEK_SET);\n}\n\nint Sys_FileRead(int handle, void *dest, int count)\n{\n\treturn fread(dest, 1, count, sys_handles[handle]);\n}\n\nint Sys_FileWrite(int handle, void *data, int count)\n{\n\treturn fwrite(data, 1, count, sys_handles[handle]);\n}\n\nint     Sys_FileTime(char *path)\n{\n\tFILE    *f;\n\n\tf = fopen(path, \"rb\");\n\tif (f)\n\t{\n\t\tfclose(f);\n\t\treturn 1;\n\t}\n\n\treturn -1;\n}\n\nvoid Sys_mkdir(char *path)\n{\n\tsceIoMkdir(path, 0777);\n}\n\nvoid Sys_BigStackRewind(void)\n{\n\tsys_bigstack_cursize = 0;\n}\n\nvoid* Sys_BigStackAlloc(int size, char* purpose)\n{\n\tvoid* p;\n\n\tp = 0;\n\tif (sys_bigstack_cursize + size < BIGSTACK_SIZE)\n\t{\n\t\tp = sys_bigstack + sys_bigstack_cursize;\n\t\tsys_bigstack_cursize = sys_bigstack_cursize + size;\n\t}\n\telse\n\t{\n\t\tSys_Error(\"Sys_BigStackAlloc: %s - failed on %i bytes\", purpose, size);\n\t};\n\treturn p;\n}\n\nvoid Sys_BigStackFree(int size, char* purpose)\n{\n\tif (sys_bigstack_cursize - size >= 0)\n\t{\n\t\tsys_bigstack_cursize = sys_bigstack_cursize - size;\n\t}\n\telse\n\t{\n\t\tSys_Error(\"Sys_BigStackFree: %s - underflow on %i bytes\", purpose, sys_bigstack_cursize - size);\n\t};\n}\n// <<< FIX\n\n\n/*\n===============================================================================\n\nSYSTEM IO\n\n===============================================================================\n*/\n\nvoid Sys_MakeCodeWriteable(unsigned long startaddr, unsigned long length)\n{\n}\n\nvoid Sys_Quit(void)\n{\n\tHost_Shutdown();\n\tsceKernelExitProcess(0);\n}\n\nvoid Sys_Error(const char *error, ...)\n{\n\n\tva_list         argptr;\n\n\tchar buf[256];\n\tva_start(argptr, error);\n\tvsnprintf(buf, sizeof(buf), error, argptr);\n\tva_end(argptr);\n\tsprintf(buf, \"%s\\n\", buf);\n\tFILE* f = NULL;\n\tif (is_uma0) f = fopen(\"uma0:/data/Quake/log.txt\", \"a+\");\n\telse f = fopen(\"ux0:/data/Quake/log.txt\", \"a+\");\n\tfwrite(buf, 1, strlen(buf), f);\n\tfclose(f);\n\tSys_Quit();\n}\n\nvoid Sys_Printf(char *fmt, ...)\n{\n#ifdef DEBUG\n\tif (hostInitialized)\n\t\treturn;\n\n\tva_list argptr;\n\tchar buf[256];\n\tva_start(argptr, fmt);\n\tvsnprintf(buf, sizeof(buf), fmt, argptr);\n\tva_end(argptr);\n\tLog(buf);\n#endif\n\n}\n\nchar *Sys_ConsoleInput(void)\n{\n\treturn NULL;\n}\n\nvoid Sys_Sleep(void)\n{\n}\n\ndouble Sys_FloatTime(void)\n{\n\tSceRtcTick ticks;\n\tsceRtcGetCurrentTick(&ticks);\n\treturn ticks.tick * 0.000001;\n}\n\nvoid Sys_HighFPPrecision(void)\n{\n}\n\nvoid Sys_LowFPPrecision(void)\n{\n}\n\n/*\n===============================================================================\n\nKEYS & INPUTS\n\n===============================================================================\n*/\ntypedef struct\n{\n\tint\t    button;\n\tint\t\tkey;\n} psvita_buttons;\n\n#define MAX_PSVITA_KEYS 12\npsvita_buttons KeyTable[MAX_PSVITA_KEYS] =\n{\n\t{ SCE_CTRL_SELECT, K_SELECT },\n\t{ SCE_CTRL_START, K_START },\n\n\t{ SCE_CTRL_UP, K_UPARROW },\n\t{ SCE_CTRL_DOWN, K_DOWNARROW},\n\t{ SCE_CTRL_LEFT, K_LEFTARROW },\n\t{ SCE_CTRL_RIGHT, K_RIGHTARROW },\n\t{ SCE_CTRL_LTRIGGER, K_LEFTTRIGGER },\n\t{ SCE_CTRL_RTRIGGER, K_RIGHTTRIGGER },\n\n\t{ SCE_CTRL_SQUARE, K_SQUARE },\n\t{ SCE_CTRL_TRIANGLE, K_TRIANGLE },\n\t{ SCE_CTRL_CROSS, K_CROSS },\n\t{ SCE_CTRL_CIRCLE, K_CIRCLE }\n};\n\nvoid PSP2_KeyDown(int keys) {\n\tint i;\n\tfor (i = 0; i < MAX_PSVITA_KEYS; i++) {\n\t\tif (keys & KeyTable[i].button) {\n\t\t\t\tKey_Event(KeyTable[i].key, true);\n\t\t}\n\t}\n}\n\nvoid PSP2_KeyUp(int keys, int oldkeys) {\n\tint i;\n\tfor (i = 0; i < MAX_PSVITA_KEYS; i++) {\n\t\tif ((!(keys & KeyTable[i].button)) && (oldkeys & KeyTable[i].button)) {\n\t\t\tKey_Event(KeyTable[i].key, false);\n\t\t}\n\t}\n}\n\nvoid Sys_SendKeyEvents(void)\n{\n\tsceCtrlPeekBufferPositive(0, &pad, 1);\n\tint kDown = pad.buttons;\n\tint kUp = oldpad.buttons;\n\n\tif (kDown)\n\t\tPSP2_KeyDown(kDown);\n\tif (kUp != kDown)\n\t\tPSP2_KeyUp(kDown, kUp);\n\n\tif (psvita_touchmode.value == 0)\n\t{\n\t\t// Touchscreen support for game status showing\n\t\tSceTouchData touch;\n\t\tsceTouchPeek(SCE_TOUCH_PORT_FRONT, &touch, 1);\n\t\tKey_Event(K_TOUCH, touch.reportNum > 0 ? true : false);\n\t}\n\toldpad = pad;\n}\n\n//=============================================================================\nint _newlib_heap_size_user = 192 * 1024 * 1024;\nchar* mod_path = NULL;\nchar mp_path[32];\n\nstatic uint16_t title[SCE_IME_DIALOG_MAX_TITLE_LENGTH];\nstatic uint16_t initial_text[SCE_IME_DIALOG_MAX_TEXT_LENGTH];\nstatic uint16_t input_text[SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1];\nchar title_keyboard[256];\n\nvoid ascii2utf(uint16_t* dst, char* src){\n\tif(!src || !dst)return;\n\twhile(*src)*(dst++)=(*src++);\n\t*dst=0x00;\n}\n\nvoid utf2ascii(char* dst, uint16_t* src){\n\tif(!src || !dst)return;\n\twhile(*src)*(dst++)=(*(src++))&0xFF;\n\t*dst=0x00;\n}\n\nvoid simulateKeyPress(char* text){\n\t\n\t//We first delete the current text\n\tint i;\n\tfor (i=0;i<100;i++){\n\t\tKey_Event(K_BACKSPACE, true);\n\t\tKey_Event(K_BACKSPACE, false);\n\t}\n\t\n\twhile (*text){\n\t\tKey_Event(*text, true);\n\t\tKey_Event(*text, false);\n\t\ttext++;\n\t}\n}\n\n#define\t\tMAXCMDLINE\t256\t// If changed, don't forget to change it in keys.c too!!\nextern\tchar\tkey_lines[32][MAXCMDLINE];\nextern\tint\t\tedit_line;\n\nbool CheckForMod(char* dir)\n{\n\tint dd = sceIoDopen(dir);\n\tSceIoDirent entry;\n\tint res;\n\tbool ret = false;\n\n\twhile ((res = sceIoDread(dd, &entry)) > 0 && (!ret))\n\t\tif ( strstr(strtolower(entry.d_name),\".pak\") != NULL || !strcmp(strtolower(entry.d_name), \"progs.dat\") ) ret = true;\t// Enable checks for progs.dat only mods\n\t\n\tsceIoDclose(dd);\n\treturn ret;\n}\n\nint quake_main (unsigned int argc, void* argv){\n\tcl_entities = malloc(sizeof(entity_t) * MAX_EDICTS);\n\tcl_temp_entities = malloc(sizeof(entity_t) * MAX_TEMP_ENTITIES);\n\tcl_efrags = malloc(sizeof(efrag_t) * MAX_EFRAGS);\n\n\t// Checking for uma0 support\n\tFILE *f = fopen(\"uma0:/data/Quake/id1/pak0.pak\", \"rb\");\n\tif (f) {\n\t\tfclose(f);\n\t\tis_uma0 = 1;\n\t}\n\t\n\t// Initializing stuffs\n\tscePowerSetArmClockFrequency(444);\n\tscePowerSetBusClockFrequency(222);\n\tscePowerSetGpuClockFrequency(222);\n\tscePowerSetGpuXbarClockFrequency(166);\n\tsceSysmoduleLoadModule(SCE_SYSMODULE_NET);\n\tsceSysmoduleLoadModule(SCE_SYSMODULE_PSPNET_ADHOC);\n\tsceCtrlSetSamplingMode(SCE_CTRL_MODE_ANALOG_WIDE);\n\tsceTouchSetSamplingState(SCE_TOUCH_PORT_FRONT, 1);\n\tsceTouchSetSamplingState(SCE_TOUCH_PORT_BACK, 1);\n\tsceAppUtilInit(&(SceAppUtilInitParam){}, &(SceAppUtilBootParam){});\n\tSceCommonDialogConfigParam cmnDlgCfgParam;\n\tsceCommonDialogConfigParamInit(&cmnDlgCfgParam);\n\tsceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_LANG, (int *)&cmnDlgCfgParam.language);\n\tsceAppUtilSystemParamGetInt(SCE_SYSTEM_PARAM_ID_ENTER_BUTTON, (int *)&cmnDlgCfgParam.enterButtonAssign);\n\tsceCommonDialogSetConfigParam(&cmnDlgCfgParam);\n\n\tconst float tickRate = 1.0f / sceRtcGetTickResolution();\n\tstatic quakeparms_t    parms;\n\t\n\t// Loading resolution and MSAA mode from config files, those are not handled via Host cause Host_Init requires vitaGL to be working\n\tif (is_uma0) f = fopen(\"uma0:data/Quake/resolution.cfg\", \"rb\");\n\telse f = fopen(\"ux0:data/Quake/resolution.cfg\", \"rb\");\n\tif (f != NULL){\n\t\tfscanf(f, \"%dx%d\", &scr_width, &scr_height);\n\t\tfclose(f);\n\t}\n\tif (is_uma0) f = fopen(\"uma0:data/Quake/antialiasing.cfg\", \"rb\");\n\telse f = fopen(\"ux0:data/Quake/antialiasing.cfg\", \"rb\");\n\tif (f != NULL){\n\t\tfscanf(f, \"%d\", &antialiasing);\n\t\tfclose(f);\n\t}\n\tcfg_width = scr_width;\n\tcfg_height = scr_height;\n\t\n\t// Initializing vitaGL\n\tvglSetCircularPoolSize(64 * 1024 * 1024);\n\tGLboolean invalid_res = GL_FALSE;\n\tswitch (antialiasing) {\n\tcase 1:\n\tcase 5:\n\tcase 6:\n\t\tinvalid_res = vglInitExtended(0x1400000, scr_width, scr_height, 0x1000000, SCE_GXM_MULTISAMPLE_2X);\n\t\tbreak;\n\tcase 2:\n\tcase 7:\n\tcase 8:\n\t\tinvalid_res = vglInitExtended(0x1400000, scr_width, scr_height, 0x1000000, SCE_GXM_MULTISAMPLE_4X);\n\t\tbreak;\n\tdefault:\n\t\tinvalid_res = vglInitExtended(0x1400000, scr_width, scr_height, 0x1000000, SCE_GXM_MULTISAMPLE_NONE);\n\t\tbreak;\n\t}\n\tif (invalid_res) {\n\t\tcfg_width = scr_width = 960;\n\t\tcfg_height = scr_height = 544;\n\t}\n\t\n\t// Properly setting SSAA\n\tswitch (antialiasing) {\n\tcase 3:\n\tcase 5:\n\tcase 7:\n\t\tgl_ssaa = 2;\n\t\tbreak;\n\tcase 4:\n\tcase 6:\n\tcase 8:\n\t\tgl_ssaa = 4;\n\t\tbreak;\n\tdefault:\n\t\tgl_ssaa = 1;\n\t\tbreak;\n\t}\n\t\n\t// Official mission packs support\n\tSceAppUtilAppEventParam eventParam;\n\tmemset(&eventParam, 0, sizeof(SceAppUtilAppEventParam));\n\tsceAppUtilReceiveAppEvent(&eventParam);\n\tif (eventParam.type == 0x05) {\n\t\tchar *int_argv[16];\n\t\tint_argv[0] = int_argv[2] = \"\";\n\t\tchar buffer[2048];\n\t\tmemset(buffer, 0, 2048);\n\t\tsceAppUtilAppEventParseLiveArea(&eventParam, buffer);\n\t\tif (strstr(buffer, \"custom\") != NULL) {\n\t\t\tmemset(input_text, 0, (SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1) << 1);\n\t\t\tmemset(initial_text, 0, (SCE_IME_DIALOG_MAX_TEXT_LENGTH) << 1);\n\t\t\tsprintf(title_keyboard, \"Insert args list\");\n\t\t\tascii2utf(title, title_keyboard);\n\t\t\tSceImeDialogParam param;\n\t\t\tsceImeDialogParamInit(&param);\n\t\t\tparam.supportedLanguages = 0x0001FFFF;\n\t\t\tparam.languagesForced = SCE_TRUE;\n\t\t\tparam.type = SCE_IME_TYPE_BASIC_LATIN;\n\t\t\tparam.title = title;\n\t\t\tparam.maxTextLength = SCE_IME_DIALOG_MAX_TEXT_LENGTH;\n\t\t\tparam.initialText = initial_text;\n\t\t\tparam.inputTextBuffer = input_text;\n\t\t\tsceImeDialogInit(&param);\n\t\t\twhile (sceImeDialogGetStatus() != SCE_COMMON_DIALOG_STATUS_FINISHED) {\n\t\t\t\tvglSwapBuffers(GL_TRUE);\n\t\t\t}\n\t\t\tSceCommonDialogStatus status = sceImeDialogGetStatus();\n\t\t\tSceImeDialogResult result;\n\t\t\tmemset(&result, 0, sizeof(SceImeDialogResult));\n\t\t\tsceImeDialogGetResult(&result);\n\t\t\tif (result.button == SCE_IME_DIALOG_BUTTON_ENTER)\n\t\t\t{\n\t\t\t\tutf2ascii(title_keyboard, input_text);\n\t\t\t\tif (strlen(title_keyboard) > 1) {\n\t\t\t\t\tint int_argc = 2;\n\t\t\t\t\tint_argv[1] = title_keyboard;\n\t\t\t\t\tchar *ptr = title_keyboard;\n\t\t\t\t\tfor (;;) {\n\t\t\t\t\t\tchar *space = strstr(ptr, \" \");\n\t\t\t\t\t\tif (space == NULL) break;\n\t\t\t\t\t\t*space = 0;\n\t\t\t\t\t\tint_argv[int_argc++] = ptr = space + 1;\n\t\t\t\t\t}\n\t\t\t\t\tint_argv[int_argc++] = \"\";\n\t\t\t\t\tCOM_InitArgv(int_argc, int_argv);\n\t\t\t\t} else COM_InitArgv(argc, argv);\n\t\t\t} else COM_InitArgv(argc, argv);\n\t\t\tsceImeDialogTerm();\n\t\t} else {\n\t\t\tint_argv[1] = buffer;\n\t\t\tCOM_InitArgv(3, int_argv);\n\t\t\tsprintf(mp_path, \"%s\", &buffer[1]);\n\t\t\tmod_path = mp_path;\n\t\t}\n\t} else COM_InitArgv(argc, argv);\n\t\n\tif (is_uma0) parms.basedir = \"uma0:/data/Quake\";\n\telse parms.basedir = \"ux0:/data/Quake\";\n\t\n\t// Initializing empty ModList\n\tmods = NULL;\n\tint i = 0;\n\tint max_idx = -1;\n\t\n\t// Scanning main folder in search of mods\n\tint dd = sceIoDopen(parms.basedir);\n\tSceIoDirent entry;\n\tint res;\n\twhile (sceIoDread(dd, &entry) > 0) {\n\t\tif (SCE_S_ISDIR(entry.d_stat.st_mode)) {\n\t\t\tif (CheckForMod(va(\"%s/%s\", parms.basedir, entry.d_name))) {\n\t\t\t\tmods = addMod(entry.d_name, mods);\n\t\t\t\tmax_mod_idx++;\n\t\t\t}\n\t\t}\n\t}\n\tsceIoDclose(dd);\n\t\n\t// Bat files support\n\tif (COM_CheckParm(\"-bat\"))\n\t{\n\t\tchar *int_argv[16];\n\t\tint_argv[0] = \"\";\n\t\tint t = COM_CheckParm(\"-bat\") + 1;\n\t\tif (t < com_argc) {\n\t\t\tchar fname[128];\n\t\t\tsprintf(fname, \"%s/%s.bat\", parms.basedir, com_argv[t]);\n\t\t\tSceUID fd = sceIoOpen(fname, SCE_O_RDONLY, 0777);\n\t\t\tif (fd >= 0) {\n\t\t\t\tint size = sceIoLseek32(fd, 0, SCE_SEEK_END);\n\t\t\t\tchar bat_args[2048];\n\t\t\t\tsceIoLseek32(fd, 0, SCE_SEEK_SET);\n\t\t\t\tsceIoRead(fd, bat_args, size);\n\t\t\t\tsceIoClose(fd);\n\t\t\t\tbat_args[size] = 0;\n\t\t\t\tint int_argc = 2;\n\t\t\t\tchar *ptr = strstr(bat_args, \"quake\") + 6;\n\t\t\t\tint_argv[1] = ptr;\n\t\t\t\tfor (;;) {\n\t\t\t\t\tchar *space = strstr(ptr, \" \");\n\t\t\t\t\tif (space == NULL) break;\n\t\t\t\t\t*space = 0;\n\t\t\t\t\tint_argv[int_argc++] = ptr = space + 1;\n\t\t\t\t}\n\t\t\t\tint_argv[int_argc++] = \"\";\n\t\t\t\tCOM_InitArgv(int_argc, int_argv);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// Texture cache\n\tif (COM_CheckParm(\"-no_tex_cache\"))\n\t\ttex_cache = 0;\n\t\n\tif (COM_CheckParm(\"-mem\"))\n\t{\n\t\tint t = COM_CheckParm(\"-mem\") + 1;\n\t\tif (t < com_argc)\n\t\t\tparms.memsize = atoi(com_argv[t]) * 1024 * 1024;\n\t} else\n\t\tparms.memsize = 64 * 1024 * 1024;\n\t\n\tparms.membase = malloc(parms.memsize);\n\n\tparms.argc = com_argc;\n\tparms.argv = com_argv;\n\n\tHost_Init(&parms);\n\thostInitialized = 1;\n\t\n\t// Setting PSN Account if it's his first time\n\tif (!strcmp(cl_name.string, \"player\"))\n\t{\n\t\tchar nickname[32];\n\t\tsceAppUtilSystemParamGetString(SCE_SYSTEM_PARAM_ID_USERNAME, nickname, SCE_SYSTEM_PARAM_USERNAME_MAXSIZE);\n\n\t\tstatic char cmd[256];\n\t\tsprintf(cmd, \"_cl_name \\\"%s\\\"\\n\", nickname);\n\t\tCbuf_AddText(cmd);\n\t}\n\n\tIN_ResetInputs();\n\tCbuf_AddText(\"exec config.cfg\\n\");\n\n\tvglWaitVblankStart(vid_vsync.value);\n\tint old_vsync = vid_vsync.value;\n\t\n\tSceRtcTick lastTick;\n\tsceRtcGetCurrentTick(&lastTick);\n\t\n\t// Disabling all FPU exceptions traps on main thread\n\tsceKernelChangeThreadVfpException(0x0800009FU, 0x0);\n\n\twhile (1)\n\t{\n\t\t// Changing V-Sync setting in realtime\n\t\tif (old_vsync != vid_vsync.value) {\n\t\t\tvglWaitVblankStart(vid_vsync.value);\n\t\t\told_vsync = vid_vsync.value;\n\t\t}\n\t\t\n\t\t// Prevent screen power-off\n\t\tsceKernelPowerTick(0);\n\n\t\t// Rumble effect managing (PSTV only)\n\t\tif (rumble_tick != 0) {\n\t\t\tif (sceKernelGetProcessTimeLow() - rumble_tick > 500000) IN_StopRumble(); // 0.5 sec\n\t\t}\n\t\t\n\t\t// AdHoc Message Dialog\n\t\tif (netcheck_dialog_running == 1) {\n\t\t\tSceCommonDialogStatus status = sceNetCheckDialogGetStatus();\n\t\t\tif (status == 2) {\n\t\t\t\tSceNetCheckDialogResult result;\n\t\t\t\tmemset(&result, 0, sizeof(SceNetCheckDialogResult));\n\t\t\t\tsceNetCheckDialogGetResult(&result);\n\n\t\t\t\tif (result.result == SCE_COMMON_DIALOG_RESULT_OK) {\n\t\t\t\t\tproto_idx = 1;\n\t\t\t\t} else {\n\t\t\t\t\tproto_idx = 0;\n\t\t\t\t}\n\n\t\t\t\tsceNetCheckDialogTerm();\n\t\t\t\tDatagram_Init();\n\t\t\t}\n\t\t}\n\n\t\t// OSK manage for Console / Input\n\t\tif (key_dest == key_console || m_state == m_lanconfig || m_state == m_setup)\n\t\t{\n\t\t\tif (old_char != 0) Key_Event(old_char, false);\n\t\t\tSceCtrlData tmp_pad, oldpad;\n\t\t\tsceCtrlPeekBufferPositive(0, &tmp_pad, 1);\n\t\t\tif (isKeyboard)\n\t\t\t{\n\t\t\t\tSceCommonDialogStatus status = sceImeDialogGetStatus();\n\t\t\t\tif (status == 2) {\n\t\t\t\t\tSceImeDialogResult result;\n\t\t\t\t\tmemset(&result, 0, sizeof(SceImeDialogResult));\n\t\t\t\t\tsceImeDialogGetResult(&result);\n\n\t\t\t\t\tif (result.button == SCE_IME_DIALOG_BUTTON_ENTER)\n\t\t\t\t\t{\n\t\t\t\t\t\tif (key_dest == key_console)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tutf2ascii(title_keyboard, input_text);\n\t\t\t\t\t\t\tstrcpy(key_lines[edit_line] + 1, title_keyboard);\n\t\t\t\t\t\t\tKey_SendText(key_lines[edit_line] + 1);\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tutf2ascii(title_keyboard, input_text);\n\t\t\t\t\t\t\tsimulateKeyPress(title_keyboard);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\tsceImeDialogTerm();\n\t\t\t\t\tisKeyboard = false;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\tif ((tmp_pad.buttons & SCE_CTRL_SELECT) && (!(oldpad.buttons & SCE_CTRL_SELECT)))\n\t\t\t\t{\n\t\t\t\t\tif ((m_state == m_setup && (setup_cursor == 0 || setup_cursor == 1)) || (key_dest == key_console) || (m_state == m_lanconfig && (lanConfig_cursor == 0 || lanConfig_cursor == 3)))\n\t\t\t\t\t{\n\t\t\t\t\t\tmemset(input_text, 0, (SCE_IME_DIALOG_MAX_TEXT_LENGTH + 1) << 1);\n\t\t\t\t\t\tmemset(initial_text, 0, (SCE_IME_DIALOG_MAX_TEXT_LENGTH) << 1);\n\t\t\t\t\t\tif (key_dest == key_console) {\n\t\t\t\t\t\t\tsprintf(title_keyboard, \"Insert Quake command\");\n\t\t\t\t\t\t} else if (m_state == m_setup) {\n\t\t\t\t\t\t\t(setup_cursor == 0) ? sprintf(title_keyboard, \"Insert hostname\") : sprintf(title_keyboard, \"Insert player name\");\n\t\t\t\t\t\t} else if (m_state == m_lanconfig){\n\t\t\t\t\t\t\t(lanConfig_cursor == 0) ? sprintf(title_keyboard, \"Insert port number\") : sprintf(title_keyboard, \"Insert server address\");\n\t\t\t\t\t\t}\n\t\t\t\t\t\tascii2utf(title, title_keyboard);\n\t\t\t\t\t\tisKeyboard = true;\n\t\t\t\t\t\tSceImeDialogParam param;\n\t\t\t\t\t\tsceImeDialogParamInit(&param);\n\t\t\t\t\t\tparam.supportedLanguages = 0x0001FFFF;\n\t\t\t\t\t\tparam.languagesForced = SCE_TRUE;\n\t\t\t\t\t\tparam.type = (m_state == m_lanconfig && lanConfig_cursor == 0) ? SCE_IME_TYPE_NUMBER : SCE_IME_TYPE_BASIC_LATIN;\n\t\t\t\t\t\tparam.title = title;\n\t\t\t\t\t\tparam.maxTextLength = (m_state == m_lanconfig && lanConfig_cursor == 0) ? 5 : SCE_IME_DIALOG_MAX_TEXT_LENGTH;\n\t\t\t\t\t\tif (key_dest == key_console)\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tascii2utf(initial_text, key_lines[edit_line] + 1);\n\t\t\t\t\t\t\tascii2utf(input_text, key_lines[edit_line] + 1);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tparam.initialText = initial_text;\n\t\t\t\t\t\tparam.inputTextBuffer = input_text;\n\t\t\t\t\t\tsceImeDialogInit(&param);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\toldpad = tmp_pad;\n\t\t}\n\n\t\t// Get current frame\n\t\tSceRtcTick tick;\n\t\tsceRtcGetCurrentTick(&tick);\n\t\tconst unsigned int deltaTick = tick.tick - lastTick.tick;\n\t\tconst float   deltaSecond = deltaTick * tickRate;\n\n\t\t// Show frame\n\t\tHost_Frame(deltaSecond);\n\t\tlastTick.tick = tick.tick;\n\n\t}\n\n\treturn 0;\n}\n\nint main(int argc, char **argv) {\n\t// We need a bigger stack to run Quake, so we create a new thread with a proper stack size\n\tSceUID main_thread = sceKernelCreateThread(\"Quake\", quake_main, 0x40, 0x800000, 0, 0, NULL);\n\tif (main_thread >= 0){\n\t\tsceKernelStartThread(main_thread, 0, NULL);\n\t}\n\treturn sceKernelExitDeleteThread(0);\n}\n"
  },
  {
    "path": "source/vid.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// vid.h -- video driver defs\n\n#define VID_CBITS\t6\n#define VID_GRADES\t(1 << VID_CBITS)\n\n// a pixel can be one, two, or four bytes\ntypedef byte pixel_t;\n\ntypedef struct vrect_s\n{\n\tint\t\t\t\tx,y,width,height;\n\tstruct vrect_s\t*pnext;\n} vrect_t;\n\ntypedef struct\n{\n\tpixel_t\t\t\t*buffer;\t\t// invisible buffer\n\tpixel_t\t\t\t*colormap;\t\t// 256 * VID_GRADES size\n\tunsigned short\t*colormap16;\t// 256 * VID_GRADES size\n\tint\t\t\t\tfullbright;\t\t// index of first fullbright color\n\tunsigned\t\trowbytes;\t// may be > width if displayed in a window\n\tunsigned\t\twidth;\t\t\n\tunsigned\t\theight;\n\tfloat\t\t\taspect;\t\t// width / height -- < 0 is taller than wide\n\tint\t\t\t\tnumpages;\n\tint\t\t\t\trecalc_refdef;\t// if true, recalc vid-based stuff\n\tpixel_t\t\t\t*conbuffer;\n\tint\t\t\t\tconrowbytes;\n\tunsigned\t\tconwidth;\n\tunsigned\t\tconheight;\n\tint\t\t\t\tmaxwarpwidth;\n\tint\t\t\t\tmaxwarpheight;\n\tpixel_t\t\t\t*direct;\t\t// direct drawing to framebuffer, if not\n\t\t\t\t\t\t\t\t\t//  NULL\n} viddef_t;\n\nextern\tviddef_t\tvid;\t\t\t\t// global video state\nextern\tunsigned short\td_8to16table[256];\nextern\tunsigned\td_8to24table[256];\nextern void (*vid_menudrawfn)(void);\nextern void (*vid_menukeyfn)(int key);\n\nvoid\tVID_SetPalette (unsigned char *palette);\n// called at startup and after any gamma correction\n\nvoid\tVID_ShiftPalette (unsigned char *palette);\n// called for bonus and pain flashes, and for underwater color changes\n\nvoid\tVID_Init (unsigned char *palette);\n// Called at startup to set up translation tables, takes 256 8 bit RGB values\n// the palette data will go away after the call, so it must be copied off if\n// the video driver will need it again\n\nvoid\tVID_Shutdown (void);\n// Called at shutdown\n\nvoid\tVID_Update (vrect_t *rects);\n// flushes the given rectangles from the view buffer to the screen\n\nint VID_SetMode (int modenum, unsigned char *palette);\n// sets the mode; only used by the Quake engine for resetting to mode 0 (the\n// base mode) on memory allocation failures\n\nvoid VID_HandlePause (bool pause);\n// called only on Win32, when pause happens, so the mouse can be released\n\nvoid VID_ChangeRes(float scale);\n// called only on Vita build, changes rescaler properties"
  },
  {
    "path": "source/view.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// view.c -- player eye positioning\n\n#include \"quakedef.h\"\n#include \"r_local.h\"\n\n/*\n\nThe view is allowed to move slightly from it's true position for bobbing,\nbut if it exceeds 8 pixels linear distance (spherical, not box), the list of\nentities sent from the server may not include everything in the pvs, especially\nwhen crossing a water boudnary.\n\n*/\n\nCVAR (lcd_x, 0, CVAR_NONE)\nCVAR(lcd_yaw, 0, CVAR_NONE)\n\nCVAR(scr_ofsx, 0, CVAR_NONE)\nCVAR(scr_ofsy, 0, CVAR_NONE)\nCVAR(scr_ofsz, 0, CVAR_NONE)\n\nCVAR(cl_rollspeed, 200, CVAR_NONE)\nCVAR(cl_rollangle, 2.0, CVAR_NONE)\n\nCVAR(cl_bob, 0.02, CVAR_NONE)\nCVAR(cl_bobcycle, 0.6, CVAR_NONE)\nCVAR(cl_bobup, 0.5, CVAR_NONE)\n\nCVAR(v_kicktime, 0.5, CVAR_NONE)\nCVAR(v_kickroll, 0.6, CVAR_NONE)\nCVAR(v_kickpitch, 0.6, CVAR_NONE)\n\nCVAR(v_iyaw_cycle, 2, CVAR_NONE)\nCVAR(v_iroll_cycle, 0.5, CVAR_NONE)\nCVAR(v_ipitch_cycle, 1, CVAR_NONE)\nCVAR(v_iyaw_level, 0.3, CVAR_NONE)\nCVAR(v_iroll_level, 0.1, CVAR_NONE)\nCVAR(v_ipitch_level, 0.3, CVAR_NONE)\n\nCVAR(v_idlescale, 0, CVAR_NONE)\n\nCVAR(crosshair, 1, CVAR_ARCHIVE)\nCVAR(crosshaircolor_r, 255, CVAR_ARCHIVE)\nCVAR(crosshaircolor_g, 255, CVAR_ARCHIVE)\nCVAR(crosshaircolor_b, 0, CVAR_ARCHIVE)\nCVAR(cl_crossx, 0, CVAR_NONE)\nCVAR(cl_crossy, 0, CVAR_NONE)\n\nCVAR(gl_cshiftpercent, 100, CVAR_NONE)\n\nCVAR(v_centermove, 0.15, CVAR_NONE)\nCVAR(v_centerspeed, 500, CVAR_NONE)\n\nCVAR(r_viewmodel_quake, 1, CVAR_ARCHIVE)\nCVAR(r_viewmodeloffset, 0, CVAR_ARCHIVE)\n\n\n//----------------------------------------------\n\nfloat v_dmg_time, v_dmg_roll, v_dmg_pitch;\nextern int in_forward, in_forward2, in_back;\n\n/*\n===============\nV_CalcRoll\n\nUsed by view and sv_user\n===============\n*/\nvec3_t\tforward, right, up;\n\nfloat V_CalcRoll (vec3_t angles, vec3_t velocity)\n{\n\tfloat\tsign;\n\tfloat\tside;\n\tfloat\tvalue;\n\t\n\tAngleVectors (angles, forward, right, up);\n\tside = DotProduct (velocity, right);\n\tsign = side < 0 ? -1 : 1;\n\tside = fabs(side);\n\t\n\tvalue = cl_rollangle.value;\n//\tif (cl.inwater)\n//\t\tvalue *= 6;\n\n\tif (side < cl_rollspeed.value)\n\t\tside = side * value / cl_rollspeed.value;\n\telse\n\t\tside = value;\n\t\n\treturn side*sign;\n\t\n}\n\n\n/*\n===============\nV_CalcBob\n\n===============\n*/\nfloat V_CalcBob (void)\n{\n\tfloat\tbob;\n\tfloat\tcycle;\n\t\n\tcycle = cl.time - (int)(cl.time/cl_bobcycle.value)*cl_bobcycle.value;\n\tcycle /= cl_bobcycle.value;\n\tif (cycle < cl_bobup.value)\n\t\tcycle = M_PI * cycle / cl_bobup.value;\n\telse\n\t\tcycle = M_PI + M_PI*(cycle-cl_bobup.value)/(1.0 - cl_bobup.value);\n\n// bob is proportional to velocity in the xy plane\n// (don't count Z, or jumping messes it up)\n\n\tbob = sqrt(cl.velocity[0]*cl.velocity[0] + cl.velocity[1]*cl.velocity[1]) * cl_bob.value;\n//Con_Printf (\"speed: %5.1f\\n\", Length(cl.velocity));\n\tbob = bob*0.3 + bob*0.7*sin(cycle);\n\tif (bob > 4)\n\t\tbob = 4;\n\telse if (bob < -7)\n\t\tbob = -7;\n\treturn bob;\n\t\n}\n\n\n//=============================================================================\n\n\nvoid V_StartPitchDrift (void)\n{\n#if 1\n\tif (cl.laststop == cl.time)\n\t{\n\t\treturn;\t\t// something else is keeping it from drifting\n\t}\n#endif\n\tif (cl.nodrift || !cl.pitchvel)\n\t{\n\t\tcl.pitchvel = v_centerspeed.value;\n\t\tcl.nodrift = false;\n\t\tcl.driftmove = 0;\n\t}\n}\n\nvoid V_StopPitchDrift (void)\n{\n\tcl.laststop = cl.time;\n\tcl.nodrift = true;\n\tcl.pitchvel = 0;\n}\n\n/*\n===============\nV_DriftPitch\n\nMoves the client pitch angle towards cl.idealpitch sent by the server.\n\nIf the user is adjusting pitch manually, either with lookup/lookdown,\nmlook and mouse, or klook and keyboard, pitch drifting is constantly stopped.\n\nDrifting is enabled when the center view key is hit, mlook is released and\nlookspring is non 0, or when \n===============\n*/\nvoid V_DriftPitch (void)\n{\n\tfloat\t\tdelta, move;\n\n\tif (noclip_anglehack || !cl.onground || cls.demoplayback )\n\t{\n\t\tcl.driftmove = 0;\n\t\tcl.pitchvel = 0;\n\t\treturn;\n\t}\n\n// don't count small mouse motion\n\tif (cl.nodrift)\n\t{\n\t\tif ( fabs(cl.cmd.forwardmove) < cl_forwardspeed.value)\n\t\t\tcl.driftmove = 0;\n\t\telse\n\t\t\tcl.driftmove += host_frametime;\n\t\n\t\tif ( cl.driftmove > v_centermove.value)\n\t\t{\n\t\t\tV_StartPitchDrift ();\n\t\t}\n\t\treturn;\n\t}\n\t\n\tdelta = cl.idealpitch - cl.viewangles[PITCH];\n\n\tif (!delta)\n\t{\n\t\tcl.pitchvel = 0;\n\t\treturn;\n\t}\n\n\tmove = host_frametime * cl.pitchvel;\n\tcl.pitchvel += host_frametime * v_centerspeed.value;\n\t\n//Con_Printf (\"move: %f (%f)\\n\", move, host_frametime);\n\n\tif (delta > 0)\n\t{\n\t\tif (move > delta)\n\t\t{\n\t\t\tcl.pitchvel = 0;\n\t\t\tmove = delta;\n\t\t}\n\t\tcl.viewangles[PITCH] += move;\n\t}\n\telse if (delta < 0)\n\t{\n\t\tif (move > -delta)\n\t\t{\n\t\t\tcl.pitchvel = 0;\n\t\t\tmove = -delta;\n\t\t}\n\t\tcl.viewangles[PITCH] -= move;\n\t}\n}\n\n\n/*\n=============\nV_CalcBlend\n=============\n*/\n#ifdef\tGLQUAKE\nvoid V_CalcBlend (void)\n{\n\tfloat\tr, g, b, a, a2;\n\tint\t\tj;\n\n\tr = 0;\n\tg = 0;\n\tb = 0;\n\ta = 0;\n\n\tfor (j=0 ; j<NUM_CSHIFTS ; j++)\t\n\t{\n\t\tif (!gl_cshiftpercent.value)\n\t\t\tcontinue;\n\n\t\ta2 = ((cl.cshifts[j].percent * gl_cshiftpercent.value) / 100.0) / 255.0;\n\n//\t\ta2 = (cl.cshifts[j].percent/2)/255.0;\n\t\tif (!a2)\n\t\t\tcontinue;\n\t\ta = a + a2*(1-a);\n//Con_Printf (\"j:%i a:%f\\n\", j, a);\n\t\ta2 = a2/a;\n\t\tr = r*(1-a2) + cl.cshifts[j].destcolor[0]*a2;\n\t\tg = g*(1-a2) + cl.cshifts[j].destcolor[1]*a2;\n\t\tb = b*(1-a2) + cl.cshifts[j].destcolor[2]*a2;\n\t}\n\n\tv_blend[0] = r/255.0;\n\tv_blend[1] = g/255.0;\n\tv_blend[2] = b/255.0;\n\tv_blend[3] = a;\n\tif (v_blend[3] > 1)\n\t\tv_blend[3] = 1;\n\tif (v_blend[3] < 0)\n\t\tv_blend[3] = 0;\n}\n#endif\n\n\n/*\n============================================================================== \n \n\t\t\t\t\t\tPALETTE FLASHES \n \n============================================================================== \n*/ \n \n \ncshift_t\tcshift_empty = { {0,0,0}, 0 };\ncshift_t\tcshift_water = { {130,80,50}, 128 };\ncshift_t\tcshift_slime = { {0,25,5}, 150 };\ncshift_t\tcshift_lava = { {255,80,0}, 150 };\n\nCVAR\t\t(v_gamma, 1, CVAR_ARCHIVE)\n\nbyte\t\tgammatable[256];\t// palette is sent through this\n\n#ifdef\tGLQUAKE\nbyte\t\tramps[3][256];\nfloat\t\tv_blend[4];\t\t// rgba 0.0 - 1.0\n#endif\t// GLQUAKE\n\nvoid BuildGammaTable (float g)\n{\n\tint\t\ti, inf;\n\t\n\tif (g == 1.0)\n\t{\n\t\tfor (i=0 ; i<256 ; i++)\n\t\t\tgammatable[i] = i;\n\t\treturn;\n\t}\n\t\n\tfor (i=0 ; i<256 ; i++)\n\t{\n\t\tinf = 255 * pow ( (i+0.5)/255.5 , g ) + 0.5;\n\t\tif (inf < 0)\n\t\t\tinf = 0;\n\t\tif (inf > 255)\n\t\t\tinf = 255;\n\t\tgammatable[i] = inf;\n\t}\n}\n\n/*\n=================\nV_CheckGamma\n=================\n*/\nbool V_CheckGamma (void)\n{\n\t/*static float oldgammavalue;\n\t\n\tif (v_gamma.value == oldgammavalue)\n\t\treturn false;\n\toldgammavalue = v_gamma.value;*/\n\n\tBuildGammaTable (v_gamma.value);\n\tvid.recalc_refdef = 1;\t\t\t\t// force a surface cache flush\n\t\n\treturn true;\n}\n\n\n\n/*\n===============\nV_ParseDamage\n===============\n*/\nvoid V_ParseDamage (void)\n{\n\tint\t\tarmor, blood;\n\tvec3_t\tfrom;\n\tint\t\ti;\n\tvec3_t\tforward, right, up;\n\tentity_t\t*ent;\n\tfloat\tside;\n\tfloat\tcount;\n\t\n\tarmor = MSG_ReadByte ();\n\tblood = MSG_ReadByte ();\n\tfor (i=0 ; i<3 ; i++)\n\t\tfrom[i] = MSG_ReadCoord ();\n\n\tcount = blood*0.5 + armor*0.5;\n\tif (count < 10)\n\t\tcount = 10;\n\n\tcl.faceanimtime = cl.time + 0.2;\t\t// but sbar face into pain frame\n\n\tcl.cshifts[CSHIFT_DAMAGE].percent += 3*count;\n\tif (cl.cshifts[CSHIFT_DAMAGE].percent < 0)\n\t\tcl.cshifts[CSHIFT_DAMAGE].percent = 0;\n\tif (cl.cshifts[CSHIFT_DAMAGE].percent > 150)\n\t\tcl.cshifts[CSHIFT_DAMAGE].percent = 150;\n\n\tif (armor > blood)\t\t\n\t{\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 200;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 100;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 100;\n\t}\n\telse if (armor)\n\t{\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 220;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 50;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 50;\n\t}\n\telse\n\t{\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[0] = 255;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[1] = 0;\n\t\tcl.cshifts[CSHIFT_DAMAGE].destcolor[2] = 0;\n\t}\n\n//\n// calculate view angle kicks\n//\n\tent = &cl_entities[cl.viewentity];\n\t\n\tVectorSubtract (from, ent->origin, from);\n\tVectorNormalize (from);\n\t\n\tAngleVectors (ent->angles, forward, right, up);\n\n\tside = DotProduct (from, right);\n\tv_dmg_roll = count*side*v_kickroll.value;\n\t\n\tside = DotProduct (from, forward);\n\tv_dmg_pitch = count*side*v_kickpitch.value;\n\n\tv_dmg_time = v_kicktime.value;\n}\n\n\n/*\n==================\nV_cshift_f\n==================\n*/\nvoid V_cshift_f (void)\n{\n\tcshift_empty.destcolor[0] = atoi(Cmd_Argv(1));\n\tcshift_empty.destcolor[1] = atoi(Cmd_Argv(2));\n\tcshift_empty.destcolor[2] = atoi(Cmd_Argv(3));\n\tcshift_empty.percent = atoi(Cmd_Argv(4));\n}\n\n\n/*\n==================\nV_BonusFlash_f\n\nWhen you run over an item, the server sends this command\n==================\n*/\nvoid V_BonusFlash_f (void)\n{\n\tcl.cshifts[CSHIFT_BONUS].destcolor[0] = 215;\n\tcl.cshifts[CSHIFT_BONUS].destcolor[1] = 186;\n\tcl.cshifts[CSHIFT_BONUS].destcolor[2] = 69;\n\tcl.cshifts[CSHIFT_BONUS].percent = 50;\n}\n\n/*\n=============\nV_SetContentsColor\n\nUnderwater, lava, etc each has a color shift\n=============\n*/\nvoid V_SetContentsColor (int contents)\n{\n\tswitch (contents)\n\t{\n\tcase CONTENTS_EMPTY:\n\tcase CONTENTS_SOLID:\n\tcase CONTENTS_SKY:\n\t\tcl.cshifts[CSHIFT_CONTENTS] = cshift_empty;\n\t\tbreak;\n\tcase CONTENTS_LAVA:\n\t\tcl.cshifts[CSHIFT_CONTENTS] = cshift_lava;\n\t\tbreak;\n\tcase CONTENTS_SLIME:\n\t\tcl.cshifts[CSHIFT_CONTENTS] = cshift_slime;\n\t\tbreak;\n\tdefault:\n\t\tcl.cshifts[CSHIFT_CONTENTS] = cshift_water;\n\t}\n}\n\n/*\n=============\nV_CalcPowerupCshift\n=============\n*/\nvoid V_CalcPowerupCshift (void)\n{\n\tif (cl.items & IT_QUAD)\n\t{\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[1] = 0;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[2] = 255;\n\t\tcl.cshifts[CSHIFT_POWERUP].percent = 30;\n\t}\n\telse if (cl.items & IT_SUIT)\n\t{\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[0] = 0;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;\n\t\tcl.cshifts[CSHIFT_POWERUP].percent = 20;\n\t}\n\telse if (cl.items & IT_INVISIBILITY)\n\t{\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[0] = 100;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[1] = 100;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[2] = 100;\n\t\tcl.cshifts[CSHIFT_POWERUP].percent = 100;\n\t}\n\telse if (cl.items & IT_INVULNERABILITY)\n\t{\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[0] = 255;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[1] = 255;\n\t\tcl.cshifts[CSHIFT_POWERUP].destcolor[2] = 0;\n\t\tcl.cshifts[CSHIFT_POWERUP].percent = 30;\n\t}\n\telse\n\t\tcl.cshifts[CSHIFT_POWERUP].percent = 0;\n}\n\n/*\n=============\nV_UpdatePalette\n=============\n*/\nvoid V_UpdatePalette (void)\n{\n\tint\t\ti, j;\n\tbool\tnew;\n\tbyte\t*basepal, *newpal;\n\tbyte\tpal[768];\n\tint\t\tr,g,b;\n\tbool force;\n\n\tV_CalcPowerupCshift ();\n\t\n\tnew = false;\n\t\n\tfor (i=0 ; i<NUM_CSHIFTS ; i++)\n\t{\n\t\tif (cl.cshifts[i].percent != cl.prev_cshifts[i].percent)\n\t\t{\n\t\t\tnew = true;\n\t\t\tcl.prev_cshifts[i].percent = cl.cshifts[i].percent;\n\t\t}\n\t\tfor (j=0 ; j<3 ; j++)\n\t\t\tif (cl.cshifts[i].destcolor[j] != cl.prev_cshifts[i].destcolor[j])\n\t\t\t{\n\t\t\t\tnew = true;\n\t\t\t\tcl.prev_cshifts[i].destcolor[j] = cl.cshifts[i].destcolor[j];\n\t\t\t}\n\t}\n\t\n// drop the damage value\n\tcl.cshifts[CSHIFT_DAMAGE].percent -= host_frametime*150;\n\tif (cl.cshifts[CSHIFT_DAMAGE].percent <= 0)\n\t\tcl.cshifts[CSHIFT_DAMAGE].percent = 0;\n\n// drop the bonus value\n\tcl.cshifts[CSHIFT_BONUS].percent -= host_frametime*100;\n\tif (cl.cshifts[CSHIFT_BONUS].percent <= 0)\n\t\tcl.cshifts[CSHIFT_BONUS].percent = 0;\n\n\tforce = V_CheckGamma ();\n\tif (!new && !force)\n\t\treturn;\n\t\t\t\n\tbasepal = host_basepal;\n\tnewpal = pal;\n\t\n\tfor (i=0 ; i<256 ; i++)\n\t{\n\t\tr = basepal[0];\n\t\tg = basepal[1];\n\t\tb = basepal[2];\n\t\tbasepal += 3;\n\t\n\t\tfor (j=0 ; j<NUM_CSHIFTS ; j++)\t\n\t\t{\n\t\t\tr += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[0]-r))>>8;\n\t\t\tg += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[1]-g))>>8;\n\t\t\tb += (cl.cshifts[j].percent*(cl.cshifts[j].destcolor[2]-b))>>8;\n\t\t}\n\t\t\n\t\tnewpal[0] = gammatable[r];\n\t\tnewpal[1] = gammatable[g];\n\t\tnewpal[2] = gammatable[b];\n\t\tnewpal += 3;\n\t}\n\n\tVID_ShiftPalette (pal);\t\n}\n\n\n/* \n============================================================================== \n \n\t\t\t\t\t\tVIEW RENDERING \n \n============================================================================== \n*/ \n\nfloat angledelta (float a)\n{\n\ta = anglemod(a);\n\tif (a > 180)\n\t\ta -= 360;\n\treturn a;\n}\n\n/*\n==================\nCalcGunAngle\n==================\n*/\nvoid CalcGunAngle (void)\n{\t\n\tfloat\tyaw, pitch, move;\n\tstatic float oldyaw = 0;\n\tstatic float oldpitch = 0;\n\t\n\tyaw = r_refdef.viewangles[YAW];\n\tpitch = -r_refdef.viewangles[PITCH];\n\n\tyaw = angledelta(yaw - r_refdef.viewangles[YAW]) * 0.4;\n\tif (yaw > 10)\n\t\tyaw = 10;\n\tif (yaw < -10)\n\t\tyaw = -10;\n\tpitch = angledelta(-pitch - r_refdef.viewangles[PITCH]) * 0.4;\n\tif (pitch > 10)\n\t\tpitch = 10;\n\tif (pitch < -10)\n\t\tpitch = -10;\n\tmove = host_frametime*20;\n\tif (yaw > oldyaw)\n\t{\n\t\tif (oldyaw + move < yaw)\n\t\t\tyaw = oldyaw + move;\n\t}\n\telse\n\t{\n\t\tif (oldyaw - move > yaw)\n\t\t\tyaw = oldyaw - move;\n\t}\n\t\n\tif (pitch > oldpitch)\n\t{\n\t\tif (oldpitch + move < pitch)\n\t\t\tpitch = oldpitch + move;\n\t}\n\telse\n\t{\n\t\tif (oldpitch - move > pitch)\n\t\t\tpitch = oldpitch - move;\n\t}\n\t\n\toldyaw = yaw;\n\toldpitch = pitch;\n\n\tcl.viewent.angles[YAW] = r_refdef.viewangles[YAW] + yaw;\n\tcl.viewent.angles[PITCH] = - (r_refdef.viewangles[PITCH] + pitch);\n\n\tv4sf src = {\n\t\tcl.time*v_iroll_cycle.value,\n\t\tcl.time*v_ipitch_cycle.value,\n\t\tcl.time*v_iyaw_cycle.value,\n\t\t0\n\t};\n\t\n\tv4sf dst = sin_ps(src);\n\t\n\tcl.viewent.angles[ROLL] -= v_idlescale.value * dst[0] * v_iroll_level.value;\n\tcl.viewent.angles[PITCH] -= v_idlescale.value * dst[1] * v_ipitch_level.value;\n\tcl.viewent.angles[YAW] -= v_idlescale.value * dst[2] * v_iyaw_level.value;\n}\n\n/*\n==============\nV_BoundOffsets\n==============\n*/\nvoid V_BoundOffsets (void)\n{\n\tentity_t\t*ent;\n\t\n\tent = &cl_entities[cl.viewentity];\n\n// absolutely bound refresh reletive to entity clipping hull\n// so the view can never be inside a solid wall\n\n\tif (r_refdef.vieworg[0] < ent->origin[0] - 14)\n\t\tr_refdef.vieworg[0] = ent->origin[0] - 14;\n\telse if (r_refdef.vieworg[0] > ent->origin[0] + 14)\n\t\tr_refdef.vieworg[0] = ent->origin[0] + 14;\n\tif (r_refdef.vieworg[1] < ent->origin[1] - 14)\n\t\tr_refdef.vieworg[1] = ent->origin[1] - 14;\n\telse if (r_refdef.vieworg[1] > ent->origin[1] + 14)\n\t\tr_refdef.vieworg[1] = ent->origin[1] + 14;\n\tif (r_refdef.vieworg[2] < ent->origin[2] - 22)\n\t\tr_refdef.vieworg[2] = ent->origin[2] - 22;\n\telse if (r_refdef.vieworg[2] > ent->origin[2] + 30)\n\t\tr_refdef.vieworg[2] = ent->origin[2] + 30;\n}\n\n/*\n==============\nV_AddIdle\n\nIdle swaying\n==============\n*/\nvoid V_AddIdle (void)\n{\n\t\n\tv4sf src = {\n\t\tcl.time*v_iroll_cycle.value,\n\t\tcl.time*v_ipitch_cycle.value,\n\t\tcl.time*v_iyaw_cycle.value,\n\t\t0\n\t};\n\t\n\tv4sf dst = sin_ps(src);\n\t\n\tr_refdef.viewangles[ROLL] += v_idlescale.value * dst[0] * v_iroll_level.value;\n\tr_refdef.viewangles[PITCH] += v_idlescale.value * dst[1] * v_ipitch_level.value;\n\tr_refdef.viewangles[YAW] += v_idlescale.value * dst[2] * v_iyaw_level.value;\n}\n\n\n/*\n==============\nV_CalcViewRoll\n\nRoll is induced by movement and damage\n==============\n*/\nvoid V_CalcViewRoll (void)\n{\n\tfloat\t\tside;\n\t\t\n\tside = V_CalcRoll (cl_entities[cl.viewentity].angles, cl.velocity);\n\tr_refdef.viewangles[ROLL] += side;\n\n\tif (v_dmg_time > 0)\n\t{\n\t\tr_refdef.viewangles[ROLL] += v_dmg_time/v_kicktime.value*v_dmg_roll;\n\t\tr_refdef.viewangles[PITCH] += v_dmg_time/v_kicktime.value*v_dmg_pitch;\n\t\tv_dmg_time -= host_frametime;\n\t}\n\n\tif (cl.stats[STAT_HEALTH] <= 0)\n\t{\n\t\tr_refdef.viewangles[ROLL] = 80;\t// dead view angle\n\t\treturn;\n\t}\n\n}\n\n\n/*\n==================\nV_CalcIntermissionRefdef\n\n==================\n*/\nvoid V_CalcIntermissionRefdef (void)\n{\n\tentity_t\t*ent, *view;\n\tfloat\t\told;\n\n// ent is the player model (visible when out of body)\n\tent = &cl_entities[cl.viewentity];\n// view is the weapon model (only visible from inside body)\n\tview = &cl.viewent;\n\n\tVectorCopy (ent->origin, r_refdef.vieworg);\n\tVectorCopy (ent->angles, r_refdef.viewangles);\n\tview->model = NULL;\n\n// always idle in intermission\n\told = v_idlescale.value;\n\tv_idlescale.value = 1;\n\tV_AddIdle ();\n\tv_idlescale.value = old;\n}\n\n/*\n==================\nV_CalcRefdef\n\n==================\n*/\nvoid V_CalcRefdef (void)\n{\n\tentity_t\t*ent, *view;\n\tint\t\t\ti;\n\tvec3_t\t\tforward, right, up;\n\tvec3_t\t\tangles;\n\tfloat\t\tbob;\n\tstatic float oldz = 0;\n\n\tV_DriftPitch ();\n\n// ent is the player model (visible when out of body)\n\tent = &cl_entities[cl.viewentity];\n// view is the weapon model (only visible from inside body)\n\tview = &cl.viewent;\n\t\n\n// transform the view offset by the model's matrix to get the offset from\n// model origin for the view\n\tent->angles[YAW] = cl.viewangles[YAW];\t// the model should face\n\t\t\t\t\t\t\t\t\t\t// the view dir\n\tent->angles[PITCH] = -cl.viewangles[PITCH];\t// the model should face\n\t\t\t\t\t\t\t\t\t\t// the view dir\n\t\t\t\t\t\t\t\t\t\t\n\t\n\tbob = V_CalcBob ();\n\t\n// refresh position\n\tVectorCopy (ent->origin, r_refdef.vieworg);\n\tr_refdef.vieworg[2] += cl.viewheight + bob;\n\n// never let it sit exactly on a node line, because a water plane can\n// dissapear when viewed with the eye exactly on it.\n// the server protocol only specifies to 1/16 pixel, so add 1/32 in each axis\n\tr_refdef.vieworg[0] += 1.0/32;\n\tr_refdef.vieworg[1] += 1.0/32;\n\tr_refdef.vieworg[2] += 1.0/32;\n\n\tVectorCopy (cl.viewangles, r_refdef.viewangles);\n\tV_CalcViewRoll ();\n\tV_AddIdle ();\n\n// offsets\n\tangles[PITCH] = -ent->angles[PITCH];\t// because entity pitches are\n\t\t\t\t\t\t\t\t\t\t\t//  actually backward\n\tangles[YAW] = ent->angles[YAW];\n\tangles[ROLL] = ent->angles[ROLL];\n\n\tAngleVectors (angles, forward, right, up);\n\n\tfor (i=0 ; i<3 ; i++)\n\t\tr_refdef.vieworg[i] += scr_ofsx.value*forward[i]\n\t\t\t+ scr_ofsy.value*right[i]\n\t\t\t+ scr_ofsz.value*up[i];\n\t\n\t\n\tV_BoundOffsets ();\n\t\t\n// set up gun position\n\tVectorCopy (cl.viewangles, view->angles);\n\t\n\tCalcGunAngle ();\n\n\tVectorCopy (ent->origin, view->origin);\n\tview->origin[2] += cl.viewheight;\n\n\tVectorCopy (r_refdef.vieworg, view->origin);\n\tVectorMA (view->origin, bob * 0.4, forward, view->origin);\n\n\tif (r_viewmodeloffset.string[0]) {\n\t\tfloat offset[3];\n\t\tint size = sizeof(offset)/sizeof(offset[0]);\n\n\t\tParseFloats(r_viewmodeloffset.string, offset, &size);\n\t\tVectorMA (view->origin,  offset[0], right,   view->origin);\n\t\tVectorMA (view->origin, -offset[1], up,      view->origin);\n\t\tVectorMA (view->origin,  offset[2], forward, view->origin);\n\t}\n\n// fudge position around to keep amount of weapon visible\n// roughly equal with different FOV\n\n\tif (r_viewmodel_quake.value)\n\t{\n\t\tif (viewsize.value == 110)\n\t\t\tview->origin[2] += 1;\n\t\telse if (viewsize.value == 100)\n\t\t\tview->origin[2] += 2;\n\t\telse if (viewsize.value == 90)\n\t\t\tview->origin[2] += 1;\n\t\telse if (viewsize.value == 80)\n\t\t\tview->origin[2] += 0.5;\n\t}\n\n\tview->model = cl.model_precache[cl.stats[STAT_WEAPON]];\n\tview->frame = cl.stats[STAT_WEAPONFRAME];\n\tview->colormap = vid.colormap;\n\n// set up the refresh position\n\tVectorAdd (r_refdef.viewangles, cl.punchangle, r_refdef.viewangles);\n\n// smooth out stair step ups\nif (cl.onground && ent->origin[2] - oldz > 0)\n{\n\tfloat steptime;\n\t\n\tsteptime = cl.time - cl.oldtime;\n\tif (steptime < 0)\n//FIXME\t\tI_Error (\"steptime < 0\");\n\t\tsteptime = 0;\n\n\toldz += steptime * 80;\n\tif (oldz > ent->origin[2])\n\t\toldz = ent->origin[2];\n\tif (ent->origin[2] - oldz > 12)\n\t\toldz = ent->origin[2] - 12;\n\tr_refdef.vieworg[2] += oldz - ent->origin[2];\n\tview->origin[2] += oldz - ent->origin[2];\n}\nelse\n\toldz = ent->origin[2];\n\n\tif (chase_active.value)\n\t\tChase_Update ();\n}\n\n/*\n==================\nV_RenderView\n\nThe player's clipping box goes from (-16 -16 -24) to (16 16 32) from\nthe entity origin, so any view position inside that will be valid\n==================\n*/\nextern vrect_t\tscr_vrect;\n\nvoid V_RenderView (void)\n{\n\tif (con_forcedup)\n\t\treturn;\n\n// don't allow cheats in multiplayer\n\tif (cl.maxclients > 1)\n\t{\n\t\tCvar_Set (\"scr_ofsx\", \"0\");\n\t\tCvar_Set (\"scr_ofsy\", \"0\");\n\t\tCvar_Set (\"scr_ofsz\", \"0\");\n\t}\n\n\tif (cl.intermission)\n\t{\t// intermission / finale rendering\n\t\tV_CalcIntermissionRefdef ();\t\n\t}\n\telse\n\t{\n\t\tif (!cl.paused /* && (sv.maxclients > 1 || key_dest == key_game) */ )\n\t\t\tV_CalcRefdef ();\n\t}\n\n\tR_PushDlights ();\n\n\tR_RenderView ();\n\n}\n\n//============================================================================\n\n/*\n=============\nV_Init\n=============\n*/\nvoid V_Init (void)\n{\n\tCmd_AddCommand (\"v_cshift\", V_cshift_f);\t\n\tCmd_AddCommand (\"bf\", V_BonusFlash_f);\n\tCmd_AddCommand (\"centerview\", V_StartPitchDrift);\n\n\tCvar_RegisterVariable (&lcd_x);\n\tCvar_RegisterVariable (&lcd_yaw);\n\n\tCvar_RegisterVariable (&v_centermove);\n\tCvar_RegisterVariable (&v_centerspeed);\n\n\tCvar_RegisterVariable (&v_iyaw_cycle);\n\tCvar_RegisterVariable (&v_iroll_cycle);\n\tCvar_RegisterVariable (&v_ipitch_cycle);\n\tCvar_RegisterVariable (&v_iyaw_level);\n\tCvar_RegisterVariable (&v_iroll_level);\n\tCvar_RegisterVariable (&v_ipitch_level);\n\n\tCvar_RegisterVariable (&v_idlescale);\n\tCvar_RegisterVariable (&crosshair);\n\tCvar_RegisterVariable (&crosshaircolor_r);\n\tCvar_RegisterVariable (&crosshaircolor_g);\n\tCvar_RegisterVariable (&crosshaircolor_b);\n\tCvar_RegisterVariable (&cl_crossx);\n\tCvar_RegisterVariable (&cl_crossy);\n\tCvar_RegisterVariable (&gl_cshiftpercent);\n\n\tCvar_RegisterVariable (&scr_ofsx);\n\tCvar_RegisterVariable (&scr_ofsy);\n\tCvar_RegisterVariable (&scr_ofsz);\n\tCvar_RegisterVariable (&cl_rollspeed);\n\tCvar_RegisterVariable (&cl_rollangle);\n\tCvar_RegisterVariable (&cl_bob);\n\tCvar_RegisterVariable (&cl_bobcycle);\n\tCvar_RegisterVariable (&cl_bobup);\n\n\tCvar_RegisterVariable (&v_kicktime);\n\tCvar_RegisterVariable (&v_kickroll);\n\tCvar_RegisterVariable (&v_kickpitch);\t\n\t\n\tBuildGammaTable (1.0);\t// no gamma yet\n\tCvar_RegisterVariable (&v_gamma);\n\n\tCvar_RegisterVariable (&r_viewmodel_quake);\n\tCvar_RegisterVariable (&r_viewmodeloffset);\n}\n\n\n"
  },
  {
    "path": "source/view.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// view.h\n\nextern\tcvar_t\t\tv_gamma;\n\nextern\tbyte\t\tgammatable[256];\t// palette is sent through this\nextern\tbyte\t\tramps[3][256];\nextern float v_blend[4];\n\nextern cvar_t lcd_x;\n\n\nvoid V_Init (void);\nvoid V_RenderView (void);\nfloat V_CalcRoll (vec3_t angles, vec3_t velocity);\nvoid V_UpdatePalette (void);\n\n"
  },
  {
    "path": "source/wad.c",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// wad.c\n\n#include \"quakedef.h\"\n\nint\t\t\twad_numlumps;\nlumpinfo_t\t*wad_lumps;\nbyte\t\t*wad_base;\n\nvoid SwapPic (qpic_t *pic);\n\n/*\n==================\nW_CleanupName\n\nLowercases name and pads with spaces and a terminating 0 to the length of\nlumpinfo_t->name.\nUsed so lumpname lookups can proceed rapidly by comparing 4 chars at a time\nSpace padding is so names can be printed nicely in tables.\nCan safely be performed in place.\n==================\n*/\nvoid W_CleanupName (const char *in, char *out)\n{\n\tint\t\ti;\n\tint\t\tc;\n\t\n\tfor (i=0 ; i<16 ; i++ )\n\t{\n\t\tc = in[i];\n\t\tif (!c)\n\t\t\tbreak;\n\t\t\t\n\t\tif (c >= 'A' && c <= 'Z')\n\t\t\tc += ('a' - 'A');\n\t\tout[i] = c;\n\t}\n\t\n\tfor ( ; i< 16 ; i++ )\n\t\tout[i] = 0;\n}\n\n\n\n/*\n====================\nW_LoadWadFile\n====================\n*/\nvoid W_LoadWadFile (char *filename)\n{\n\tlumpinfo_t\t\t*lump_p;\n\twadinfo_t\t\t*header;\n\tunsigned\t\ti;\n\tint\t\t\t\tinfotableofs;\n\t\n\twad_base = COM_LoadHunkFile (filename, NULL);\n\tif (!wad_base)\n\t\tSys_Error (\"W_LoadWadFile: couldn't load %s\", filename);\n\n\theader = (wadinfo_t *)wad_base;\n\t\n\tif (header->identification[0] != 'W'\n\t|| header->identification[1] != 'A'\n\t|| header->identification[2] != 'D'\n\t|| header->identification[3] != '2')\n\t\tSys_Error (\"Wad file %s doesn't have WAD2 id\\n\",filename);\n\t\t\n\twad_numlumps = LittleLong(header->numlumps);\n\tinfotableofs = LittleLong(header->infotableofs);\n\twad_lumps = (lumpinfo_t *)(wad_base + infotableofs);\n\t\n\tfor (i=0, lump_p = wad_lumps ; i<wad_numlumps ; i++,lump_p++)\n\t{\n\t\tlump_p->filepos = LittleLong(lump_p->filepos);\n\t\tlump_p->size = LittleLong(lump_p->size);\n\t\tW_CleanupName (lump_p->name, lump_p->name);\n\t\tif (lump_p->type == TYP_QPIC)\n\t\t\tSwapPic ( (qpic_t *)(wad_base + lump_p->filepos));\n\t}\n}\n\n\n/*\n=============\nW_GetLumpinfo\n=============\n*/\nlumpinfo_t\t*W_GetLumpinfo (const char *name)\n{\n\tint\t\ti;\n\tlumpinfo_t\t*lump_p;\n\tchar\tclean[16];\n\t\n\tW_CleanupName (name, clean);\n\t\n\tfor (lump_p=wad_lumps, i=0 ; i<wad_numlumps ; i++,lump_p++)\n\t{\n\t\tif (!strcmp(clean, lump_p->name))\n\t\t\treturn lump_p;\n\t}\n\t\n\tSys_Error (\"W_GetLumpinfo: %s not found\", name);\n\treturn NULL;\n}\n\nvoid *W_GetLumpName (const char *name)\n{\n\tlumpinfo_t\t*lump;\n\t\n\tlump = W_GetLumpinfo (name);\n\t\n\treturn (void *)(wad_base + lump->filepos);\n}\n\nvoid *W_GetLumpNum (int num)\n{\n\tlumpinfo_t\t*lump;\n\t\n\tif (num < 0 || num > wad_numlumps)\n\t\tSys_Error (\"W_GetLumpNum: bad number: %i\", num);\n\t\t\n\tlump = wad_lumps + num;\n\t\n\treturn (void *)(wad_base + lump->filepos);\n}\n\n/*\n=============================================================================\n\nautomatic byte swapping\n\n=============================================================================\n*/\n\nvoid SwapPic (qpic_t *pic)\n{\n\tpic->width = LittleLong(pic->width);\n\tpic->height = LittleLong(pic->height);\t\n}\n\n/*\n=============================================================================\nWAD3 Texture Loading for BSP 3.0 Support\n=============================================================================\n*/\n\n#ifdef GLQUAKE\n\n#define TEXWAD_MAXIMAGES 16384\n\ntypedef struct {\n\tchar name[MAX_QPATH];\n\tFILE *file;\n\tint position;\n\tint size;\n} texwadlump_t;\n\nstatic texwadlump_t texwadlump[TEXWAD_MAXIMAGES];\n\nvoid WAD3_LoadTextureWadFile (char *filename) {\n\tlumpinfo_t *lumps, *lump_p;\n\twadinfo_t header;\n\tint i, j, infotableofs, numlumps, lowmark;\n\tFILE *file;\n\n\tif (COM_FOpenFile (va(\"textures/halflife/%s\", filename), &file, NULL) != -1)\n\t\tgoto loaded;\n\tif (COM_FOpenFile (va(\"textures/%s\", filename), &file, NULL) != -1)\n\t\tgoto loaded;\n\tif (COM_FOpenFile (filename, &file, NULL) != -1)\n\t\tgoto loaded;\n\n\tHost_Error (\"Couldn't load halflife wad \\\"%s\\\"\\n\", filename);\n\nloaded:\n\tif (fread(&header, 1, sizeof(wadinfo_t), file) != sizeof(wadinfo_t)) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: unable to read wad header\");\n\t\treturn;\n\t}\n\n\tif (memcmp(header.identification, \"WAD3\", 4)) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: Wad file %s doesn't have WAD3 id\\n\",filename);\n\t\treturn;\n\t}\n\n\tnumlumps = LittleLong(header.numlumps);\n\tif (numlumps < 1 || numlumps > TEXWAD_MAXIMAGES) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: invalid number of lumps (%i)\\n\", numlumps);\n\t\treturn;\n\t}\n\n\tinfotableofs = LittleLong(header.infotableofs);\n\tif (fseek(file, infotableofs, SEEK_SET)) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: unable to seek to lump table\");\n\t\treturn;\n\t}\n\n\tlowmark = Hunk_LowMark();\n\tif (!(lumps = Hunk_Alloc(sizeof(lumpinfo_t) * numlumps))) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: unable to allocate temporary memory for lump table\");\n\t\treturn;\n\t}\n\n\tif (fread(lumps, 1, sizeof(lumpinfo_t) * numlumps, file) != sizeof(lumpinfo_t) * numlumps) {\n\t\tCon_Printf (\"WAD3_LoadTextureWadFile: unable to read lump table\");\n\t\tHunk_FreeToLowMark(lowmark);\n\t\treturn;\n\t}\n\n\tfor (i = 0, lump_p = lumps; i < numlumps; i++,lump_p++) {\n\t\tW_CleanupName (lump_p->name, lump_p->name);\n\t\tfor (j = 0; j < TEXWAD_MAXIMAGES; j++) {\n\t\t\tif (!texwadlump[j].name[0] || !strcmp(lump_p->name, texwadlump[j].name))\n\t\t\t\tbreak;\n\t\t}\n\t\tif (j == TEXWAD_MAXIMAGES)\n\t\t\tbreak; // we are full, don't load any more\n\t\tif (!texwadlump[j].name[0])\n\t\t\tstrncpyz (texwadlump[j].name, lump_p->name, sizeof(texwadlump[j].name));\n\t\ttexwadlump[j].file = file;\n\t\ttexwadlump[j].position = LittleLong(lump_p->filepos);\n\t\ttexwadlump[j].size = LittleLong(lump_p->disksize);\n\t}\n\n\tHunk_FreeToLowMark(lowmark);\n\t//leaves the file open\n}\n\n//converts paletted to rgba\nstatic byte *ConvertWad3ToRGBA(miptex_t *tex) {\n\tbyte *in, *data, *pal;\n\tint i, p, image_size;\n\n\tif (!tex->offsets[0])\n\t\tSys_Error(\"ConvertWad3ToRGBA: tex->offsets[0] == 0\");\n\n\timage_size = tex->width * tex->height;\n\tin = (byte *) ((byte *) tex + tex->offsets[0]);\n\tdata = malloc(image_size * 4); // Baker\n\n\tpal = in + ((image_size * 85) >> 6) + 2;\n\tfor (i = 0; i < image_size; i++) {\n\t\tp = *in++;\n\t\tif (tex->name[0] == '{' && p == 255) {\n\t\t\t((int *) data)[i] = 0;\n\t\t} else {\n\t\t\tp *= 3;\n\t\t\tdata[i * 4 + 0] = pal[p];\n\t\t\tdata[i * 4 + 1] = pal[p + 1];\n\t\t\tdata[i * 4 + 2] = pal[p + 2];\n\t\t\tdata[i * 4 + 3] = 255;\n\t\t}\n\t}\n\treturn data;\n}\n\nbyte *WAD3_LoadTexture(miptex_t *mt) {\n\tchar texname[MAX_QPATH];\n\tint i, j, lowmark = 0;\n\tFILE *file;\n\tmiptex_t *tex;\n\tbyte *data;\n\n\tif (mt->offsets[0])\n\t\treturn ConvertWad3ToRGBA(mt);\n\n\ttexname[sizeof(texname) - 1] = 0;\n\tW_CleanupName (mt->name, texname);\n\tfor (i = 0; i < TEXWAD_MAXIMAGES; i++) {\n\t\tif (!texwadlump[i].name[0])\n\t\t\tbreak;\n\t\tif (strcmp(texname, texwadlump[i].name))\n\t\t\tcontinue;\n\n\t\tfile = texwadlump[i].file;\n\t\tif (fseek(file, texwadlump[i].position, SEEK_SET)) {\n\t\t\tCon_Printf(\"WAD3_LoadTexture: corrupt WAD3 file\");\n\t\t\treturn NULL;\n\t\t}\n\t\tlowmark = Hunk_LowMark();\n\t\ttex = Hunk_Alloc(texwadlump[i].size);\n\t\tif (fread(tex, 1, texwadlump[i].size, file) < texwadlump[i].size) {\n\t\t\tCon_Printf(\"WAD3_LoadTexture: corrupt WAD3 file\");\n\t\t\tHunk_FreeToLowMark(lowmark);\n\t\t\treturn NULL;\n\t\t}\n\t\ttex->width = LittleLong(tex->width);\n\t\ttex->height = LittleLong(tex->height);\n\t\tif (tex->width != mt->width || tex->height != mt->height) {\n\t\t\tHunk_FreeToLowMark(lowmark);\n\t\t\treturn NULL;\n\t\t}\n\t\tfor (j = 0;j < MIPLEVELS;j++)\n\t\t\ttex->offsets[j] = LittleLong(tex->offsets[j]);\n\t\tdata = ConvertWad3ToRGBA(tex);\n\t\tHunk_FreeToLowMark(lowmark);\n\t\treturn data;\n\t}\n\treturn NULL;\n}\n\n#endif"
  },
  {
    "path": "source/wad.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n// wad.h\n\n//===============\n//   TYPES\n//===============\n\n#define\tCMP_NONE\t\t0\n#define\tCMP_LZSS\t\t1\n\n#define\tTYP_NONE\t\t0\n#define\tTYP_LABEL\t\t1\n\n#define\tTYP_LUMPY\t\t64\t\t\t\t// 64 + grab command number\n#define\tTYP_PALETTE\t\t64\n#define\tTYP_QTEX\t\t65\n#define\tTYP_QPIC\t\t66\n#define\tTYP_SOUND\t\t67\n#define\tTYP_MIPTEX\t\t68\n\ntypedef struct\n{\n\tint\t\t\twidth, height;\n\tbyte\t\tdata[4];\t\t\t// variably sized\n} qpic_t;\n\n\n\ntypedef struct\n{\n\tchar\t\tidentification[4];\t\t// should be WAD2 or 2DAW\n\tint\t\t\tnumlumps;\n\tint\t\t\tinfotableofs;\n} wadinfo_t;\n\ntypedef struct\n{\n\tint\t\t\tfilepos;\n\tint\t\t\tdisksize;\n\tint\t\t\tsize;\t\t\t\t\t// uncompressed\n\tchar\t\ttype;\n\tchar\t\tcompression;\n\tchar\t\tpad1, pad2;\n\tchar\t\tname[16];\t\t\t\t// must be null terminated\n} lumpinfo_t;\n\nextern\tint\t\t\twad_numlumps;\nextern\tlumpinfo_t\t*wad_lumps;\nextern\tbyte\t\t*wad_base;\n\nvoid\tW_LoadWadFile (char *filename);\nvoid\tW_CleanupName (const char *in, char *out);\nlumpinfo_t\t*W_GetLumpinfo (const char *name);\nvoid\t*W_GetLumpName (const char *name);\nvoid\t*W_GetLumpNum (int num);\n\nvoid SwapPic (qpic_t *pic);\n"
  },
  {
    "path": "source/webdownload.c",
    "content": "/*\n   Copyright (C) 2006 Pekka Lampila (\"Medar\"), Damien Deville (\"Pb\")\n   and German Garcia Fernandez (\"Jal\") for Chasseur de bots association.\n\n\n   This program is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License\n   as published by the Free Software Foundation; either version 2\n   of the License, or (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n   See the GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n */\n\n\n#include \"webdownload.h\"\n#include \"quakedef.h\"\n\n#include <curl/curl.h>\n#include <stdio.h>\n\nstatic int Web_Init( void );\nstatic void Web_Cleanup( void );\n\n// to get the size and mime type before the download we can use that\n// http://curl.haxx.se/mail/lib-2002-05/0036.html\n\n// Baker: NO ... use #define APPLICATION \"Qrack\"\n\nstatic CURL *curl = NULL;\nstatic char curl_err[1024];\nstatic int ( *progress )(double)= NULL;\n\nstatic size_t Write( void *ptr, size_t size, size_t nmemb, void *stream )\n{\n\tFILE *f;\n\t//Con_Printf(\"name %s path %s\\n\", data->name, data->path);\n\tf = fopen( (char *)stream, \"ab\" );\n\n\tif( f == NULL )\n\t\treturn size*nmemb; // weird\n\n\t//fwrite(ptr,size,nmemb,(FILE *) stream);\n\tfwrite( ptr, size, nmemb, f );\n\tfclose( f );\n\n\treturn size*nmemb;\n}\n\nstatic int Progress( void *clientp, double dltotal, double dlnow, double ultotal, double ulnow )\n{\n\t// callback\n\tif( progress != NULL )\n\t{\n\t\tif( progress( dlnow/dltotal ) != 0 )\n\t\t\treturn 1; // we abort\n\t}\n\n\t//Con_Printf(\"Progress: %2.2f\\n\",dlnow*100.0/dltotal);\n\treturn 0;\n}\n\nstatic void Web_Cleanup( void )\n{\n\tif( curl != NULL )\n\t{\n\t\t/* always cleanup */\n\t\tcurl_easy_cleanup( curl );\n\t\tcurl = NULL;\n\n\t\t// reset callback\n\t\tprogress = NULL;\n\t}\n}\n\nstatic int Web_Init( void )\n{\n\tCURLcode code;\n\tchar useragent[256];\n\n\tif( curl != NULL )\n\t{\n\t\tWeb_Cleanup();\n\t}\n\n\t// reinit\n\tcurl = curl_easy_init();\n\t// reset callback\n\tprogress = NULL;\n\n\t// http://curl.haxx.se/libcurl/c/curl_easy_setopt.html\n\t/* init some options of curl */\n\tcode = curl_easy_setopt( curl, CURLOPT_ERRORBUFFER, curl_err );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set error buffer\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_NOPROGRESS, 0 );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set NoProgress\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_NOSIGNAL, 1 );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set libcurl nosignal mode\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_FOLLOWLOCATION, 1 );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set FollowLocation\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_MAXREDIRS, 2 );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set Max Redirection\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_WRITEFUNCTION, Write );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set writer callback function\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_PROGRESSFUNCTION, Progress );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set progress callback function\\n\" );\n\t\treturn 0;\n\t}\n\n\tstrlcpy (useragent, \"Linux GL vitaQuake\", sizeof(useragent));\n\n\tcode = curl_easy_setopt( curl, CURLOPT_USERAGENT, useragent );\n\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set UserAgent\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_FAILONERROR, 1 );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set fail on error\\n\" );\n\t\treturn 0;\n\t}\n\n\treturn 1;\n}\n\nint Web_Get( const char *url, const char *referer, const char *name, int resume, int max_downloading_time, int timeout, int ( *_progress )(double) )\n{\n\tCURLcode code;\n\tFILE *f;\n\tunsigned int fsize;\n\n\t// init/reinit curl\n\tWeb_Init();\n\n\tcode = curl_easy_setopt( curl, CURLOPT_URL, url );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set url\\n\" );\n\t\treturn 0;\n\t}\n\n\tif( referer )\n\t{\n\t\tcode = curl_easy_setopt( curl, CURLOPT_REFERER, referer );\n\t\tif( code != CURLE_OK )\n\t\t{\n\t\t\tCon_Printf( \"Failed to set Referer\\n\" );\n\t\t\treturn 0;\n\t\t}\n\t}\n\n\t// connection timeout\n\tcode = curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, timeout );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set libcurl connection timeout\\n\" );\n\t\treturn 0;\n\t}\n\n\tcode = curl_easy_setopt( curl, CURLOPT_TIMEOUT, max_downloading_time );\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set libcurl global timeout\\n\" );\n\t\treturn 0;\n\t}\n\n\tif( resume == 1 )\n\t{\n\t\t// test if file exist\n\t\tif( ( f = fopen( name, \"r\" ) ) == NULL )\n\t\t{\n\t\t\t// file does not exist\n\t\t\tgoto new_file;\n\t\t}\n\t\t// the file exist\n\t\t// get the size\n\t\tfsize = fseek( f, 0, SEEK_END );\n\t\tfclose( f );\n\n\t\tcode = curl_easy_setopt( curl, CURLOPT_RESUME_FROM, fsize );\n\t\tif( code != CURLE_OK )\n\t\t{\n\t\t\tCon_Printf( \"Failed to set file resume from length\\n\" );\n\t\t\treturn 0;\n\t\t}\n\n\t\t// file exist all good\n\t}\n\telse\n\t{\n\t\t// we will append to the file so if it already exist we will have twice the data\n\t\t// so delete the file if it exist\n\t\tremove( name );\n\t}\n\nnew_file:\n\n\tcode = curl_easy_setopt( curl, CURLOPT_FILE, name );\n\t//code=curl_easy_setopt(curl, CURLOPT_FILE, &f);\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to set writer data\\n\" );\n\t\treturn 0;\n\t}\n\n\t// set callback\n\tprogress = _progress;\n\tcode = curl_easy_perform( curl );\n\n\tif (progress != NULL)\n\t\tCon_Printf( \"Downloading %s from %s\\n\", name, url );\n\n\tif( code != CURLE_OK )\n\t{\n\t\tCon_Printf( \"Failed to download %s from %s\\n\", name, url );\n\t\tCon_Printf( \"Error: %s\\n\", curl_err );\n\n\t\tWeb_Cleanup();\n\t\treturn 0;\n\t}\n\n\tWeb_Cleanup();\n\treturn 1;\n}\n"
  },
  {
    "path": "source/webdownload.h",
    "content": "/*\n   Copyright (C) 2006 Pekka Lampila (\"Medar\"), Damien Deville (\"Pb\")\n   and German Garcia Fernandez (\"Jal\") for Chasseur de bots association.\n\n\n   This program is free software; you can redistribute it and/or\n   modify it under the terms of the GNU General Public License\n   as published by the Free Software Foundation; either version 2\n   of the License, or (at your option) any later version.\n\n   This program is distributed in the hope that it will be useful,\n   but WITHOUT ANY WARRANTY; without even the implied warranty of\n   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n   See the GNU General Public License for more details.\n\n   You should have received a copy of the GNU General Public License\n   along with this program; if not, write to the Free Software\n   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n */\n\n#ifndef __WEBDOWNLOAD__H__\n#define __WEBDOWNLOAD__H__\n\nint Web_Get( const char *url, const char *referer, const char *name, int resume, int max_downloading_time, int timeout, int ( *_progress )(double) );\n\n#endif\n"
  },
  {
    "path": "source/world.c",
    "content": "/*\n* World query functions\n*\n* Copyright (C) 1996-1997 Id Software, Inc.\n*\n* This program is free software; you can redistribute it and/or\n* modify it under the terms of the GNU General Public License\n* as published by the Free Software Foundation; either version 2\n* of the License, or (at your option) any later version.\n*\n* This program is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n* General Public License for more details.\n*/\n\n#include \"quakedef.h\"\n\n/*\nentities never clip against themselves, or their owner\nline of sight checks trace->crosscontent, but bullets don't\n*/\n\ntypedef struct\n{\n\tvec3_t\t\tboxmins, boxmaxs;// enclose the test object along entire move\n\tfloat\t\t*mins, *maxs;\t// size of the moving object\n\tvec3_t\t\tmins2, maxs2;\t// size when clipping against mosnters\n\tfloat\t\t*start, *end;\n\ttrace_t\t\ttrace;\n\tint\t\t\ttype;\n\tedict_t\t\t*passedict;\n} moveclip_t;\n\nint SV_HullPointContents(hull_t *hull, int num, vec3_t p);\n\n/*\n===============================================================================\nHULL BOXES\n===============================================================================\n*/\n\n\nstatic\thull_t\t\tbox_hull;\nstatic\tmclipnode_t\tbox_clipnodes[6];\nstatic\tmplane_t\tbox_planes[6];\n\n/*\n===================\nSV_InitBoxHull\nSet up the planes and clipnodes so that the six floats of a bounding box\ncan just be stored out and get a proper hull_t structure.\n===================\n*/\nvoid SV_InitBoxHull(void)\n{\n\tint\ti, side;\n\n\tbox_hull.clipnodes = box_clipnodes;\n\tbox_hull.planes = box_planes;\n\tbox_hull.firstclipnode = 0;\n\tbox_hull.lastclipnode = 5;\n\n\tfor (i = 0; i<6; i++)\n\t{\n\t\tbox_clipnodes[i].planenum = i;\n\n\t\tside = i & 1;\n\n\t\tbox_clipnodes[i].children[side] = CONTENTS_EMPTY;\n\t\tif (i != 5)\n\t\t\tbox_clipnodes[i].children[side ^ 1] = i + 1;\n\t\telse\n\t\t\tbox_clipnodes[i].children[side ^ 1] = CONTENTS_SOLID;\n\n\t\tbox_planes[i].type = i >> 1;\n\t\tbox_planes[i].normal[i >> 1] = 1;\n\t}\n}\n\n/*\n===================\nSV_HullForBox\nTo keep everything totally uniform, bounding boxes are turned into small\nBSP trees instead of being compared directly.\n===================\n*/\nhull_t\t*SV_HullForBox(vec3_t mins, vec3_t maxs)\n{\n\tbox_planes[0].dist = maxs[0];\n\tbox_planes[1].dist = mins[0];\n\tbox_planes[2].dist = maxs[1];\n\tbox_planes[3].dist = mins[1];\n\tbox_planes[4].dist = maxs[2];\n\tbox_planes[5].dist = mins[2];\n\n\treturn &box_hull;\n}\n\n/*\n================\nSV_HullForEntity\nReturns a hull that can be used for testing or clipping an object of mins/maxs size.\nOffset is filled in to contain the adjustment that must be added to the\ntesting object's origin to get a point to use with the returned hull.\n================\n*/\nhull_t *SV_HullForEntity(edict_t *ent, vec3_t mins, vec3_t maxs, vec3_t offset)\n{\n\tmodel_t\t\t*model;\n\tvec3_t\t\tsize, hullmins, hullmaxs;\n\thull_t\t\t*hull;\n\n\t// decide which clipping hull to use, based on the size\n\tif (ent->v.solid == SOLID_BSP)\n\t{ // explicit hulls in the BSP model\n\t\tif (ent->v.movetype != MOVETYPE_PUSH)\n\t\t\tSys_Error(\"SOLID_BSP without MOVETYPE_PUSH\");\n\n\t\tmodel = sv.models[(int)ent->v.modelindex];\n\n\t\tif (!model || model->type != mod_brush)\n\t\t\tSys_Error(\"MOVETYPE_PUSH with a non-bsp model\");\n\n\t\tVectorSubtract(maxs, mins, size);\n\t\tif (model->bspversion == HL_BSPVERSION) {\n\t\t\tif (size[0] < 3) {\n\t\t\t\thull = &model->hulls[0]; // 0x0x0\n\t\t\t} else if (size[0] <= 32) {\n\t\t\t\tif (size[2] < 54) // pick the nearest of 36 or 72\n\t\t\t\t\thull = &model->hulls[3]; // 32x32x36\n\t\t\t\telse\n\t\t\t\t\thull = &model->hulls[1]; // 32x32x72\n\t\t\t} else {\n\t\t\t\thull = &model->hulls[2]; // 64x64x64\n\t\t\t}\n\t\t} else {\n\t\t\tif (size[0] < 3)\n\t\t\t\thull = &model->hulls[0];\n\t\t\telse if (size[0] <= 32)\n\t\t\t\thull = &model->hulls[1];\n\t\t\telse\n\t\t\t\thull = &model->hulls[2];\n\t\t}\n\t\t// calculate an offset value to center the origin\n\t\tVectorSubtract(hull->clip_mins, mins, offset);\n\t\tVectorAdd(offset, ent->v.origin, offset);\n\t}\n\telse\n\t{\t// create a temp hull from bounding box sizes\n\t\tVectorSubtract(ent->v.mins, maxs, hullmins);\n\t\tVectorSubtract(ent->v.maxs, mins, hullmaxs);\n\t\thull = SV_HullForBox(hullmins, hullmaxs);\n\n\t\tVectorCopy(ent->v.origin, offset);\n\t}\n\n\treturn hull;\n}\n\n/*\n===============================================================================\nENTITY AREA CHECKING\n===============================================================================\n*/\n\n\n//============================================================================\n\nstatic\tareanode_t\tsv_areanodes[AREA_NODES];\nstatic\tint\t\t\tsv_numareanodes;\n\nareanode_t *SV_CreateAreaNode(int depth, vec3_t mins, vec3_t maxs)\n{\n\tareanode_t\t*anode;\n\tvec3_t\t\tsize, mins1, maxs1, mins2, maxs2;\n\n\tanode = &sv_areanodes[sv_numareanodes];\n\tsv_numareanodes++;\n\n\tClearLink(&anode->trigger_edicts);\n\tClearLink(&anode->solid_edicts);\n\n\tif (depth == AREA_DEPTH)\n\t{\n\t\tanode->axis = -1;\n\t\tanode->children[0] = anode->children[1] = NULL;\n\t\treturn anode;\n\t}\n\n\tVectorSubtract(maxs, mins, size);\n\tanode->axis = (size[0] > size[1]) ? 0 : 1;\n\n\tanode->dist = 0.5 * (maxs[anode->axis] + mins[anode->axis]);\n\tVectorCopy(mins, mins1);\n\tVectorCopy(mins, mins2);\n\tVectorCopy(maxs, maxs1);\n\tVectorCopy(maxs, maxs2);\n\n\tmaxs1[anode->axis] = mins2[anode->axis] = anode->dist;\n\n\tanode->children[0] = SV_CreateAreaNode(depth + 1, mins2, maxs2);\n\tanode->children[1] = SV_CreateAreaNode(depth + 1, mins1, maxs1);\n\n\treturn anode;\n}\n\nvoid SV_ClearWorld(void)\n{\n\tSV_InitBoxHull();\n\n\tmemset(sv_areanodes, 0, sizeof(sv_areanodes));\n\tsv_numareanodes = 0;\n\tSV_CreateAreaNode(0, sv.worldmodel->mins, sv.worldmodel->maxs);\n}\n\nvoid SV_UnlinkEdict(edict_t *ent)\n{\n\tif (!ent->area.prev)\n\t\treturn;\t\t// not linked in anywhere\n\n\tRemoveLink(&ent->area);\n\tent->area.prev = ent->area.next = NULL;\n}\n\nvoid SV_TouchLinks(edict_t *ent, areanode_t *node)\n{\n\tlink_t\t\t*l, *next;\n\tedict_t\t\t*touch;\n\tint\t\t\told_self, old_other;\n\n\t// touch linked edicts\n\tfor (l = node->trigger_edicts.next; l != &node->trigger_edicts; l = next)\n\t{\n\t\t//johnfitz -- fixes a crash when a touch function deletes an entity which comes later in the list\n\t\tif (!l)\n\t\t{\n\t\t\tCon_Printf(\"SV_TouchLinks: null link\\n\");\n\t\t\tbreak;\n\t\t}\n\t\t//johnfitz\n\n\t\tnext = l->next;\n\t\ttouch = EDICT_FROM_AREA(l);\n\t\tif (touch == ent)\n\t\t\tcontinue;\n\t\tif (!touch->v.touch || touch->v.solid != SOLID_TRIGGER)\n\t\t\tcontinue;\n\t\tif (ent->v.absmin[0] > touch->v.absmax[0]\n\t\t\t|| ent->v.absmin[1] > touch->v.absmax[1]\n\t\t\t|| ent->v.absmin[2] > touch->v.absmax[2]\n\t\t\t|| ent->v.absmax[0] < touch->v.absmin[0]\n\t\t\t|| ent->v.absmax[1] < touch->v.absmin[1]\n\t\t\t|| ent->v.absmax[2] < touch->v.absmin[2])\n\t\t\tcontinue;\n\n\t\told_self = pr_global_struct->self;\n\t\told_other = pr_global_struct->other;\n\n\t\tpr_global_struct->self = EDICT_TO_PROG(touch);\n\t\tpr_global_struct->other = EDICT_TO_PROG(ent);\n\t\tpr_global_struct->time = sv.time;\n\t\tPR_ExecuteProgram(touch->v.touch);\n\n\t\tpr_global_struct->self = old_self;\n\t\tpr_global_struct->other = old_other;\n\t}\n\n\t// recurse down both sides\n\tif (node->axis == -1)\n\t\treturn;\n\n\tif (ent->v.absmax[node->axis] > node->dist)\n\t\tSV_TouchLinks(ent, node->children[0]);\n\tif (ent->v.absmin[node->axis] < node->dist)\n\t\tSV_TouchLinks(ent, node->children[1]);\n}\n\n/*\n===============\nSV_FindTouchedLeafs\n===============\n*/\nvoid SV_FindTouchedLeafs(edict_t *ent, mnode_t *node)\n{\n\tmplane_t\t*splitplane;\n\tmleaf_t\t\t*leaf;\n\tint\t\tsides, leafnum;\n\n\tif (node->contents == CONTENTS_SOLID)\n\t\treturn;\n\n\t// add an efrag if the node is a leaf\n\n\tif (node->contents < 0)\n\t{\n\t\tif (ent->num_leafs == MAX_ENT_LEAFS)\n\t\t\treturn;\n\n\t\tleaf = (mleaf_t *)node;\n\t\tleafnum = leaf - sv.worldmodel->leafs - 1;\n\n\t\tent->leafnums[ent->num_leafs] = leafnum;\n\t\tent->num_leafs++;\n\t\treturn;\n\t}\n\n\t// NODE_MIXED\n\n\tsplitplane = node->plane;\n\tsides = BOX_ON_PLANE_SIDE(ent->v.absmin, ent->v.absmax, splitplane);\n\n\t// recurse down the contacted sides\n\tif (sides & 1)\n\t\tSV_FindTouchedLeafs(ent, node->children[0]);\n\n\tif (sides & 2)\n\t\tSV_FindTouchedLeafs(ent, node->children[1]);\n}\n\nvoid SV_LinkEdict(edict_t *ent, bool touch_triggers)\n{\n\tareanode_t\t*node;\n\n\tif (ent->area.prev)\n\t\tSV_UnlinkEdict(ent);\t// unlink from old position\n\n\tif (ent == sv.edicts)\n\t\treturn;\t\t// don't add the world\n\n\tif (ent->free)\n\t\treturn;\n\n\t// set the abs box\n\t// ROTATE START\n\tif (ent->v.solid == SOLID_BSP &&\n\t\t(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) && ent != sv.edicts)\n\t{   \t// expand for rotation\n\t\tfloat      max, v;\n\t\tint         i;\n\n\t\tmax = DotProduct(ent->v.mins, ent->v.mins);\n\t\tv = DotProduct(ent->v.maxs, ent->v.maxs);\n\n\t\tif (max < v)\n\t\t\tmax = v;\n\n\t\tmax = sqrt(max);\n\n\t\tfor (i = 0; i<3; i++)\n\t\t{\n\t\t\tent->v.absmin[i] = ent->v.origin[i] - max;\n\t\t\tent->v.absmax[i] = ent->v.origin[i] + max;\n\t\t}\n\t}\n\telse\n\t\t// ROTATE END\n\t{\n\t\tVectorAdd(ent->v.origin, ent->v.mins, ent->v.absmin);\n\t\tVectorAdd(ent->v.origin, ent->v.maxs, ent->v.absmax);\n\t}\n\n\t// to make items easier to pick up and allow them to be grabbed off\n\t// of shelves, the abs sizes are expanded\n\tif ((int)ent->v.flags & FL_ITEM)\n\t{\n\t\tent->v.absmin[0] -= 15;\n\t\tent->v.absmin[1] -= 15;\n\t\tent->v.absmax[0] += 15;\n\t\tent->v.absmax[1] += 15;\n\t}\n\telse\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\t\tent->v.absmin[0] -= 1;\n\t\tent->v.absmin[1] -= 1;\n\t\tent->v.absmin[2] -= 1;\n\t\tent->v.absmax[0] += 1;\n\t\tent->v.absmax[1] += 1;\n\t\tent->v.absmax[2] += 1;\n\t}\n\n\t// link to PVS leafs\n\tent->num_leafs = 0;\n\tif (ent->v.modelindex)\n\t\tSV_FindTouchedLeafs(ent, sv.worldmodel->nodes);\n\n\tif (ent->v.solid == SOLID_NOT)\n\t\treturn;\n\n\t// find the first node that the ent's box crosses\n\tnode = sv_areanodes;\n\twhile (1)\n\t{\n\t\tif (node->axis == -1)\n\t\t\tbreak;\n\n\t\tif (ent->v.absmin[node->axis] > node->dist)\n\t\t\tnode = node->children[0];\n\t\telse if (ent->v.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\n\t// link it in\n\tif (ent->v.solid == SOLID_TRIGGER)\n\t\tInsertLinkBefore(&ent->area, &node->trigger_edicts);\n\telse\n\t\tInsertLinkBefore(&ent->area, &node->solid_edicts);\n\n\t// if touch_triggers, touch all entities at this node and decend for more\n\tif (touch_triggers)\n\t\tSV_TouchLinks(ent, sv_areanodes);\n}\n\n\n/*\n===============================================================================\nPOINT TESTING IN HULLS\n===============================================================================\n*/\n\n\n/*\n==================\nSV_HullPointContents\n==================\n*/\nint SV_HullPointContents(hull_t *hull, int num, vec3_t p)\n{\n\tfloat\t\td;\n\tmclipnode_t\t*node;\n\tmplane_t\t*plane;\n\n\twhile (num >= 0)\n\t{\n\t\tif (num < hull->firstclipnode || num > hull->lastclipnode)\n\t\t\tSys_Error(\"SV_HullPointContents: bad node number\");\n\n\t\tnode = hull->clipnodes + num;\n\t\tplane = hull->planes + node->planenum;\n\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\n\t\tnum = (d < 0) ? node->children[1] : node->children[0];\n\t}\n\n\treturn num;\n}\n\n\n/*\n==================\nSV_PointContents\n==================\n*/\nint SV_PointContents(vec3_t p)\n{\n\tint\t\tcont;\n\n\tcont = SV_HullPointContents(&sv.worldmodel->hulls[0], 0, p);\n\tif (cont <= CONTENTS_CURRENT_0 && cont >= CONTENTS_CURRENT_DOWN)\n\t\tcont = CONTENTS_WATER;\n\treturn cont;\n}\n\nint SV_TruePointContents(vec3_t p)\n{\n\treturn SV_HullPointContents(&sv.worldmodel->hulls[0], 0, p);\n}\n\n//===========================================================================\n\n/*\n============\nSV_TestEntityPosition\nThis could be a lot more efficient...\n============\n*/\nedict_t\t*SV_TestEntityPosition(edict_t *ent)\n{\n\ttrace_t\ttrace;\n\n\ttrace = SV_Move(ent->v.origin, ent->v.mins, ent->v.maxs, ent->v.origin, 0, ent);\n\n\tif (trace.startsolid)\n\t\treturn sv.edicts;\n\n\treturn NULL;\n}\n\n/*\n===============================================================================\nLINE TESTING IN HULLS\n===============================================================================\n*/\n\n// 1/32 epsilon to keep floating point happy\n#define\tDIST_EPSILON\t(0.03125)\n\n/*\n==================\nSV_RecursiveHullCheck\n==================\n*/\nbool SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace)\n{\n\tmclipnode_t\t*node;\n\tmplane_t\t*plane;\n\tfloat\t\tt1, t2, frac, midf;\n\tint\t\t\ti, side;\n\tvec3_t\t\tmid;\n\n\t// check for empty\n\tif (num < 0)\n\t{\n\t\tif (num != CONTENTS_SOLID)\n\t\t{\n\t\t\ttrace->allsolid = false;\n\t\t\tif (num == CONTENTS_EMPTY)\n\t\t\t\ttrace->inopen = true;\n\t\t\telse\n\t\t\t\ttrace->inwater = true;\n\t\t}\n\t\telse\n\t\t{\n\t\t\ttrace->startsolid = true;\n\t\t}\n\t\treturn true;\t\t// empty\n\t}\n\n\tif (num < hull->firstclipnode || num > hull->lastclipnode)\n\t\tSys_Error(\"SV_RecursiveHullCheck: bad node number\");\n\n\t// find the point distances\n\tnode = hull->clipnodes + num;\n\tplane = hull->planes + node->planenum;\n\n\tif (plane->type < 3)\n\t{\n\t\tt1 = p1[plane->type] - plane->dist;\n\t\tt2 = p2[plane->type] - plane->dist;\n\t}\n\telse\n\t{\n\t\tt1 = DotProduct(plane->normal, p1) - plane->dist;\n\t\tt2 = DotProduct(plane->normal, p2) - plane->dist;\n\t}\n\n\tif (t1 >= 0 && t2 >= 0)\n\t\treturn SV_RecursiveHullCheck(hull, node->children[0], p1f, p2f, p1, p2, trace);\n\tif (t1 < 0 && t2 < 0)\n\t\treturn SV_RecursiveHullCheck(hull, node->children[1], p1f, p2f, p1, p2, trace);\n\n\t// put the crosspoint DIST_EPSILON pixels on the near side\n\tif (t1 < 0)\n\t\tfrac = (t1 + DIST_EPSILON) / (t1 - t2);\n\telse\n\t\tfrac = (t1 - DIST_EPSILON) / (t1 - t2);\n\tif (frac < 0)\n\t\tfrac = 0;\n\tif (frac > 1)\n\t\tfrac = 1;\n\n\tmidf = p1f + (p2f - p1f)*frac;\n\tfor (i = 0; i<3; i++)\n\t\tmid[i] = p1[i] + frac*(p2[i] - p1[i]);\n\n\tside = (t1 < 0);\n\n\t// move up to the node\n\tif (!SV_RecursiveHullCheck(hull, node->children[side], p1f, midf, p1, mid, trace))\n\t\treturn false;\n\n#ifdef PARANOID\n\tif (SV_HullPointContents(sv_hullmodel, mid, node->children[side]) == CONTENTS_SOLID)\n\t{\n\t\tCon_Printf(\"mid PointInHullSolid\\n\");\n\t\treturn false;\n\t}\n#endif\n\n\tif (SV_HullPointContents(hull, node->children[side ^ 1], mid) != CONTENTS_SOLID) // go past the node\n\t\treturn SV_RecursiveHullCheck(hull, node->children[side ^ 1], midf, p2f, mid, p2, trace);\n\n\tif (trace->allsolid)\n\t\treturn false;\t\t// never got out of the solid area\n\n\t\t\t\t\t\t\t// the other side of the node is solid, this is the impact point\n\tif (!side)\n\t{\n\t\tVectorCopy(plane->normal, trace->plane.normal);\n\t\ttrace->plane.dist = plane->dist;\n\t}\n\telse\n\t{\n\t\tVectorSubtract(vec3_origin, plane->normal, trace->plane.normal);\n\t\ttrace->plane.dist = -plane->dist;\n\t}\n\n\twhile (SV_HullPointContents(hull, hull->firstclipnode, mid) == CONTENTS_SOLID)\n\t{ // shouldn't really happen, but does occasionally\n\t\tfrac -= 0.1;\n\t\tif (frac < 0)\n\t\t{\n\t\t\ttrace->fraction = midf;\n\t\t\tVectorCopy(mid, trace->endpos);\n\t\t\t//Con_DPrintf (\"backup past 0\\n\"); // JPG - removed this (it was spamming big time)\n\t\t\treturn false;\n\t\t}\n\t\tmidf = p1f + (p2f - p1f)*frac;\n\t\tfor (i = 0; i<3; i++)\n\t\t\tmid[i] = p1[i] + frac*(p2[i] - p1[i]);\n\t}\n\n\ttrace->fraction = midf;\n\tVectorCopy(mid, trace->endpos);\n\n\treturn false;\n}\n\n//Handles selection or creation of a clipping hull, and offseting (and eventually rotation) of the end points\ntrace_t SV_ClipMoveToEntity(edict_t *ent, vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end)\n{\n\ttrace_t\t\ttrace;\n\tvec3_t\t\toffset, start_l, end_l;\n\thull_t\t\t*hull;\n\n\t// fill in a default trace\n\tmemset(&trace, 0, sizeof(trace_t));\n\ttrace.fraction = 1;\n\ttrace.allsolid = true;\n\tVectorCopy(end, trace.endpos);\n\n\t// get the clipping hull\n\thull = SV_HullForEntity(ent, mins, maxs, offset);\n\n\tVectorSubtract(start, offset, start_l);\n\tVectorSubtract(end, offset, end_l);\n\n\t// ROTATE START\n\t// rotate start and end into the models frame of reference\n\tif (ent->v.solid == SOLID_BSP &&\n\t\t(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) && ent != sv.edicts)\n\t{\n\t\t//\t\tvec3_t   a;\n\t\tvec3_t   forward, right, up;\n\t\tvec3_t   temp;\n\n\t\tAngleVectors(ent->v.angles, forward, right, up);\n\n\t\tVectorCopy(start_l, temp);\n\t\tstart_l[0] = DotProduct(temp, forward);\n\t\tstart_l[1] = -DotProduct(temp, right);\n\t\tstart_l[2] = DotProduct(temp, up);\n\n\t\tVectorCopy(end_l, temp);\n\t\tend_l[0] = DotProduct(temp, forward);\n\t\tend_l[1] = -DotProduct(temp, right);\n\t\tend_l[2] = DotProduct(temp, up);\n\t}\n\t// ROTATE END\n\n\t// trace a line through the apropriate clipping hull\n\tSV_RecursiveHullCheck(hull, hull->firstclipnode, 0, 1, start_l, end_l, &trace);\n\n\n\t// ROTATE START\n\t// rotate endpos back to world frame of reference\n\tif (ent->v.solid == SOLID_BSP &&\n\t\t(ent->v.angles[0] || ent->v.angles[1] || ent->v.angles[2]) && ent != sv.edicts)\n\t{\n\t\tvec3_t   a;\n\t\tvec3_t   forward, right, up;\n\t\tvec3_t   temp;\n\n\t\tif (trace.fraction != 1)\n\t\t{\n\t\t\tVectorSubtract(vec3_origin, ent->v.angles, a);\n\t\t\tAngleVectors(a, forward, right, up);\n\n\t\t\tVectorCopy(trace.endpos, temp);\n\t\t\ttrace.endpos[0] = DotProduct(temp, forward);\n\t\t\ttrace.endpos[1] = -DotProduct(temp, right);\n\t\t\ttrace.endpos[2] = DotProduct(temp, up);\n\n\t\t\tVectorCopy(trace.plane.normal, temp);\n\t\t\ttrace.plane.normal[0] = DotProduct(temp, forward);\n\t\t\ttrace.plane.normal[1] = -DotProduct(temp, right);\n\t\t\ttrace.plane.normal[2] = DotProduct(temp, up);\n\t\t}\n\n\t\t// fix trace up by the offset\n\t\tVectorAdd(trace.endpos, offset, trace.endpos);\n\n\t}\n\t// other cases where not\n\t// Solid BSP\n\telse\n\t{\n\t\tif (trace.fraction != 1)\n\t\t\tVectorAdd(trace.endpos, offset, trace.endpos);\n\n\t}\n\n\t// ROTATE END\n\n\n\t// did we clip the move?\n\tif (trace.fraction < 1 || trace.startsolid)\n\t\ttrace.ent = ent;\n\n\treturn trace;\n}\n\n//===========================================================================\n\n/*\n====================\nSV_ClipToLinks\nMins and maxs enclose the entire area swept by the move\n====================\n*/\nvoid SV_ClipToLinks(areanode_t *node, moveclip_t *clip)\n{\n\tlink_t\t\t*l, *next;\n\tedict_t\t\t*touch;\n\ttrace_t\t\ttrace;\n\n\t// touch linked edicts\n\tfor (l = node->solid_edicts.next; l != &node->solid_edicts; l = next)\n\t{\n\t\tnext = l->next;\n\t\ttouch = EDICT_FROM_AREA(l);\n\t\tif (touch->v.solid == SOLID_NOT)\n\t\t\tcontinue;\n\t\tif (touch == clip->passedict)\n\t\t\tcontinue;\n\t\tif (touch->v.solid == SOLID_TRIGGER)\n\t\t\tSys_Error(\"Trigger in clipping list\");\n\n\t\tif (clip->type == MOVE_NOMONSTERS && touch->v.solid != SOLID_BSP)\n\t\t\tcontinue;\n\n\t\tif (clip->boxmins[0] > touch->v.absmax[0]\n\t\t\t|| clip->boxmins[1] > touch->v.absmax[1]\n\t\t\t|| clip->boxmins[2] > touch->v.absmax[2]\n\t\t\t|| clip->boxmaxs[0] < touch->v.absmin[0]\n\t\t\t|| clip->boxmaxs[1] < touch->v.absmin[1]\n\t\t\t|| clip->boxmaxs[2] < touch->v.absmin[2])\n\t\t\tcontinue;\n\n\t\tif (clip->passedict && clip->passedict->v.size[0] && !touch->v.size[0])\n\t\t\tcontinue;\t// points never interact\n\n\t\t\t\t\t\t// might intersect, so do an exact clip\n\t\tif (clip->trace.allsolid)\n\t\t\treturn;\n\t\tif (clip->passedict)\n\t\t{\n\t\t\tif (PROG_TO_EDICT(touch->v.owner) == clip->passedict)\n\t\t\t\tcontinue;\t// don't clip against own missiles\n\t\t\tif (PROG_TO_EDICT(clip->passedict->v.owner) == touch)\n\t\t\t\tcontinue;\t// don't clip against owner\n\t\t}\n\n\t\tif ((int)touch->v.flags & FL_MONSTER)\n\t\t\ttrace = SV_ClipMoveToEntity(touch, clip->start, clip->mins2, clip->maxs2, clip->end);\n\t\telse\n\t\t\ttrace = SV_ClipMoveToEntity(touch, clip->start, clip->mins, clip->maxs, clip->end);\n\t\tif (trace.allsolid || trace.startsolid || trace.fraction < clip->trace.fraction)\n\t\t{\n\t\t\ttrace.ent = touch;\n\t\t\tif (clip->trace.startsolid)\n\t\t\t{\n\t\t\t\tclip->trace = trace;\n\t\t\t\tclip->trace.startsolid = true;\n\t\t\t}\n\t\t\telse\n\t\t\t{\n\t\t\t\tclip->trace = trace;\n\t\t\t}\n\t\t}\n\t\telse if (trace.startsolid)\n\t\t{\n\t\t\tclip->trace.startsolid = true;\n\t\t}\n\t}\n\n\t// recurse down both sides\n\tif (node->axis == -1)\n\t\treturn;\n\n\tif (clip->boxmaxs[node->axis] > node->dist)\n\t\tSV_ClipToLinks(node->children[0], clip);\n\tif (clip->boxmins[node->axis] < node->dist)\n\t\tSV_ClipToLinks(node->children[1], clip);\n}\n\nvoid SV_MoveBounds(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, vec3_t boxmins, vec3_t boxmaxs)\n{\n\tint\t\ti;\n\n\tfor (i = 0; i<3; i++)\n\t{\n\t\tif (end[i] > start[i])\n\t\t{\n\t\t\tboxmins[i] = start[i] + mins[i] - 1;\n\t\t\tboxmaxs[i] = end[i] + maxs[i] + 1;\n\t\t}\n\t\telse\n\t\t{\n\t\t\tboxmins[i] = end[i] + mins[i] - 1;\n\t\t\tboxmaxs[i] = start[i] + maxs[i] + 1;\n\t\t}\n\t}\n}\n\ntrace_t SV_Move(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict)\n{\n\tmoveclip_t\tclip;\n\tint\t\t\ti;\n\n\tmemset(&clip, 0, sizeof(moveclip_t));\n\n\t// clip to world\n\tclip.trace = SV_ClipMoveToEntity(sv.edicts, start, mins, maxs, end);\n\n\tclip.start = start;\n\tclip.end = end;\n\tclip.mins = mins;\n\tclip.maxs = maxs;\n\tclip.type = type;\n\tclip.passedict = passedict;\n\n\tif (type == MOVE_MISSILE)\n\t{\n\t\tfor (i = 0; i<3; i++)\n\t\t{\n\t\t\tclip.mins2[i] = -15;\n\t\t\tclip.maxs2[i] = 15;\n\t\t}\n\t}\n\telse\n\t{\n\t\tVectorCopy(mins, clip.mins2);\n\t\tVectorCopy(maxs, clip.maxs2);\n\t}\n\n\t// create the bounding box of the entire move\n\tSV_MoveBounds(start, clip.mins2, clip.maxs2, end, clip.boxmins, clip.boxmaxs);\n\n\t// clip to entities\n\tSV_ClipToLinks(sv_areanodes, &clip);\n\n\treturn clip.trace;\n}"
  },
  {
    "path": "source/world.h",
    "content": "/*\n* Copyright (C) 1996-1997 Id Software, Inc.\n*\n* This program is free software; you can redistribute it and/or\n* modify it under the terms of the GNU General Public License\n* as published by the Free Software Foundation; either version 2\n* of the License, or (at your option) any later version.\n*\n* This program is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n* General Public License for more details.\n*/\n\n#define\tMOVE_NORMAL\t\t0\n#define\tMOVE_NOMONSTERS\t1\n#define\tMOVE_MISSILE\t2\n\ntypedef struct areanode_s\n{\n\tint\t\taxis;\t\t// -1 = leaf node\n\tfloat\tdist;\n\tstruct areanode_s\t*children[2];\n\tlink_t\ttrigger_edicts;\n\tlink_t\tsolid_edicts;\n} areanode_t;\n\ntypedef struct\n{\n\tvec3_t\tnormal;\n\tfloat\tdist;\n} plane_t;\n\ntypedef struct\n{\n\tbool\tallsolid;\t// if true, plane is not valid\n\tbool\tstartsolid;\t// if true, the initial point was in a solid area\n\tbool\tinopen, inwater;\n\tfloat\tfraction;\t\t// time completed, 1.0 = didn't hit anything\n\tvec3_t\tendpos;\t\t\t// final position\n\tplane_t\tplane;\t\t\t// surface normal at impact\n\tedict_t\t*ent;\t\t\t// entity the surface is on\n} trace_t;\n\n#define\tAREA_DEPTH\t4\n#define\tAREA_NODES\t32\n\nvoid SV_ClearWorld(void);\n// called after the world model has been loaded, before linking any entities\n\nvoid SV_UnlinkEdict(edict_t *ent);\n// call before removing an entity, and before trying to move one,\n// so it doesn't clip against itself\n// flags ent->v.modified\n\nvoid SV_LinkEdict(edict_t *ent, bool touch_triggers);\n// Needs to be called any time an entity changes origin, mins, maxs, or solid\n// flags ent->v.modified\n// sets ent->v.absmin and ent->v.absmax\n// if touchtriggers, calls prog functions for the intersected triggers\n\nint SV_TruePointContents(vec3_t p);\nint SV_PointContents(vec3_t p);\n\n\n// returns the CONTENTS_* value from the world at the given point.\n// does not check any entities at all\n// the non-true version remaps the water current contents to content_water\n\nbool SV_RecursiveHullCheck(hull_t *hull, int num, float p1f, float p2f, vec3_t p1, vec3_t p2, trace_t *trace);\nedict_t\t*SV_TestEntityPosition(edict_t *ent);\n\ntrace_t SV_Move(vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, int type, edict_t *passedict);\n// mins and maxs are relative\n\n// if the entire move stays in a solid volume, trace.allsolid will be set\n\n// if the starting point is in a solid, it will be allowed to move out\n// to an open area\n\n// nomonsters is used for line of sight or edge testing, where mosnters\n// shouldn't be considered solid objects\n\n// passedict is explicitly excluded from clipping checks (normally NULL)\n"
  },
  {
    "path": "source/zone.c",
    "content": "/*\n* Copyright (C) 1996-1997 Id Software, Inc.\n*\n* This program is free software; you can redistribute it and/or\n* modify it under the terms of the GNU General Public License\n* as published by the Free Software Foundation; either version 2\n* of the License, or (at your option) any later version.\n*\n* This program is distributed in the hope that it will be useful,\n* but WITHOUT ANY WARRANTY; without even the implied warranty of\n* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\n* General Public License for more details.\n*/\n\n#include \"quakedef.h\"\n\n#define\tZONE_DEFAULT_SIZE\t0x100000\t// 1Mb\n#define\tDYNAMIC_SIZE\t256*1024 //johnfitz: was 48k\n\n#define\tZONEID\t0x1d4a11\n#define MINFRAGMENT\t64\n\ntypedef struct memblock_s {\n\tint size;           // including the header and possibly tiny fragments\n\tint tag;            // a tag of 0 is a free block\n\tint id;        \t\t// should be ZONEID\n\tstruct memblock_s *next, *prev;\n\tint pad;\t\t\t// pad to 64 bit boundary\n} memblock_t;\n\ntypedef struct {\n\tint size;\t\t// total bytes malloced, including header\n\tmemblock_t blocklist;\t\t// start / end cap for linked list\n\tmemblock_t *rover;\n} memzone_t;\n\nvoid Cache_FreeLow(int new_low_hunk);\nvoid Cache_FreeHigh(int new_high_hunk);\n\n/*\n==============================================================================\n\nZONE 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\nmemzone_t *mainzone;\n\n/*\n========================\nZ_ClearZone\n========================\n*/\nvoid Z_ClearZone(memzone_t *zone, int size)\n{\n\tmemblock_t *block;\n\n\t// set the entire zone to one free block\n\n\tzone->blocklist.next = zone->blocklist.prev = block = (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\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_Free\n========================\n*/\nvoid Z_Free(void *ptr)\n{\n\tmemblock_t *block, *other;\n\n\tif (!ptr)\n\t\tSys_Error(\"Z_Free: NULL pointer\");\n\n\tblock = (memblock_t *)((byte *)ptr - sizeof(memblock_t));\n\tif (block->id != ZONEID){\n\t\tCon_DPrintf(\"Z_Free: freed a pointer without ZONEID\\n\");\n\t\treturn;\n\t}\n\tif (block->tag == 0)\n\t\tSys_Error(\"Z_Free: freed a freed pointer\");\n\n\tblock->tag = 0;\t\t// mark as free\n\n\tother = block->prev;\n\tif (!other->tag) {\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 == mainzone->rover)\n\t\t\tmainzone->rover = other;\n\t\tblock = other;\n\t}\n\n\tother = block->next;\n\tif (!other->tag) {\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 == mainzone->rover)\n\t\t\tmainzone->rover = block;\n\t}\n}\n\n/*\n========================\nZ_Malloc\n========================\n*/\nvoid *Z_Malloc(int size)\n{\n\tvoid *buf;\n\n\tZ_CheckHeap();\t// DEBUG\n\tif (!(buf = Z_TagMalloc(size, 1)))\n\t\tSys_Error(\"Z_Malloc: failed on allocation of %i bytes\", size);\n\tmemset(buf, 0, size);\n\n\treturn buf;\n}\n\nvoid *Z_TagMalloc(int size, int tag)\n{\n\tint extra;\n\tmemblock_t *start, *rover, *new, *base;\n\n\tif (!tag)\n\t\tSys_Error(\"Z_TagMalloc: tried to use a 0 tag\");\n\n\t// scan through the block list looking for the first free block\n\t// of sufficient size\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 + 7) & ~7;\t\t// align to 8-byte boundary\n\n\tbase = rover = mainzone->rover;\n\tstart = base->prev;\n\n\tdo {\n\t\tif (rover == start)\t// scaned all the way around the list\n\t\t\treturn NULL;\n\t\tif (rover->tag)\n\t\t\tbase = rover = rover->next;\n\t\telse\n\t\t\trover = rover->next;\n\t} while (base->tag || base->size < size);\n\n\t// found a block big enough\n\textra = base->size - size;\n\tif (extra > MINFRAGMENT) {\t// there will be a free fragment after the allocated block\n\t\tnew = (memblock_t *)((byte *)base + size);\n\t\tnew->size = extra;\n\t\tnew->tag = 0;\t\t\t// free block\n\t\tnew->prev = base;\n\t\tnew->id = ZONEID;\n\t\tnew->next = base->next;\n\t\tnew->next->prev = new;\n\t\tbase->next = new;\n\t\tbase->size = size;\n\t}\n\n\tbase->tag = tag;\t\t\t\t// no longer a free block\n\n\tmainzone->rover = base->next;\t// next allocation will start looking here\n\n\tbase->id = ZONEID;\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_Print\n========================\n*/\nvoid Z_Print(memzone_t *zone)\n{\n\tmemblock_t *block;\n\n\tCon_Printf(\"zone size: %i  location: %p\\n\", mainzone->size, mainzone);\n\n\tfor (block = zone->blocklist.next;; block = block->next) {\n\t\tCon_Printf(\"block:%p    size:%7i    tag:%3i\\n\", block, block->size, block->tag);\n\n\t\tif (block->next == &zone->blocklist)\n\t\t\tbreak;\t\t\t// all blocks have been hit\n\t\tif ((byte *)block + block->size != (byte *)block->next)\n\t\t\tCon_Printf(\"ERROR: block size does not touch the next block\\n\");\n\t\tif (block->next->prev != block)\n\t\t\tCon_Printf(\"ERROR: next block doesn't have proper back link\\n\");\n\t\tif (!block->tag && !block->next->tag)\n\t\t\tCon_Printf(\"ERROR: two consecutive free blocks\\n\");\n\t}\n}\n\n/*\n========================\nZ_CheckHeap\n========================\n*/\nvoid Z_CheckHeap (void)\n{\n\tmemblock_t\t*block;\n\n\tfor (block = mainzone->blocklist.next ; ; block = block->next)\n\t{\n\t\tif (block->next == &mainzone->blocklist)\n\t\t\tbreak;\t\t\t// all blocks have been hit\n\t\tif ( (byte *)block + block->size != (byte *)block->next)\n\t\t\tSys_Error (\"Z_CheckHeap: block size does not touch the next block\\n\");\n\t\tif ( block->next->prev != block)\n\t\t\tSys_Error (\"Z_CheckHeap: next block doesn't have proper back link\\n\");\n\t\tif (!block->tag && !block->next->tag)\n\t\t\tSys_Error (\"Z_CheckHeap: two consecutive free blocks\\n\");\n\t}\n}\n\n/*\n========================\nZ_Realloc\n========================\n*/\nvoid *Z_Realloc(void *ptr, int size)\n{\n\tint old_size;\n\tvoid *old_ptr;\n\tmemblock_t *block;\n\n\tif (!ptr)\n\t\treturn Z_Malloc(size);\n\n\tblock = (memblock_t *)((byte *)ptr - sizeof(memblock_t));\n\tif (block->id != ZONEID)\n\t\tSys_Error(\"Z_Realloc: realloced a pointer without ZONEID\");\n\tif (block->tag == 0)\n\t\tSys_Error(\"Z_Realloc: realloced a freed pointer\");\n\n\told_size = block->size;\n\told_size -= (4 + (int) sizeof(memblock_t)); /* see Z_TagMalloc() */\n\told_ptr = ptr;\n\n\tZ_Free(ptr);\n\tptr = Z_TagMalloc(size, 1);\n\tif (!ptr)\n\t\tSys_Error(\"Z_Realloc: failed on allocation of %i bytes\", size);\n\n\tif (ptr != old_ptr)\n\t\tmemmove(ptr, old_ptr, min(old_size, size));\n\tif (old_size < size)\n\t\tmemset((byte *)ptr + old_size, 0, size - old_size);\n\n\treturn ptr;\n}\n\n//============================================================================\n\n#define\tHUNK_SENTINAL\t0x1df001ed\n\ntypedef struct {\n\tint sentinal;\n\tint size;\t\t// including sizeof(hunk_t), -1 = not allocated\n\tchar name[8];\n} hunk_t;\n\nbyte *hunk_base;\nint hunk_size;\n\nint hunk_low_used;\nint hunk_high_used;\n\nbool hunk_tempactive;\nint hunk_tempmark;\n\nvoid R_FreeTextures(void);\n\n/*\n==============\nHunk_Check\n\nRun consistency and sentinal trashing checks\n==============\n*/\nvoid Hunk_Check(void)\n{\n\thunk_t *h;\n\n\tfor (h = (hunk_t *)hunk_base; (byte *)h != hunk_base + hunk_low_used;) {\n\t\tif (h->sentinal != HUNK_SENTINAL)\n\t\t\tSys_Error(\"Hunk_Check: trashed sentinal\");\n\t\tif (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)\n\t\t\tSys_Error(\"Hunk_Check: bad size\");\n\t\th = (hunk_t *)((byte *)h + h->size);\n\t}\n}\n\n/*\n==============\nHunk_Print\n\nIf \"all\" is specified, every single allocation is printed.\nOtherwise, allocations with the same name will be totaled up before printing.\n==============\n*/\nvoid Hunk_Print(bool all)\n{\n\thunk_t *h, *next, *endlow, *starthigh, *endhigh;\n\tint count, sum, totalblocks;\n\tchar name[9];\n\n\tname[8] = 0;\n\tcount = 0;\n\tsum = 0;\n\ttotalblocks = 0;\n\n\th = (hunk_t *)hunk_base;\n\tendlow = (hunk_t *)(hunk_base + hunk_low_used);\n\tstarthigh = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);\n\tendhigh = (hunk_t *)(hunk_base + hunk_size);\n\n\tCon_Printf(\"          :%8i total hunk size\\n\", hunk_size);\n\tCon_Printf(\"-------------------------\\n\");\n\n\twhile (1) {\n\t\t// skip to the high hunk if done with low hunk\n\t\tif (h == endlow) {\n\t\t\tCon_Printf(\"-------------------------\\n\");\n\t\t\tCon_Printf(\"          :%8i REMAINING\\n\", hunk_size - hunk_low_used - hunk_high_used);\n\t\t\tCon_Printf(\"-------------------------\\n\");\n\t\t\th = starthigh;\n\t\t}\n\n\t\t// if totally done, break\n\t\tif (h == endhigh)\n\t\t\tbreak;\n\n\t\t// run consistency checks\n\t\tif (h->sentinal != HUNK_SENTINAL)\n\t\t\tSys_Error(\"Hunk_Check: trashed sentinal\");\n\n\t\tif (h->size < 16 || h->size + (byte *)h - hunk_base > hunk_size)\n\t\t\tSys_Error(\"Hunk_Check: bad size\");\n\n\t\tnext = (hunk_t *)((byte *)h + h->size);\n\t\tcount++;\n\t\ttotalblocks++;\n\t\tsum += h->size;\n\n\t\t// print the single block\n\t\tmemcpy(name, h->name, 8);\n\t\tif (all)\n\t\t\tCon_Printf(\"%8p :%8i %8s\\n\", h, h->size, name);\n\n\t\t// print the total\n\t\tif (next == endlow || next == endhigh || strncmp(h->name, next->name, 8)) {\n\t\t\tif (!all)\n\t\t\t\tCon_Printf(\"          :%8i %8s (TOTAL)\\n\", sum, name);\n\t\t\tcount = 0;\n\t\t\tsum = 0;\n\t\t}\n\n\t\th = next;\n\t}\n\n\tCon_Printf(\"-------------------------\\n\");\n\tCon_Printf(\"%8i total blocks\\n\", totalblocks);\n\n}\n\n/*\n===================\nHunk_Print_f -- Baker 3.76 - Hunk Print from FitzQuake\n===================\n*/\nvoid Hunk_Print_f(void)\n{\n\tHunk_Print(false);\n}\n\n/*\n===================\nHunk_AllocName\n===================\n*/\nvoid *Hunk_AllocName(int size, char *name)\n{\n\thunk_t *h;\n\n#ifdef PARANOID\n\tHunk_Check();\n#endif\n\n\tif (size < 0)\n\t\tSys_Error(\"Hunk_Alloc: bad size: %i\", size);\n\n\tsize = sizeof(hunk_t) + ((size + 15) & ~15);\n\n\tif (hunk_size - hunk_low_used - hunk_high_used < size)\n\t\tSys_Error (\"Hunk_AllocName: failed on %i bytes for %s\",size, name);\t\n\n\th = (hunk_t *)(hunk_base + hunk_low_used);\n\thunk_low_used += size;\n\n\tCache_FreeLow(hunk_low_used);\n\n\tmemset(h, 0, size);\n\n\th->size = size;\n\th->sentinal = HUNK_SENTINAL;\n\tstrncpy(h->name, name, 8);\n\n\treturn (void *)(h + 1);\n}\n\n/*\n===================\nHunk_Alloc\n===================\n*/\nvoid *Hunk_Alloc(int size)\n{\n\treturn Hunk_AllocName(size, \"unknown\");\n}\n\nint Hunk_LowMark(void)\n{\n\treturn hunk_low_used;\n}\n\nvoid Hunk_FreeToLowMark(int mark)\n{\n\tif (mark < 0 || mark > hunk_low_used)\n\t\tSys_Error(\"Hunk_FreeToLowMark: bad mark %i\", mark);\n\tmemset(hunk_base + mark, 0, hunk_low_used - mark);\n\thunk_low_used = mark;\n}\n\nint Hunk_HighMark(void)\n{\n\tif (hunk_tempactive) {\n\t\thunk_tempactive = false;\n\t\tHunk_FreeToHighMark(hunk_tempmark);\n\t}\n\n\treturn hunk_high_used;\n}\n\nvoid Hunk_FreeToHighMark(int mark)\n{\n\tif (hunk_tempactive) {\n\t\thunk_tempactive = false;\n\t\tHunk_FreeToHighMark(hunk_tempmark);\n\t}\n\tif (mark < 0 || mark > hunk_high_used)\n\t\tSys_Error(\"Hunk_FreeToHighMark: bad mark %i\", mark);\n\tmemset(hunk_base + hunk_size - hunk_high_used, 0, hunk_high_used - mark);\n\thunk_high_used = mark;\n}\n\n/*\n===================\nHunk_HighAllocName\n===================\n*/\nvoid *Hunk_HighAllocName(int size, char *name)\n{\n\thunk_t *h;\n\n\tif (size < 0)\n\t\tSys_Error(\"Hunk_HighAllocName: bad size: %i\", size);\n\n\tif (hunk_tempactive) {\n\t\tHunk_FreeToHighMark(hunk_tempmark);\n\t\thunk_tempactive = false;\n\t}\n\n#ifdef PARANOID\n\tHunk_Check();\n#endif\n\n\tsize = sizeof(hunk_t) + ((size + 15) & ~15);\n\n\tif (hunk_size - hunk_low_used - hunk_high_used < size)\n\t\tSys_Error(\"Hunk_HighAlloc: failed on %i bytes for %s\", size, name);\n\n\thunk_high_used += size;\n\tCache_FreeHigh(hunk_high_used);\n\n\th = (hunk_t *)(hunk_base + hunk_size - hunk_high_used);\n\n\tmemset(h, 0, size);\n\th->size = size;\n\th->sentinal = HUNK_SENTINAL;\n\tstrncpy(h->name, name, 8);\n\n\treturn (void *)(h + 1);\n}\n\n/*\n=================\nHunk_TempAlloc\n\nReturn space from the top of the hunk\n=================\n*/\nvoid *Hunk_TempAlloc(int size)\n{\n\tvoid *buf;\n\n\tsize = (size + 15) & ~15;\n\n\tif (hunk_tempactive) {\n\t\tHunk_FreeToHighMark(hunk_tempmark);\n\t\thunk_tempactive = false;\n\t}\n\n\thunk_tempmark = Hunk_HighMark();\n\n\tbuf = Hunk_HighAllocName(size, \"temp\");\n\n\thunk_tempactive = true;\n\n\treturn buf;\n}\n\n/*\n===============================================================================\n\nCACHE MEMORY\n\n===============================================================================\n*/\n\ntypedef struct cache_system_s {\n\tint size;\t\t// including this header\n\tcache_user_t *user;\n\tchar name[16];\n\tstruct cache_system_s *prev, *next;\n\tstruct cache_system_s *lru_prev, *lru_next;\t// for LRU flushing\n} cache_system_t;\n\ncache_system_t *Cache_TryAlloc(int size, bool nobottom);\n\ncache_system_t cache_head;\n\n/*\n===========\nCache_Move\n===========\n*/\nvoid Cache_Move(cache_system_t *c)\n{\n\tcache_system_t *new;\n\n\t// we are clearing up space at the bottom, so only allocate it late\n\n\tif ((new = Cache_TryAlloc(c->size, true))) {\n\t\t//\t\tCon_Printf (\"cache_move ok\\n\");\n\n\t\tmemcpy(new + 1, c + 1, c->size - sizeof(cache_system_t));\n\t\tnew->user = c->user;\n\t\tmemcpy(new->name, c->name, sizeof(new->name));\n\t\tCache_Free(c->user);\n\t\tnew->user->data = (void *)(new + 1);\n\t}\n\telse {\n\t\t//\t\tCon_Printf (\"cache_move failed\\n\");\n\n\t\tCache_Free(c->user);\t\t// tough luck...\n\t}\n}\n\n/*\n============\nCache_FreeLow\n\nThrow things out until the hunk can be expanded to the given point\n============\n*/\nvoid Cache_FreeLow(int new_low_hunk)\n{\n\tcache_system_t *c;\n\n\twhile (1) {\n\t\tc = cache_head.next;\n\t\tif (c == &cache_head)\n\t\t\treturn;\t\t// nothing in cache at all\n\t\tif ((byte *)c >= hunk_base + new_low_hunk)\n\t\t\treturn;\t\t// there is space to grow the hunk\n\t\tCache_Move(c);\t// reclaim the space\n\t}\n}\n\n/*\n============\nCache_FreeHigh\n\nThrow things out until the hunk can be expanded to the given point\n============\n*/\nvoid Cache_FreeHigh(int new_high_hunk)\n{\n\tcache_system_t *c, *prev;\n\n\tprev = NULL;\n\twhile (1) {\n\t\tc = cache_head.prev;\n\t\tif (c == &cache_head)\n\t\t\treturn;\t\t// nothing in cache at all\n\t\tif ((byte *)c + c->size <= hunk_base + hunk_size - new_high_hunk)\n\t\t\treturn;\t\t// there is space to grow the hunk\n\t\tif (c == prev)\n\t\t\tCache_Free(c->user);\t// didn't move out of the way\n\t\telse {\n\t\t\tCache_Move(c);\t// try to move it\n\t\t\tprev = c;\n\t\t}\n\t}\n}\n\nvoid Cache_UnlinkLRU(cache_system_t *cs)\n{\n\tif (!cs->lru_next || !cs->lru_prev)\n\t\tSys_Error(\"Cache_UnlinkLRU: NULL link\");\n\n\tcs->lru_next->lru_prev = cs->lru_prev;\n\tcs->lru_prev->lru_next = cs->lru_next;\n\n\tcs->lru_prev = cs->lru_next = NULL;\n}\n\nvoid Cache_MakeLRU(cache_system_t *cs)\n{\n\tif (cs->lru_next || cs->lru_prev)\n\t\tSys_Error(\"Cache_MakeLRU: active link\");\n\n\tcache_head.lru_next->lru_prev = cs;\n\tcs->lru_next = cache_head.lru_next;\n\tcs->lru_prev = &cache_head;\n\tcache_head.lru_next = cs;\n}\n\n/*\n============\nCache_TryAlloc\n\nLooks for a free block of memory between the high and low hunk marks\nSize should already include the header and padding\n============\n*/\ncache_system_t *Cache_TryAlloc(int size, bool nobottom)\n{\n\tcache_system_t *cs, *new;\n\n\t// is the cache completely empty?\n\n\tif (!nobottom && cache_head.prev == &cache_head) {\n\t\tif (hunk_size - hunk_high_used - hunk_low_used < size)\n\t\t\tSys_Error(\"Cache_TryAlloc: %i is greater then free hunk\", size);\n\n\t\tnew = (cache_system_t *)(hunk_base + hunk_low_used);\n\t\tmemset(new, 0, sizeof(*new));\n\t\tnew->size = size;\n\n\t\tcache_head.prev = cache_head.next = new;\n\t\tnew->prev = new->next = &cache_head;\n\n\t\tCache_MakeLRU(new);\n\t\treturn new;\n\t}\n\n\t// search from the bottom up for space\n\n\tnew = (cache_system_t *)(hunk_base + hunk_low_used);\n\tcs = cache_head.next;\n\n\tdo {\n\t\tif (!nobottom || cs != cache_head.next) {\n\t\t\tif ((byte *)cs - (byte *) new >= size) {\t// found space\n\t\t\t\tmemset(new, 0, sizeof(*new));\n\t\t\t\tnew->size = size;\n\n\t\t\t\tnew->next = cs;\n\t\t\t\tnew->prev = cs->prev;\n\t\t\t\tcs->prev->next = new;\n\t\t\t\tcs->prev = new;\n\n\t\t\t\tCache_MakeLRU(new);\n\n\t\t\t\treturn new;\n\t\t\t}\n\t\t}\n\n\t\t// continue looking\n\t\tnew = (cache_system_t *)((byte *)cs + cs->size);\n\t\tcs = cs->next;\n\n\t} while (cs != &cache_head);\n\n\t// try to allocate one at the very end\n\tif (hunk_base + hunk_size - hunk_high_used - (byte *) new >= size) {\n\t\tmemset(new, 0, sizeof(*new));\n\t\tnew->size = size;\n\n\t\tnew->next = &cache_head;\n\t\tnew->prev = cache_head.prev;\n\t\tcache_head.prev->next = new;\n\t\tcache_head.prev = new;\n\n\t\tCache_MakeLRU(new);\n\n\t\treturn new;\n\t}\n\n\treturn NULL;\t\t// couldn't allocate\n}\n\n/*\n============\nCache_Flush_f\n\nThrow everything out, so new data will be demand cached\n============\n*/\nvoid Cache_Flush(void)\n{\n\twhile (cache_head.next != &cache_head)\n\t\tCache_Free(cache_head.next->user);\t// reclaim the space\n}\n\n/*\n============\nCache_Print\n============\n*/\nvoid Cache_Print(void)\n{\n\tcache_system_t *cd;\n\n\tfor (cd = cache_head.next; cd != &cache_head; cd = cd->next)\n\t\tCon_Printf(\"%8i : %s\\n\", cd->size, cd->name);\n}\n\n/*\n============\nCache_Report\n============\n*/\nvoid Cache_Report(void)\n{\n\tCon_DPrintf(\"%4.1f megabyte data cache\\n\", (hunk_size - hunk_high_used - hunk_low_used) / (float)(1024 * 1024));\n}\n\n/*\n============\nCache_Compact\n============\n*/\nvoid Cache_Compact(void)\n{\n}\n\n/*\n============\nCache_Init\n============\n*/\nvoid Cache_Init(void)\n{\n\tcache_head.next = cache_head.prev = &cache_head;\n\tcache_head.lru_next = cache_head.lru_prev = &cache_head;\n\n\tCmd_AddCommand(\"flush\", Cache_Flush);\n}\n\n/*\n==============\nCache_Free\n\nFrees the memory and removes it from the LRU list\n==============\n*/\nvoid Cache_Free(cache_user_t *c)\n{\n\tcache_system_t *cs;\n\n\tif (!c->data)\n\t\tSys_Error(\"Cache_Free: not allocated\");\n\n\tcs = ((cache_system_t *)c->data) - 1;\n\n\tcs->prev->next = cs->next;\n\tcs->next->prev = cs->prev;\n\tcs->next = cs->prev = NULL;\n\n\tc->data = NULL;\n\n\tCache_UnlinkLRU(cs);\n}\n\n/*\n==============\nCache_Check\n==============\n*/\nvoid *Cache_Check(cache_user_t *c)\n{\n\tcache_system_t *cs;\n\n\tif (!c->data)\n\t\treturn NULL;\n\n\tcs = ((cache_system_t *)c->data) - 1;\n\n\t// move to head of LRU\n\tCache_UnlinkLRU(cs);\n\tCache_MakeLRU(cs);\n\n\treturn c->data;\n}\n\n/*\n==============\nCache_Alloc\n==============\n*/\nvoid *Cache_Alloc(cache_user_t *c, int size, char *name)\n{\n\tcache_system_t *cs;\n\n\tif (c->data)\n\t\tSys_Error(\"Cache_Alloc: already allocated\");\n\n\tif (size <= 0)\n\t\tSys_Error(\"Cache_Alloc: size %i\", size);\n\n\tsize = (size + sizeof(cache_system_t) + 15) & ~15;\n\n\t// find memory for it\n\twhile (1) {\n\t\tif ((cs = Cache_TryAlloc(size, false))) {\n\t\t\tstrncpy(cs->name, name, sizeof(cs->name) - 1);\n\t\t\tc->data = (void *)(cs + 1);\n\t\t\tcs->user = c;\n\t\t\tbreak;\n\t\t}\n\n\t\t// free the least recently used cahedat\n\t\tif (cache_head.lru_prev == &cache_head)\n\t\t\tSys_Error(\"Cache_Alloc: out of memory\"); // not enough memory at all\n\n\t\tCache_Free(cache_head.lru_prev->user);\n\t}\n\n\treturn Cache_Check(c);\n}\n\n//============================================================================\n\n/*\n========================\nMemory_Init\n========================\n*/\nvoid Memory_Init(void *buf, int size)\n{\n\tint p, zonesize = ZONE_DEFAULT_SIZE;\n\n\thunk_base = buf;\n\thunk_size = size;\n\thunk_low_used = 0;\n\thunk_high_used = 0;\n\n\tCache_Init();\n\tif ((p = COM_CheckParm(\"-zone\")) && (p + 1) < com_argc)\n\t\tzonesize = atoi(com_argv[p + 1]) * 1024;\n\n\tmainzone = Hunk_AllocName(zonesize, \"zone\");\n\tZ_ClearZone(mainzone, zonesize);\n\n\tCmd_AddCommand(\"hunk_print\", Hunk_Print_f); //johnfitz\n}\n"
  },
  {
    "path": "source/zone.h",
    "content": "/*\nCopyright (C) 1996-1997 Id Software, Inc.\n\nThis program is free software; you can redistribute it and/or\nmodify it under the terms of the GNU General Public License\nas published by the Free Software Foundation; either version 2\nof the License, or (at your option) any later version.\n\nThis program is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  \n\nSee the GNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with this program; if not, write to the Free Software\nFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.\n\n*/\n/*\n memory allocation\n\n\nH_??? The hunk manages the entire memory block given to quake.  It must be\ncontiguous.  Memory can be allocated from either the low or high end in a\nstack fashion.  The only way memory is released is by resetting one of the\npointers.\n\nHunk allocations should be given a name, so the Hunk_Print () function\ncan display usage.\n\nHunk allocations are guaranteed to be 16 byte aligned.\n\nThe video buffers are allocated high to avoid leaving a hole underneath\nserver allocations when changing to a higher video mode.\n\n\nZ_??? Zone memory functions used for small, dynamic allocations like text\nstrings from command input.  There is only about 48K for it, allocated at\nthe very bottom of the hunk.\n\nCache_??? Cache memory is for objects that can be dynamically loaded and\ncan usefully stay persistant between levels.  The size of the cache\nfluctuates from level to level.\n\nTo allocate a cachable object\n\n\nTemp_??? Temp memory is used for file loading and surface caching.  The size\nof the cache memory is adjusted so that there is a minimum of 512k remaining\nfor temp memory.\n\n\n------ Top of Memory -------\n\nhigh hunk allocations\n\n<--- high hunk reset point held by vid\n\nvideo buffer\n\nz buffer\n\nsurface cache\n\n<--- high hunk used\n\ncachable memory\n\n<--- low hunk used\n\nclient and server low hunk allocations\n\n<-- low hunk reset point held by host\n\nstartup hunk allocations\n\nZone block\n\n----- Bottom of Memory -----\n\n\n\n*/\n\nvoid Memory_Init (void *buf, int size);\n\nvoid Z_Free (void *ptr);\nvoid *Z_Malloc (int size);\t\t\t// returns 0 filled memory\nvoid *Z_TagMalloc (int size, int tag);\n\nvoid Z_DumpHeap (void);\nvoid Z_CheckHeap (void);\nint Z_FreeMemory (void);\n\nvoid *Hunk_Alloc (int size);\t\t// returns 0 filled memory\nvoid *Hunk_AllocName (int size, char *name);\n\nvoid *Hunk_HighAllocName (int size, char *name);\n\nint\tHunk_LowMark (void);\nvoid Hunk_FreeToLowMark (int mark);\n\nint\tHunk_HighMark (void);\nvoid Hunk_FreeToHighMark (int mark);\n\nvoid *Hunk_TempAlloc (int size);\n\nvoid Hunk_Check (void);\n\ntypedef struct cache_user_s\n{\n\tvoid\t*data;\n} cache_user_t;\n\nvoid Cache_Flush (void);\n\nvoid *Cache_Check (cache_user_t *c);\n// returns the cached data, and moves to the head of the LRU list\n// if present, otherwise returns NULL\n\nvoid Cache_Free (cache_user_t *c);\n\nvoid *Cache_Alloc (cache_user_t *c, int size, char *name);\n// Returns NULL if all purgable data was tossed and there still\n// wasn't enough room.\n\nvoid Cache_Report (void);\n\n\n\n"
  }
]