commit fb01ea5ba8fdecc728fba834348d8ee840ef4c61 Author: Hans Kokx Date: Tue Jul 14 19:31:07 2026 +0200 first commit diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..d159169 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/GRAPHHOV.EQU b/GRAPHHOV.EQU new file mode 100644 index 0000000..e53a99c --- /dev/null +++ b/GRAPHHOV.EQU @@ -0,0 +1,145 @@ +; Hovertank 3-D Source Code +; Copyright (C) 1993-2014 Flat Rock Software +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation; either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, +; but WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +; GNU General Public License for more details. +; +; You should have received a copy of the GNU General Public License along +; with this program; if not, write to the Free Software Foundation, Inc., +; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +;===================================== +; +; Graphics DEFINE file for .HOV +; IGRAB-ed on Thu Dec 02 11:07:47 1993 +; +;===================================== + +MAN1PIC = 0 +MAN2PIC = 1 +MANDIE1PIC = 2 +MANDIE2PIC = 3 +MANDIE3PIC = 4 +MANDIE4PIC = 5 +MANDIE5PIC = 6 +WOMAN1PIC = 7 +WOMAN2PIC = 8 +WOMANDIE1PIC = 9 +WOMANDIE2PIC = 10 +WOMANDIE3PIC = 11 +WOMANDIE4PIC = 12 +WOMANDIE5PIC = 13 +BIGSHOTPIC = 14 +PSHOTPIC = 15 +MSHOTPIC = 16 +SHOTDIE1PIC = 17 +SHOTDIE2PIC = 18 +SHOTDIE3PIC = 19 +SHOTDIE4PIC = 20 +SHOTDIE5PIC = 21 +TANK1PIC = 22 +TANKDIE1PIC = 23 +TANKDIE2PIC = 24 +TANKDIE3PIC = 25 +TANKDIE4PIC = 26 +TANKDIE5PIC = 27 +MUTANT1PIC = 28 +MUTANT2PIC = 29 +MUTANT3PIC = 30 +MUTANT4PIC = 31 +MUTANTDIE1PIC = 32 +MUTANTDIE2PIC = 33 +MUTANTDIE3PIC = 34 +MUTANTDIE4PIC = 35 +MUTANTDIE5PIC = 36 +MUTANTSWINGPIC = 37 +MUTANTHITPIC = 38 +SHIELD1PIC = 39 +SHIELD2PIC = 40 +DRONE1PIC = 41 +DRONE2PIC = 42 +DRONE3PIC = 43 +DRONE4PIC = 44 +DRONEDIE1PIC = 45 +DRONEDIE2PIC = 46 +DRONEDIE3PIC = 47 +DRONEDIE4PIC = 48 +DRONEDIE5PIC = 49 +WARP1PIC = 50 +WARP2PIC = 51 +WARP3PIC = 52 +WARP4PIC = 53 +DASHPIC = 54 +DIGIT0PIC = 55 +DIGIT1PIC = 56 +DIGIT2PIC = 57 +DIGIT3PIC = 58 +DIGIT4PIC = 59 +DIGIT5PIC = 60 +DIGIT6PIC = 61 +DIGIT7PIC = 62 +DIGIT8PIC = 63 +DIGIT9PIC = 64 +SHIELDFULLPIC = 65 +SHIELDHALFPIC = 66 +SHIELDLOWPIC = 67 +EMPTYGUYPIC = 68 +SAVEDGUYPIC = 69 +DEADGUYPIC = 70 +REARMINGPIC = 71 +READYPIC = 72 +CHARGINGPIC = 73 +MAXPOWERPIC = 74 +ENDPIC = 75 +LOGOPIC = 76 +STARSPIC = 77 +TITLEPIC = 78 +DEATHPIC = 79 +MISSIONPIC = 80 +UFAPIC = 81 +MADUFAPIC = 82 + + + +; +; Amount of each data item +; +NUMCHUNKS = 86 +NUMFONT = 0 +NUMFONTM = 1 +NUMPICS = 83 +NUMPICM = 0 +NUMSPRITES = 0 +NUMTILE8 = 72 +NUMTILE8M = 0 +NUMTILE16 = 0 +NUMTILE16M = 0 +NUMTILE32 = 0 +NUMTILE32M = 0 +; +; File offsets for data items +; +STRUCTPIC = 0 + +STARTFONT = 1 +STARTFONTM = 1 +STARTPICS = 2 +STARTPICM = 85 +STARTSPRITES = 85 +STARTTILE8 = 85 +STARTTILE8M = 86 +STARTTILE16 = 86 +STARTTILE16M = 86 +STARTTILE32 = 86 +STARTTILE32M = 86 + +; +; Thank you for using IGRAB! +; diff --git a/GRAPHHOV.H b/GRAPHHOV.H new file mode 100644 index 0000000..dbf64da --- /dev/null +++ b/GRAPHHOV.H @@ -0,0 +1,146 @@ +/* Hovertank 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +////////////////////////////////////// +// +// Graphics DEFINE file for .HOV +// IGRAB-ed on Thu Dec 02 11:07:46 1993 +// +////////////////////////////////////// + +#define MAN1PIC 0 +#define MAN2PIC 1 +#define MANDIE1PIC 2 +#define MANDIE2PIC 3 +#define MANDIE3PIC 4 +#define MANDIE4PIC 5 +#define MANDIE5PIC 6 +#define WOMAN1PIC 7 +#define WOMAN2PIC 8 +#define WOMANDIE1PIC 9 +#define WOMANDIE2PIC 10 +#define WOMANDIE3PIC 11 +#define WOMANDIE4PIC 12 +#define WOMANDIE5PIC 13 +#define BIGSHOTPIC 14 +#define PSHOTPIC 15 +#define MSHOTPIC 16 +#define SHOTDIE1PIC 17 +#define SHOTDIE2PIC 18 +#define SHOTDIE3PIC 19 +#define SHOTDIE4PIC 20 +#define SHOTDIE5PIC 21 +#define TANK1PIC 22 +#define TANKDIE1PIC 23 +#define TANKDIE2PIC 24 +#define TANKDIE3PIC 25 +#define TANKDIE4PIC 26 +#define TANKDIE5PIC 27 +#define MUTANT1PIC 28 +#define MUTANT2PIC 29 +#define MUTANT3PIC 30 +#define MUTANT4PIC 31 +#define MUTANTDIE1PIC 32 +#define MUTANTDIE2PIC 33 +#define MUTANTDIE3PIC 34 +#define MUTANTDIE4PIC 35 +#define MUTANTDIE5PIC 36 +#define MUTANTSWINGPIC 37 +#define MUTANTHITPIC 38 +#define SHIELD1PIC 39 +#define SHIELD2PIC 40 +#define DRONE1PIC 41 +#define DRONE2PIC 42 +#define DRONE3PIC 43 +#define DRONE4PIC 44 +#define DRONEDIE1PIC 45 +#define DRONEDIE2PIC 46 +#define DRONEDIE3PIC 47 +#define DRONEDIE4PIC 48 +#define DRONEDIE5PIC 49 +#define WARP1PIC 50 +#define WARP2PIC 51 +#define WARP3PIC 52 +#define WARP4PIC 53 +#define DASHPIC 54 +#define DIGIT0PIC 55 +#define DIGIT1PIC 56 +#define DIGIT2PIC 57 +#define DIGIT3PIC 58 +#define DIGIT4PIC 59 +#define DIGIT5PIC 60 +#define DIGIT6PIC 61 +#define DIGIT7PIC 62 +#define DIGIT8PIC 63 +#define DIGIT9PIC 64 +#define SHIELDFULLPIC 65 +#define SHIELDHALFPIC 66 +#define SHIELDLOWPIC 67 +#define EMPTYGUYPIC 68 +#define SAVEDGUYPIC 69 +#define DEADGUYPIC 70 +#define REARMINGPIC 71 +#define READYPIC 72 +#define CHARGINGPIC 73 +#define MAXPOWERPIC 74 +#define ENDPIC 75 +#define LOGOPIC 76 +#define STARSPIC 77 +#define TITLEPIC 78 +#define DEATHPIC 79 +#define MISSIONPIC 80 +#define UFAPIC 81 +#define MADUFAPIC 82 + + + +// +// Amount of each data item +// +#define NUMCHUNKS 86 +#define NUMFONT 0 +#define NUMFONTM 1 +#define NUMPICS 83 +#define NUMPICM 0 +#define NUMSPRITES 0 +#define NUMTILE8 72 +#define NUMTILE8M 0 +#define NUMTILE16 0 +#define NUMTILE16M 0 +#define NUMTILE32 0 +#define NUMTILE32M 0 +// +// File offsets for data items +// +#define STRUCTPIC 0 + +#define STARTFONT 1 +#define STARTFONTM 1 +#define STARTPICS 2 +#define STARTPICM 85 +#define STARTSPRITES 85 +#define STARTTILE8 85 +#define STARTTILE8M 86 +#define STARTTILE16 86 +#define STARTTILE16M 86 +#define STARTTILE32 86 +#define STARTTILE32M 86 + +// +// Thank you for using IGRAB! +// diff --git a/HMAIN.C b/HMAIN.C new file mode 100644 index 0000000..e5cf079 --- /dev/null +++ b/HMAIN.C @@ -0,0 +1,1368 @@ +/* Hovertank 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "HOVERDEF.H" +#pragma hdrstop + +/* + +NOTICE TO ANYONE READING THIS: + +This is the last gasp of our old routines! Everything is being rewritten +from scratch to work with new graphic modes and utilities. This code +stinks! + +*/ + + +/* +============================================================================= + + GLOBALS + +============================================================================= +*/ + +int SNDstarted,KBDstarted; // whether int handlers were started + +int grhandle,levelhandle,soundhandle; + +typedef struct +{ + int headersize; + long dictionary; + long dataoffsets; +} grheadtype; + +grheadtype *grhead; // sets grhuffman and grstarts from here +huffnode *grhuffman; // huffman dictionary for egagraph +long *grstarts; // array of offsets in egagraph, -1 for sparse +int grhandle; // handle to egagraph, kept open allways +long grposition; // current seek position in file +long chunkcomplen; // compressed length of a chunk + + +int soundblaster; // present? + +int levelhandle,soundhandle; + +#define BUFFERSIZE 1024 +memptr bufferseg; // small general purpose memory block + +memptr levelseg; + +int tedlevel,ingame,resetgame; + +memptr scalesegs[NUMPICS]; + +/* +============================================================================= +*/ + + +/* +============= += += DoHelpText += +============= +*/ + +void DoHelpText(void) +{ + CenterWindow (38,14); + + fontcolor = 13; + CPPrint ("HoverTank Commands\n"); + fontcolor = 15; + py+=6; + PPrint ( +"F2 : Sound on / off\n" +"F3 : Keyboard mode / custom\n" +"F4 : Joystick mode\n" +"F5 : Reset game\n" +"ESC : Quit\n"); + + py+=6; + PPrint ( +"UP / DOWN : forward/reverse\n" +"LEFT / RIGHT : turn\n"); + + py+=6; + CPPrint (""); + Ack(); + EraseWindow (); + + CPPrint ("Button 1 / Ctrl\n"); + CPPrint ("---------------\n\n"); + + PPrint ( +/*.....................................*/ +"Charge cannon. A fully charged cannon\n" +"can shoot through multiple targets.\n" +"While the cannon is charging, your\n" +"tanks turning speed is halved for fine\n" +"aiming adjustments.\n\n"); + + CPPrint (""); + Ack(); + EraseWindow (); + + CPPrint ("Button 2 / Alt\n"); + CPPrint ("---------------\n\n"); + PPrint ( +/*.....................................*/ +"Afterburner thrusting. Doubles your\n" +"forward or backwards speed, but does\n" +"not effect your turning speed.\n"); + + Ack(); + +} + + +/* +================== += += DebugMemory += +================== +*/ + +void DebugMemory (void) +{ + CenterWindow (16,7); + + CPPrint ("Memory Usage\n"); + CPPrint ("------------"); + PPrint ("\nTotal :"); + PPrintUnsigned (totalmem/64); + PPrint ("k\nFree :"); + PPrintUnsigned (MMUnusedMemory()/64); + PPrint ("k\nWith purge:"); + PPrintUnsigned (MMTotalFree()/64); + PPrint ("k\n"); + CPPrint (""); + PGet(); +} + + + + +/* +================ += += DebugKeys += +================ +*/ +void DebugKeys (void) +{ + int i; + + if (keydown[0x22]) // G = god mode + { + ExpWin (12,1); + if (godmode) + CPPrint ("God mode off"); + else + CPPrint ("God mode on"); + Ack(); + godmode ^= 1; + } + else if (keydown[0x32]) // M = memory info + { + DebugMemory(); + } + if (keydown[0x19]) // P = pause with no screen disruptioon + { + singlestep=1; + } + if (keydown[0x1f]) // S = shield point + { + screenofs = 0; + HealPlayer(); + } + else if (keydown[0x14]) // T = free time + { + if (timestruct.min<9) + timestruct.min++; + screenofs = 0; + DrawPic (6,48,DIGIT0PIC+timestruct.min); + } + else if (keydown[0x11]) // W = warp to level + { + ExpWin(26,1); + PPrint("Warp to which level(1-20):"); + i = InputInt(); + if (i>=1 && i<=21) + { + level = i-1; + leveldone=1; + } + } + +} + +/*=========================================================================*/ + +/* +============= += += CheckKeys += += Checks to see if an F-key is being pressed and handles it += +============= +*/ + +int CheckKeys(void) +{ + if (!NBKscan) + return 0; + + switch (NBKscan&0x7f) + { + case 0x3b: // F1 = help + ClearKeys (); + DoHelpText (); + break; + case 0x3c: // F2 = sound on/off + ClearKeys (); + ExpWin (13,1); + PPrint ("Sound (Y/N)?"); + ch=toupper(PGet()); + if (ch=='N') + soundmode = false; + else if (ch=='Y') + soundmode = true; + break; + case 0x3d: // F3 = keyboard mode + ClearKeys (); + calibratekeys (); + break; + case 0x3e: // F4 = joystick mode + ClearKeys (); + CalibrateJoy (1); + break; + case 0x3f: // F5 = reset game + ClearKeys (); + ExpWin (18,1); + PPrint ("RESET GAME (Y/N)?"); + ch=toupper(PGet()); + if (ch=='Y') + { + resetgame = 1; + leveldone = -99; + } + break; + + case 0x58: // F12 + ? = debug keys + DebugKeys(); + break; + case 1: // ESC = quit + ClearKeys (); + ExpWin (12,1); + PPrint ("QUIT (Y/N)?"); + ch=toupper(PGet()); + if (ch=='Y') + Quit (""); + break; + + + default: + return 0; + } + + + ClearKeys (); + return 1; +} + + +//========================================================================== + +/* +============================ += += GetChunkLength += += Seeks into the igrab data file at the start of the given chunk and += reads the uncompressed length (first four bytes). The file pointer is += positioned so the compressed data can be read in next. += ChunkCompLen is set to the calculated compressed length += +============================ +*/ + +long GetChunkLength (int chunk) +{ + long len; + + lseek(grhandle,grstarts[chunk],SEEK_SET); + read(grhandle,&len,sizeof(len)); + chunkcomplen = grstarts[chunk+1]-grstarts[chunk]-4; + + return len; +} + +//========================================================================== + +/* +============================ += += LoadNearData += += Load stuff into data segment before memory manager is += started (which takes all available memory, near and far) += +============================ +*/ + +void LoadNearData (void) +{ + int handle; + long length; + +// +// load egahead.ext (offsets and dictionary for graphics file) +// + if ((handle = open("EGAHEAD."EXTENSION, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1) + Quit ("Can't open EGAHEAD."EXTENSION"!"); + + length = filelength(handle); + grhead = malloc(length); + + read(handle, grhead, length); + + close(handle); + + +} + +//========================================================================== + +/* +========================== += += SegRead += += Read from a file to a segment pointer += +========================== +*/ + +void SegRead (int handle, memptr dest, long length) +{ + if (length>0xffffl) + Quit ("SegRead doesn't support 64K reads yet!"); + +asm push ds +asm mov bx,[handle] +asm mov cx,[WORD PTR length] +asm mov dx,0 // segment aligned +asm mov ds,[dest] +asm mov ah,3fh // READ w/handle +asm int 21h +asm pop ds + +} + +//========================================================================== + + + +///////////////////////////////////////////////////////// +// +// InitGrFile +// +///////////////////////////////////////////////////////// + +void InitGrFile (void) +{ + memptr buffer; + +// +// calculate some offsets in the header +// + grhuffman = (huffnode *)( ((char *)grhead)+grhead->dictionary); + grstarts = (long *)( ((char *)grhead)+grhead->dataoffsets); + + OptimizeNodes (grhuffman); + +// +// Open the graphics file, leaving it open until the game is finished +// + grhandle = open("EGAGRAPH."EXTENSION, O_RDONLY | O_BINARY); + if (grhandle == -1) + Quit ("Cannot open EGAGRAPH."EXTENSION"!"); + + +// +// load the pic and sprite headers into the data segment +// +#if NUMPICS>0 + needgr[STRUCTPIC] = 1; // make sure this chunk never reloads + grsegs[STRUCTPIC] = (memptr)0xffff; + GetChunkLength(STRUCTPIC); // position file pointer + MMGetPtr(&buffer, chunkcomplen); + SegRead (grhandle,buffer,chunkcomplen); + HuffExpand ((unsigned char huge *)buffer, (unsigned char huge *)pictable, + sizeof(pictable),grhuffman); + MMFreePtr(&buffer); +#endif + +#if NUMPICM>0 + needgr[STRUCTPICM] = 1; // make sure this chunk never reloads + grsegs[STRUCTPICM] = (memptr)0xffff; + GetChunkLength(STRUCTPICM); // position file pointer + MMGetPtr(&buffer, chunkcomplen); + SegRead (grhandle,buffer,chunkcomplen); + HuffExpand (buffer, (unsigned char huge *)picmtable, + sizeof(picmtable),grhuffman); + MMFreePtr(&buffer); +#endif + +#if NUMSPRITES>0 + needgr[STRUCTSPRITE] = 1; // make sure this chunk never reloads + grsegs[STRUCTSPRITE] = (memptr)0xffff; + GetChunkLength(STRUCTSPRITE); // position file pointer + MMGetPtr(&buffer, chunkcomplen); + SegRead (grhandle,buffer,chunkcomplen); + HuffExpand (buffer, (unsigned char huge *)spritetable, + sizeof(spritetable),grhuffman); + MMFreePtr(&buffer); +#endif + + +} + + +//========================================================================== + +/* +========================== += += CacheGrFile += += Goes through grneeded and grsegs, and makes sure += everything needed is in memory += +========================== +*/ + +// base tile sizes for EGA mode +#define BLOCK 32 +#define MASKBLOCK 40 + +void CacheGrFile (void) +{ + int i; + long filepos,newpos; // current seek position in file + long expanded,compressed; // chunk lengths + memptr bigbufferseg; // for compressed + +// +// make unneeded chunks purgable +// + for (i=0;i=STARTTILE8) + { + // + // tiles are of a known size + // + if (i=STARTTILE8) + { + // + // tiles are of a known size + // + if (picnum0) + close(grhandle); + if (levelhandle>0) + close(levelhandle); + if (soundhandle>0) + close(soundhandle); + + _AX = 3; + geninterrupt (0x10); // text mode + + if (!(*error) && !tedlevel) + { +#if 0 + movedata (FP_SEG(&PIRACY),FP_OFF(&PIRACY),0xb800,0,4000); + bioskey (0); + clrscr(); +#endif + + _argc = 2; + _argv[1] = "LAST.SHL"; + _argv[2] = "ENDSCN.SCN"; + _argv[3] = NULL; + if (execv("LOADSCN.EXE", _argv) == -1) + { + clrscr(); + puts("Couldn't find executable LOADSCN.EXE.\n"); + exit(1); + } + + } + else + puts (error); + + + exit (0); // quit to DOS +} + + +//========================================================================== + +/* +====================== += += LoadLevel += += Loads LEVEL00.EXT (00 = global variable level) += +====================== +*/ + +void LoadLevel(void) +{ + unsigned far *planeptr; + int loop,x,y,i,j; + unsigned length; + char filename[30]; + char num[3]; + memptr bufferseg; + + +// +// load the new level in and decompress +// + if (level<10) + { + itoa (level,num,10); + strcpy (filename,"LEVEL0"); + } + else + { + itoa (level,num,10); + strcpy (filename,"LEVEL"); + } + + strcat (filename,num); + strcat (filename,"."EXTENSION); + + BloadinMM(filename,&bufferseg); + + length = *(unsigned _seg *)bufferseg; + + if (levelseg) + MMFreePtr (&levelseg); + + MMGetPtr (&levelseg,length); + + RLEWExpand ((unsigned far *)bufferseg,(unsigned far *)levelseg); + + MMFreePtr (&bufferseg); + + levelheader = (LevelDef far *)levelseg; + +// +// copy plane 0 to tilemap +// + planeptr= (unsigned far *)((char _seg *)levelseg+32); + for (y=0;yheight;y++) + for (x=0;xwidth;x++) + tilemap[x][y]=*planeptr++; + + +// +// spawn tanks +// + planeptr= (unsigned far *)((char _seg *)levelseg+32+levelheader->planesize); + StartLevel (planeptr); + + MMFreePtr (&levelseg); + +} + +//========================================================================== + + +/* +================= += += CacheDrawPic += +================= +*/ + +void CacheDrawPic(int picnum) +{ + int i; + + CachePic (STARTPICS+picnum); + + EGASplitScreen(200); + SetScreen(0,0); + SetLineWidth(80); + screenofs = 0; + + EGAWRITEMODE(0); + DrawPic (0,0,picnum); + + EGAWRITEMODE(1); + EGAMAPMASK(15); + CopyEGA(80,200,0,0x4000); + EGAWRITEMODE(0); + + MMSetPurge (&grsegs[STARTPICS+picnum],3); + +} + + +//========================================================================== + +int SoundPlaying (void) +{ + if (soundblaster) + return jmSamplePlaying(); + else + return sndptr; +} + +#if 0 + +/* +===================== += += PlaySound += += Dispatches to either pc speaker sound routines or sound blaster += digitized routines += +===================== +*/ + +void PlaySound (int num) +{ + if (soundblaster) + jmPlaySample(num); + else + PlaySoundSPK(num); +} + +#endif + +//========================================================================== + + +/* +===================== += += Intro += +===================== +*/ + +void Intro (void) +{ + memptr shapeseg; + int i,f,sx,sy,page; + unsigned pageptr[2],pagewidth[2],pageheight[2]; + float x,y,z,angle,step,sn,cs,maxz,sizescale,maxy,coordscale,scale; + float ytop,xmid,minz,worldycenter,worldxcenter; + + FadeOut(); + + SetLineWidth(SCREENWIDTH); + + screenofs=0; + + CacheDrawPic (STARSPIC); + pxl=0; + pxh=320; + py=180; + CPPrint ("Copyright (c) 1991 Softdisk inc.\n"); + CPPrint ("'I' for information"); + EGAWRITEMODE(1); + EGAMAPMASK(15); + CopyEGA(40,200,0,0x4000); + CopyEGA(40,200,0,0x8000); + CopyEGA(40,200,0,0xc000); + StopDrive(); + + CachePic (STARTPICS+LOGOPIC); + + SC_MakeShape( + grsegs[STARTPICS+LOGOPIC], + pictable[LOGOPIC].width, + pictable[LOGOPIC].height, + &shapeseg); + + MMFreePtr(&grsegs[STARTPICS+LOGOPIC]); + + FadeIn(); + + sx=160; + sy=180; + + memset (zbuffer,0,sizeof(zbuffer)); + +/* +============================================================================= + + SCALED PICTURE DIRECTOR + +============================================================================= +*/ + +#define PICHEIGHT 64 // full size height of scaled pic +#define NUMFRAMES 300.0 +#define MAXANGLE (3.141592657*0.6) // go from 0 to this in numframes +#define RADIUS 1000.0 // world coordinates +#define DISTANCE 1000.0 // center point z distance + + minz = cos(MAXANGLE)*RADIUS; // closest point + minz += DISTANCE; + sizescale = 256*minz; // closest point will be full size + ytop = 80 - (PICHEIGHT/2)*(sizescale/DISTANCE)/256; + z = sizescale/(DISTANCE*256); + ytop = ytop/z; // world coordinates + worldycenter=ytop-RADIUS; + xmid=sin(MAXANGLE)*RADIUS/2; + worldxcenter=-xmid; + + f=1; + page = inttime = screenofs = pagewidth[0] = pagewidth[1] = 0; + do + { + step = f/NUMFRAMES; + angle=MAXANGLE*step; + sn=sin(angle); + cs=cos(angle); + x=worldxcenter+sn*RADIUS/2; + y=worldycenter+sn*RADIUS; + z=DISTANCE+cs*RADIUS; + scale = sizescale/z; + sx=160+ (int)(x*scale/256); + sy=100- (int)(y*scale/256); + + inttime=0; + sound((int)(sn*1500)); + +// +// erase old position +// + if (pagewidth[page]) + { + EGAWRITEMODE(1); + EGAMAPMASK(15); + CopyEGA(pagewidth[page],pageheight[page], + pageptr[page]+0x8000,pageptr[page]); + } + +// +// draw new position +// + EGAWRITEMODE(2); + if (SC_ScaleShape(sx,sy,(int)scale<40 ? 10 : scale/4,shapeseg)) + { + pagewidth[page]=scaleblockwidth; + pageheight[page]=scaleblockheight; + pageptr[page]=scaleblockdest; + } + else + pagewidth[page]=0; + + EGAWRITEMODE(0); + EGABITMASK(255); + +// +// display it +// + SetScreen(screenofs,0); + + page^=1; + screenofs = 0x4000*page; + + f++; + + if (fNUMFRAMES) + f=NUMFRAMES; + } + else + f++; // last frame is shown + + if (NBKscan>0x7f) + break; + } while (f<=NUMFRAMES); + nosound(); + + for (i=0;i<200;i++) + { + WaitVBL(1); + if (NBKscan>0x7f) + { + if (NBKscan==0x97) //'I' for info + { + screenofs^=0x4000; + CenterWindow(24,10); + py+=2; + CPPrint ("Hovertank v1.17\n\n"); + CPPrint ("Softdisk Publishing delivers a\n"); + CPPrint ("high quality EGA game to\n"); + CPPrint ("your door every month!\n"); + CPPrint ("Call 1-800-831-2694 for\n"); + CPPrint ("subscription rates and\n"); + CPPrint ("back issues.\n"); + ClearKeys(); + Ack(); + } + ClearKeys(); + break; + } + } + + MMFreePtr(&shapeseg); +} + +//========================================================================== + + + +/* +===================== +== +== DemoLoop +== +===================== +*/ +#define PAUSE 300 +void DemoLoop (void) +{ + int i,originx; + ControlStruct c; + + FadeOut(); + + CacheDrawPic (TITLEPIC); + StopDrive(); // make floppy motors turn off + + FadeIn (); + + originx=0; + i=100; + while (1) + { + if (i>PAUSE && i<=PAUSE+80) + originx+=4; + + if (i>PAUSE*2 && i<=PAUSE*2+80) + originx-=4; + + if (i>PAUSE*2+80) + i=0; + + SetScreen(originx/8,originx%8); + + i++; + + screenofs = originx/8; + if (CheckKeys()) + { + EGAWRITEMODE(1); + EGAMAPMASK(15); + CopyEGA(80,200,0x4000,0); + } + c=ControlPlayer(1); + if (c.button1 || c.button2) + break; + if (keydown[0x39]) + break; + } + + ClearKeys(); +} + + +//========================================================================== + +/* +==================== += += SetupGraphics += +==================== +*/ +void SetupGraphics (void) +{ + int i; + + InitGrFile (); // load the graphic file header + +// +// go through the pics and make scalable shapes, the discard the pic +// + for (i=MAN1PIC;iclass = nothing; + if (hit->radarx) + XPlot (hit->radarx,hit->radary,hit->radarcolor); + DrawPic (2*savedcount+1,6,SAVEDGUYPIC); + savedcount++; + if (!--numrefugees) + { + PlaySound (LASTHOSTAGESND); + SpawnWarp (warpx,warpy); + } +} + +/* +=================== += += CheckFire += +=================== +*/ + +void CheckFire (void) +{ + if (gunstate == rearming) + { + if ( (guncount+=tics) > GUNARM) + { + gunstate = ready; + PlaySound(GUNREADYSND); + DrawPic (14,40,READYPIC); + } + return; + } + + if (c.button1) + { + // holding down button + if (gunstate==ready) + { + gunstate = charging; + DrawPic (14,40,CHARGINGPIC); + guncount = 0; + } + if ( gunstate == charging && (guncount+=tics) > GUNCHARGE) + { + PlaySound(MAXPOWERSND); + gunstate = maxpower; + DrawPic (14,40,MAXPOWERPIC); + } + } + else + // button up + if (gunstate>ready) // fire small shot if charging, large if maxed + { + DrawPic (14,40,REARMINGPIC); + guncount = 0; + SpawnShot (obon.x,obon.y,obon.angle,pshotobj+(gunstate-charging)); + gunstate = rearming; + PlaySound (FIRESND); + } +} + + +/* +=================== += += DamagePlayer += +=================== +*/ + +void DamagePlayer (void) +{ + PlaySound (TAKEDAMAGESND); + if (!godmode && !--objlist[0].hitpoints) + { + PlaySound(PLAYERDEADSND); + while (SoundPlaying()) + ; + leveldone = -1; // all hit points gone + } + else + DrawPic (24,36,SHIELDLOWPIC+1-objlist[0].hitpoints); + ColorBorder(12); + bordertime = 60; +} + +void HealPlayer (void) +{ + PlaySound (ARMORUPSND); + if (objlist[0].hitpoints<3) + objlist[0].hitpoints++; + DrawPic (24,36,SHIELDLOWPIC+1-objlist[0].hitpoints); + ColorBorder(9); + bordertime = 60; +} + + +/* +=================== += += Thrust += +=================== +*/ + +void Thrust (void) +{ + xmove = FixedByFrac(PLAYERTHRUST*tics,costable[obon.angle]); + ymove = FixedByFrac(PLAYERTHRUST*tics,sintable[obon.angle])^SIGNBIT; + ClipMove(); +} + + +/* +=================== += += Reverse += +=================== +*/ + +void Reverse (void) +{ + xmove = FixedByFrac(PLAYERREVERSE*tics,costable[obon.angle])^SIGNBIT; + ymove = FixedByFrac(PLAYERREVERSE*tics,sintable[obon.angle]); + ClipMove(); +} + + +/* +=================== += += AfterBurn += +=================== +*/ + +void AfterBurn (void) +{ + xmove = FixedByFrac(PLAYERAFTERBURN*tics,costable[obon.angle]); + ymove = FixedByFrac(PLAYERAFTERBURN*tics,sintable[obon.angle])^SIGNBIT; + ClipMove(); + if (!SoundPlaying()) + PlaySound(AFTERBURNSND); +} + +void BeforeBurn (void) +{ + xmove = FixedByFrac(PLAYERAFTERBURN*tics,costable[obon.angle]^SIGNBIT); + ymove = FixedByFrac(PLAYERAFTERBURN*tics,sintable[obon.angle]); + ClipMove(); + if (!SoundPlaying()) + PlaySound(AFTERBURNSND); +} + + +/* +=================== += += PlayerThink += +=================== +*/ + +void PlayerThink (void) +{ + int anglechange; + objtype *check; + + if (c.button1) // hold down fire for slow adjust + { + if (tics<=4) + { + anglechange = ANGLESTEP*tics/2; + if (!anglechange) + anglechange=1; + } + else + anglechange = ANGLESTEP*2; + } + else + anglechange = ANGLESTEP*tics; + + if (c.dir==west || c.dir==northwest || c.dir==southwest) + { + obon.angle+=anglechange; + + if ( obon.angle >= ANGLES ) + obon.angle -= ANGLES; + } + else if (c.dir==east || c.dir==northeast || c.dir==southeast) + { + obon.angle-=anglechange; + + if ( obon.angle < 0) + obon.angle += ANGLES; + } + + if (c.button2 && (c.dir==south || c.dir==southeast || c.dir==southwest) ) + BeforeBurn(); + else if (c.button2) + AfterBurn(); + else if (c.dir==north || c.dir==northeast || c.dir==northwest) + Thrust(); + else if (c.dir==south || c.dir==southeast || c.dir==southwest) + Reverse(); + + CheckFire (); + + for (check = &objlist[1];check<=lastobj;check++) + if + (check->class + && check->xl <= obon.xh + && check->xh >= obon.xl + && check->yl <= obon.yh + && check->yh >= obon.yl) + { + switch (check->class) + { + case refugeeobj: + GetRefugee (check); + break; + + case shieldobj: + objlist[0] = obon; + HealPlayer (); + obon = objlist[0]; + check->class = nothing; + if (check->radarx) + XPlot (check->radarx,check->radary,check->radarcolor); + break; + + case warpobj: + leveldone = 1; + break; + } + } + + StartView(); // calculate view position and trace walls + // FinishView in PlayLoop draws everything +} + + +/* +============================================================================= + + SHOTS + +============================================================================= +*/ + +/* +==================== += += SpawnShot += +==================== +*/ + +void SpawnShot (fixed gx, fixed gy, int angle, classtype class) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = angle; + new->think = ShotThink; + new->class = class; + new->size = TILEGLOBAL/8; + switch (class) + { + case pshotobj: + new->shapenum = PSHOTPIC; + new->speed = SHOTSPEED; + break; + case pbigshotobj: + new->shapenum = BIGSHOTPIC; + new->speed = SHOTSPEED; + break; + case mshotobj: + new->shapenum = MSHOTPIC; + new->speed = MSHOTSPEED; + break; + } + CalcBoundsNew(); +} + + +/* +=================== += += ExplodeShot += +=================== +*/ + +void ExplodeShot(void) +{ + PlaySound (SHOOTWALLSND); + obon.class = inertobj; + obon.shapenum = obon.temp1 = SHOTDIE1PIC; + obon.think = ExplodeThink; + obon.stage = 0; + TransformObon(); +} + + +/* +==================== += += ClipPointMove += +==================== +*/ + +#define SHOTCLIP 0x1000 // explode 1/16th tile from wall + +int ClipPointMove (void) +{ + int xt,yt; + long xclipdist,yclipdist,intersect,basex,basey; + unsigned inside,total; + + xmove = FixedByFrac(obon.speed*tics,costable[obon.angle]); + if (xmove<0) + xmove=-(xmove^SIGNBIT); + ymove = FixedByFrac(obon.speed*tics,sintable[obon.angle])^SIGNBIT; + if (ymove<0) + ymove=-(ymove^SIGNBIT); + + obon.x += xmove; + obon.y += ymove; + + xt = obon.x>>TILESHIFT; + yt = obon.y>>TILESHIFT; + if (!tilemap[xt][yt]) + return 0; + +// +// intersect the path with the tile edges to determine point of impact +// + basex = obon.x & 0xffff0000; + basey = obon.y & 0xffff0000; + obon.x &= 0xffff; // move origin to ul corner of tile + obon.y &= 0xffff; + + if (xmove>0) + { + inside = obon.x; + total = xmove; + intersect = obon.y - ymove*inside/total; + if (intersect <= TILEGLOBAL) + { + obon.x = basex - SHOTCLIP; + obon.y = basey + intersect; + return 1; + } + } + else if (xmove<0) + { + inside = TILEGLOBAL-obon.x; + total = -xmove; + intersect = obon.y - ymove*inside/total; + if (intersect <= TILEGLOBAL) + { + obon.x = basex + TILEGLOBAL + SHOTCLIP; + obon.y = basey + intersect; + return 1; + } + } + + if (ymove>0) + { + inside = obon.y; + total = ymove; + intersect = obon.x - xmove*inside/total; + if (intersect <= TILEGLOBAL) + { + obon.x = basex + intersect; + obon.y = basey - SHOTCLIP; + return 1; + } + } + else if (ymove < 0) + { + inside = TILEGLOBAL-obon.y; + total = -ymove; + intersect = obon.x - xmove*inside/total; + if (intersect <= TILEGLOBAL) + { + obon.x = basex + intersect; + obon.y = basey + TILEGLOBAL + SHOTCLIP; + return 1; + } + } + + return 1; +} + + +/* +=================== += += ShotThink += +=================== +*/ + +void ShotThink (void) +{ + int i,xt,yt; + + objtype *check; + + for (i=0;i<3;i++) // so it can move over one tile distance + { + if (ClipPointMove()) + { + ExplodeShot(); + return; + } + + CalcBounds(); + + for (check = &objlist[0];check<=lastobj;check++) + if + (check->class + && check->xl <= obon.xh + && check->xh >= obon.xl + && check->yl <= obon.yh + && check->yh >= obon.yl) + { + switch (check->class) + { + case playerobj: + if (obon.class == mshotobj) + { + DamagePlayer (); + obon.class = nothing; + return; + } + break; + + case refugeeobj: + KillRefugee (check); + if (obon.class == pbigshotobj) + break; + obon.class = nothing; + return; + + case mutantobj: + KillMutant (check); + if (obon.class == pbigshotobj) + break; + obon.class = nothing; + return; + + case tankobj: + if (obon.class != mshotobj) + { + KillTank (check); + if (obon.class == pbigshotobj) + break; + obon.class = nothing; + return; + } + break; + + case droneobj: + KillDrone (check); + if (obon.class == pbigshotobj) + break; + obon.class = nothing; + return; + } + } + + } + + TransformObon(); +} + + +/* +================== += += InertThink += += Corpses, etc... += +================== +*/ + +void InertThink (void) +{ + TransformObon(); +} + + +/* +=================== += += ExplodeThink += +=================== +*/ + +void ExplodeThink (void) +{ + obon.ticcount+=tics; + if (obon.ticcount>EXPLODEANM) + { + obon.ticcount -= EXPLODEANM; + if (++obon.stage == 5) + { + if (obon.temp1 == SHOTDIE1PIC) // shopt explosions go away + obon.class = nothing; + else + obon.think = InertThink; + return; + } + obon.shapenum = obon.temp1 + obon.stage; + } + + TransformObon(); +} + + +/* +============================================================================= + + WARP GATE + +============================================================================= +*/ + +/* +================== += += SpawnWarp += +================== +*/ + +void SpawnWarp (fixed gx, fixed gy) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = WarpThink; + new->class = warpobj; + new->size = MINDIST; + new->radarcolor = 14; + new->shapenum = WARP1PIC; + CalcBoundsNew(); +} + + +/* +=================== += += WarpThink += +=================== +*/ + +void WarpThink (void) +{ + obon.ticcount+=tics; + if (obon.ticcount>WARPANM) + { + obon.ticcount -= WARPANM; + if (++obon.stage == 4) + obon.stage = 0; + obon.shapenum = WARP1PIC + obon.stage; + } + + TransformObon(); +} + + + +/* +============================================================================= + + REFUGEE + +============================================================================= +*/ + +/* +================== += += SpawnRefugee += += obon.temp2 is true if a drone is seeking it += +================== +*/ + +void SpawnRefugee (fixed gx, fixed gy,int sex) +{ + numrefugees++; + + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = RefugeeThink; + new->class = refugeeobj; + new->size = TILEGLOBAL/3; + new->radarcolor = 15; + if (sex) + { + new->shapenum = MAN1PIC; + new->temp1 = MAN1PIC; + } + else + { + new->shapenum = WOMAN1PIC; + new->temp1 = WOMAN1PIC; + } + new->temp2 = 0; + new->ticcount = Rnd(REFUGEEANM*3); + CalcBoundsNew(); +} + + + +/* +=================== += += KillRefugee += +=================== +*/ + +void KillRefugee (objtype *hit) +{ + PlaySound (HOSTAGEDEADSND); + if (hit->radarx) + XPlot (hit->radarx,hit->radary,hit->radarcolor); + killedcount++; + DrawPic (2*(totalrefugees-killedcount)+1,6,DEADGUYPIC); + if (!--numrefugees) + { + PlaySound (WARPGATESND); + SpawnWarp (warpx,warpy); + } + + hit->radarcolor = 0; + hit->class = inertobj; + if (hit->temp1 == MAN1PIC) + hit->shapenum = hit->temp1 = MANDIE1PIC; + else + hit->shapenum = hit->temp1 = WOMANDIE1PIC; + hit->think = ExplodeThink; + hit->stage = hit->ticcount = 0; +} + + + +/* +=================== += += RefugeeThink += +=================== +*/ + +void RefugeeThink (void) +{ + obon.ticcount+=tics; + if (obon.ticcount>REFUGEEANM) + { + obon.ticcount -= REFUGEEANM; + if (++obon.stage == 2) + obon.stage = 0; + obon.shapenum = obon.temp1 + obon.stage; + } + + TransformObon(); +} + + +/* +============================================================================= + + DRONE + +============================================================================= +*/ + + + +/* +================== += += SpawnDrone += += obon.temp1 is a pointer to the refugee the drone is currently seeking += +================== +*/ + +void SpawnDrone (fixed gx, fixed gy) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = DroneThink; + new->class = droneobj; + new->size = MINDIST; + new->radarcolor = 10; + new->hitpoints = 2; + new->shapenum = DRONE1PIC; + new->ticcount = Rnd(DRONEANM*3); + new->temp1 = (int)new; // will hunt first think + CalcBoundsNew(); +} + + +/* +=================== += += KillDrone += +=================== +*/ + +void KillDrone (objtype *hit) +{ + PlaySound (SHOOTTHINGSND); + if (hit->radarx) + XPlot (hit->radarx,hit->radary,hit->radarcolor); + + hit->radarcolor = 0; + hit->class = inertobj; + hit->shapenum = hit->temp1 = DRONEDIE1PIC; + hit->think = ExplodeThink; + hit->stage = hit->ticcount = 0; +} + + + +/* +================== += += DroneLockOn += +================== +*/ + +void DroneLockOn (void) +{ + objtype *check; + + for (check=&objlist[2];checkclass == refugeeobj && !check->temp2) + { + check->temp2++; + obon.temp1 = (int)check; + return; + } + + obon.temp1 = (int)&objlist[0]; // go after player last +} + +/* +=================== += += DroneThink += +=================== +*/ + +void DroneThink (void) +{ + if ( ((objtype *)obon.temp1)->class != refugeeobj && + ((objtype *)obon.temp1)->class != playerobj) + DroneLockOn (); // target died + + obon.ticcount+=tics; + if (obon.ticcount>DRONEANM) + { + obon.ticcount -= DRONEANM; + if (++obon.stage == 4) + obon.stage = 0; + obon.shapenum = DRONE1PIC + obon.stage; + } + + ChaseThing ((objtype *)obon.temp1); + + CalcBounds (); + + TransformObon(); + + for (check = &objlist[0];check<=lastobj;check++) + if + (check->class + && check->xl <= obon.xh + && check->xh >= obon.xl + && check->yl <= obon.yh + && check->yh >= obon.yl) + { + switch (check->class) + { + case playerobj: // kill player and blow up + DamagePlayer (); + PlaySound (SHOOTTHINGSND); + if (obon.radarx) + XPlot (obon.radarx,obon.radary,obon.radarcolor); + + obon.radarcolor = 0; + obon.class = inertobj; + obon.shapenum = obon.temp1 = DRONEDIE1PIC; + obon.think = ExplodeThink; + obon.stage = obon.ticcount = 0; + return; + + case refugeeobj: + KillRefugee (check); + break; + } + } +} + + +/* +============================================================================= + + TANK + +============================================================================= +*/ + + +/* +================== += += SpawnTank += +================== +*/ + +void SpawnTank (fixed gx, fixed gy) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = TankThink; + new->class = tankobj; + new->size = MINDIST; + new->shapenum = TANK1PIC; + new->radarcolor = 13; + new->hitpoints = 3; + CalcBoundsNew(); +} + + +/* +=================== += += KillTank += +=================== +*/ + +void KillTank (objtype *hit) +{ + PlaySound (SHOOTTHINGSND); + if (hit->radarx) + XPlot (hit->radarx,hit->radary,hit->radarcolor); + + hit->radarcolor = 0; + hit->class = inertobj; + hit->shapenum = hit->temp1 = TANKDIE1PIC; + hit->think = ExplodeThink; + hit->stage = hit->ticcount = 0; +} + + +/* +====================== += += AimAtPlayer += += Hunt for player += +====================== +*/ + +void AimAtPlayer (void) +{ + long deltax,deltay; + int i,xstep,ystep,tx,ty,steps; + dirtype d[3],tdir, olddir, turnaround; + + olddir=obon.dir; + turnaround=opposite[olddir]; + + deltax=objlist[0].x-obon.x; + deltay=objlist[0].y-obon.y; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>MINCHASE) + d[1]= east; + else if (deltax<-MINCHASE) + d[1]= west; + if (deltay>MINCHASE) + d[2]=south; + else if (deltay<-MINCHASE) + d[2]=north; + + if (LABS(deltay)MINCHASE) + { + xstep = 1; + steps = ((objlist[0].x - obon.x)>>TILESHIFT)-1; + obon.angle = 0; + } + else if (deltax<-MINCHASE) + { + xstep = -1; + steps = ((obon.x - objlist[0].x)>>TILESHIFT)-1; + obon.angle = 180; + } + if (deltay>MINCHASE) + { + ystep = 1; + steps = ((objlist[0].y - obon.y)>>TILESHIFT)-1; + obon.angle = 270; + } + else if (deltay<-MINCHASE) + { + ystep = -1; + steps = ((obon.y - objlist[0].y)>>TILESHIFT)-1; + obon.angle = 90; + } + + tx = obon.x >> TILESHIFT; + ty = obon.y >> TILESHIFT; + + for (i=0;i128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir+=2) + if (tdir!=turnaround) + { + obon.dir=tdir; + if (Walk()) + return; + } + } + else + { + for (tdir=west;tdir>=north;tdir-=2) + if (tdir!=turnaround) + { + obon.dir=tdir; + if (Walk()) + return; + } + } + + obon.dir=turnaround; + Walk(); // last chance, don't worry about returned value +} + + +/* +=================== += += TankThink += +=================== +*/ + +void TankThink (void) +{ + if (obon.stage == 1) // just fired? + { + if ( (obon.ticcount += tics) >= TANKRELOAD) + obon.stage = 0; + } + + AimAtPlayer (); + TransformObon(); +} + + +/* +============================================================================= + + MUTANT + +============================================================================= +*/ + + +/* +================== += += SpawnMutant += +================== +*/ + +void SpawnMutant (fixed gx, fixed gy) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = MutantThink; + new->class = mutantobj; + new->size = MINDIST; + new->shapenum = MUTANT1PIC; + new->radarcolor = 12; + new->hitpoints = 1; + new->ticcount = Rnd(MUTANTANM*3); + CalcBoundsNew(); +} + + + +/* +=================== += += KillMutant += +=================== +*/ + +void KillMutant (objtype *hit) +{ + PlaySound (SHOOTTHINGSND); + if (hit->radarx) + XPlot (hit->radarx,hit->radary,hit->radarcolor); + + hit->radarcolor = 0; + hit->class = inertobj; + hit->shapenum = hit->temp1 = MUTANTDIE1PIC; + hit->think = ExplodeThink; + hit->stage = hit->ticcount = 0; +} + + + +/* +====================== += += Walk += += Returns true if a movement of obon.dir/obon.speed is ok or causes += an attack at player += +====================== +*/ + +#define WALLZONE (2*TILEGLOBAL/3) + +int Walk (void) +{ + int xmove,ymove,xl,yl,xh,yh,xt,yt; + + switch (obon.dir) + { + case north: + xmove = 0; + ymove = -SPDMUTANT; + break; + case east: + xmove = SPDMUTANT; + ymove = 0; + break; + case south: + xmove = 0; + ymove = SPDMUTANT; + break; + case west: + xmove = -SPDMUTANT; + ymove = 0; + break; + + default: + Quit ("Walk: Bad dir!"); + } + + obon.x += xmove; + obon.y += ymove; + +// +// calculate a hit rect to stay away from walls in +// + obon.xl = obon.x - WALLZONE; + obon.xh = obon.x + WALLZONE; + obon.yl = obon.y - WALLZONE; + obon.yh = obon.y + WALLZONE; + +// +// tile coordinate edges +// + xt = obon.x>>TILESHIFT; + yt = obon.y>>TILESHIFT; + + xl = obon.xl>>TILESHIFT; + yl = obon.yl>>TILESHIFT; + + xh = obon.xh>>TILESHIFT; + yh = obon.yh>>TILESHIFT; + +// +// check corners +// + if (tilemap[xl][yl] || tilemap[xh][yl] + || tilemap[xl][yh] || tilemap[xh][yh] + || tilemap[xt][yh] || tilemap[xt][yl] + || tilemap[xl][yt] || tilemap[xh][yt] ) + { + obon.x -= xmove; + obon.y -= ymove; + return 0; + } + +// +// check contact with player +// + + return 1; +} + + + +/* +====================== += += ChaseThing += += Hunt for player += +====================== +*/ + +void ChaseThing (objtype *chase) +{ + long deltax,deltay; + int i; + dirtype d[3],tdir, olddir, turnaround; + + olddir=obon.dir; + turnaround=opposite[olddir]; + + deltax=chase->x-obon.x; + deltay=chase->y-obon.y; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>MINCHASE) + d[1]= east; + else if (deltax<-MINCHASE) + d[1]= west; + if (deltay>MINCHASE) + d[2]=south; + else if (deltay<-MINCHASE) + d[2]=north; + + if (LABS(deltay)>LABS(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]==turnaround) + d[1]=nodir; + if (d[2]==turnaround) + d[2]=nodir; + + + if (d[1]!=nodir) + { + obon.dir=d[1]; + if (Walk()) + { + if (d[2]!=nodir) + { + obon.dir=d[2]; + Walk(); // try to go diagonal if possible + } + return; + } + } + + if (d[2]!=nodir) + { + obon.dir=d[2]; + if (Walk()) + return; + } + +/* there is no direct path to the player, so pick another direction */ + + obon.dir=olddir; + if (Walk()) + return; + + if (RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir+=2) + if (tdir!=turnaround) + { + obon.dir=tdir; + if (Walk()) + return; + } + } + else + { + for (tdir=west;tdir>=north;tdir-=2) + if (tdir!=turnaround) + { + obon.dir=tdir; + if (Walk()) + return; + } + } + + obon.dir=turnaround; + Walk(); // last chance, don't worry about returned value +} + + +/* +=================== += += MutantThink += +=================== +*/ + +#define ATTACKZONE (TILEGLOBAL) + +void MutantThink (void) +{ + obon.ticcount += tics; + + if (obon.stage==4) // attack stage + { + if (obon.ticcount < MUTANTATTACK) + { + TransformObon(); + return; + } + obon.ticcount = MUTANTANM+1-tics; + obon.stage = 0; + } + + if (obon.ticcount>MUTANTANM) + { + obon.ticcount -= MUTANTANM; + if (++obon.stage == 4) + obon.stage = 0; + obon.shapenum = MUTANT1PIC + obon.stage; + } + + if (objlist[0].xl <= obon.x + ATTACKZONE + && objlist[0].xh >= obon.x - ATTACKZONE + && objlist[0].yl <= obon.y + ATTACKZONE + && objlist[0].yh >= obon.y - ATTACKZONE) + { + obon.stage = 4; + obon.ticcount = 0; + obon.shapenum = MUTANTHITPIC; + DamagePlayer(); + } + else + ChaseThing(&objlist[0]); + + CalcBounds (); + + TransformObon(); + + +} + +/* +============================================================================= + + SHIELD + +============================================================================= +*/ + + +/* +================== += += SpawnShield += +================== +*/ + +void SpawnShield (fixed gx, fixed gy) +{ + FindFreeObj(); + new->x = gx; + new->y = gy; + new->angle = 0; + new->think = ShieldThink; + new->class = shieldobj; + new->size = MINDIST; + new->shapenum = SHIELD1PIC; + new->radarcolor = 9; + new->hitpoints = 3; + CalcBoundsNew(); +} + + +/* +=================== += += ShieldThink += +=================== +*/ + +void ShieldThink (void) +{ + obon.ticcount += tics; + + if (obon.ticcount>SHIELDANM) + { + obon.ticcount -= SHIELDANM; + if (++obon.stage == 2) + obon.stage = 0; + obon.shapenum = SHIELD1PIC + obon.stage; + } + + TransformObon(); +} + + diff --git a/HOVDRAW.C b/HOVDRAW.C new file mode 100644 index 0000000..62b434b --- /dev/null +++ b/HOVDRAW.C @@ -0,0 +1,1156 @@ +/* Hovertank 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "HOVERDEF.H" +#pragma hdrstop + +long bytecount,endcount; // for profiling + +/* +============================================================================ + + 3 - D DEFINITIONS + +============================================================================ +*/ + +fixed tileglobal = TILEGLOBAL; +fixed focallength = FOCALLENGTH; +fixed mindist = MINDIST; +int viewheight = VIEWHEIGHT; +fixed scale; + + +tilept tile,lasttile, // tile of wall being followed + focal, // focal point in tiles + left,mid,right; // rightmost tile in view + +globpt edge,view; + +int segstart[VIEWHEIGHT], // addline tracks line segment and draws + segend[VIEWHEIGHT], + segcolor[VIEWHEIGHT]; // only when the color changes + + +#define ADDLINE(a,b,y,c) \ +{ \ + if (a>segend[y]+1) \ + { \ + if (y>CENTERY) \ + DrawLine(segend[y]+1,a-1,y,8); \ + else \ + DrawLine(segend[y]+1,a-1,y,0); \ + } \ + DrawLine(a,a,y,0); \ + if (a+1<=b) \ + DrawLine(a+1,b,y,c); \ + segend[y]=b; \ +} + + +#define MAXWALLS 100 +#define MIDWALL (MAXWALLS/2) + +walltype walls[MAXWALLS],*leftwall,*rightwall; + + +//========================================================================== + +// +// refresh stuff +// + +// +// calculate location of screens in video memory so they have the +// maximum possible distance seperating them (for scaling overflow) +// + +#define EXTRALINES (0x10000l/SCREENWIDTH-STATUSLINES-VIEWHEIGHT*3) + +unsigned screenloc[3]= +{ + ((STATUSLINES+EXTRALINES/4)*SCREENWIDTH)&0xff00, + ((STATUSLINES+EXTRALINES/2+VIEWHEIGHT)*SCREENWIDTH)&0xff00, + ((STATUSLINES+3*EXTRALINES/4+2*VIEWHEIGHT)*SCREENWIDTH)&0xff00 +}; + +int screenpage,tics; + +long lasttimecount; + +#define SHIFTFRAMES 256 +int yshift[SHIFTFRAMES]; // screen sliding variables +unsigned slideofs; + +// +// rendering stuff +// + +int firstangle,lastangle; + +fixed prestep; + +fixed sintable[ANGLES+ANGLES/4],*costable = sintable+(ANGLES/4); + +fixed viewx,viewy; // the focal point +int viewangle; +fixed viewsin,viewcos; + +int zbuffer[VIEWXH+1]; // holds the height of the wall at that point + +//========================================================================== + +void DrawLine (int xl, int xh, int y,int color); +void DrawWall (walltype *wallptr); +void TraceRay (unsigned angle); +fixed FixedByFrac (fixed a, fixed b); +fixed FixedAdd (fixed a, fixed b); +fixed TransformX (fixed gx, fixed gy); +int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max); +int BackTrace (int finish); +void ForwardTrace (void); +int TurnClockwise (void); +int TurnCounterClockwise (void); +void FollowWall (void); + +void NewScene (void); +void BuildTables (void); + +//========================================================================== + + +/* +================== += += DrawLine += += Must be in write mode 2 with all planes enabled += The bit mask is left set to the end value, so clear it after all lines are += drawn += +================== +*/ + +unsigned char leftmask[8] = {0xff,0x7f,0x3f,0x1f,0xf,7,3,1}; +unsigned char rightmask[8] = {0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; + +void DrawLine (int xl, int xh, int y,int color) +{ + unsigned dest,xlb,xhb,maskleft,maskright,mid; + + xlb=xl/8; + xhb=xh/8; + + if (xhVIEWYH) + Quit("DrawLine: y>VIEWYH"); + + maskleft = leftmask[xl&7]; + maskright = rightmask[xh&7]; + + mid = xhb-xlb-1; + dest = screenofs+ylookup[y]+xlb; + + if (xlb==xhb) + { + // + // entire line is in one byte + // + + maskleft&=maskright; + + asm mov es,[screenseg] + asm mov di,[dest] + asm mov dx,GC_INDEX + + asm mov al,GC_BITMASK + asm mov ah,[BYTE PTR maskleft] + asm out dx,ax // mask off pixels + + asm mov al,[BYTE PTR color] + asm xchg al,[es:di] // load latches and write pixels + + return; + } + +asm mov es,[screenseg] +asm mov di,[dest] +asm mov dx,GC_INDEX +asm mov bh,[BYTE PTR color] + +// +// draw left side +// +asm mov al,GC_BITMASK +asm mov ah,[BYTE PTR maskleft] +asm out dx,ax // mask off pixels + +asm mov al,bh +asm mov bl,[es:di] // load latches +asm stosb + +// +// draw middle +// +asm mov ax,GC_BITMASK + 255*256 +asm out dx,ax // no masking + +asm mov al,bh +asm mov cx,[mid] +asm rep stosb + +// +// draw right side +// +asm mov al,GC_BITMASK +asm mov ah,[BYTE PTR maskright] +asm out dx,ax // mask off pixels + +asm xchg bh,[es:di] // load latches and write pixels + +} + +//========================================================================== + + +/* +=================== += += DrawWall += += Special polygon with vertical edges and symetrical top / bottom += Clips horizontally to clipleft/clipright += Clips vertically to VIEWY/VIEWYH += Should only be called if the wall is at least partially visable += +================== +*/ + +void DrawWall (walltype *wallptr) +{ + walltype static wall; + int static y1l,y1h,y2l,y2h; + + int i; + unsigned leftheight,rightheight; + long height,heightstep; + + + int temp,insight,x,y,slope,endfrac,end; + int start,ysteps,left,right; + + + wall = *wallptr; + i = wall.height1/2; + y1l = CENTERY-i; + y1h = CENTERY+i; + i = wall.height2/2; + y2l = CENTERY-i; + y2h = CENTERY+i; + + if (wall.x1>wall.leftclip) + wall.leftclip = wall.x1; + if (wall.x2>16; + height+=heightstep; + } + +// +// draw the wall to the line buffer +// + + if (y1l==y2l) + { + // + // rectangle, no slope + // + if (y1lVIEWYH) + y1h=VIEWYH; + for (y=y1l;y<=y1h;y++) + ADDLINE(wall.leftclip,wall.rightclip,y,wall.color); + return; + } + + + + if (y1l>6; + if (end>wall.rightclip) + end=wall.rightclip; + else + if (end