aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Mandel <richard@tech-transfer.com>2014-06-04 16:15:52 -0400
committerRichard Mandel <richard@tech-transfer.com>2014-06-04 16:15:52 -0400
commit86f6b5ed34c52d2ca8acbb26391ebd5b2542f1fa (patch)
tree35c05fcd035424ef5772112b58cb622fe5f61867
downloadhovertank3d-master.tar.gz
hovertank3d-master.tar.bz2
hovertank3d-master.zip
Hovertank 3D open source release.HEADmaster
-rw-r--r--COPYING339
-rw-r--r--GRAPHHOV.EQU145
-rw-r--r--GRAPHHOV.H146
-rw-r--r--HMAIN.C1368
-rw-r--r--HOVACTS.C1550
-rw-r--r--HOVDRAW.C1156
-rw-r--r--HOVER.DSKbin0 -> 972 bytes
-rw-r--r--HOVER.PRJbin0 -> 7271 bytes
-rw-r--r--HOVERDEF.H271
-rw-r--r--HOVLOOP.C1085
-rw-r--r--HOVMAIN.C1408
-rw-r--r--HOVSCALE.C530
-rw-r--r--HOVTEXT.C196
-rw-r--r--HOVTRACE.C822
-rw-r--r--IDASM.ASM1378
-rw-r--r--IDASME.ASM1653
-rw-r--r--IDLIB.H494
-rw-r--r--IDLIBC.ASM8172
-rw-r--r--IDLIBC.C2288
-rw-r--r--JM.H34
-rw-r--r--JM_SB.ASM1176
-rw-r--r--JM_SB.C317
-rw-r--r--JM_SB.H57
-rw-r--r--MEMMGR.ASM2405
-rw-r--r--MEMMGR.C794
-rw-r--r--MEMMGR.H43
-rw-r--r--OLDASM.ASM660
-rw-r--r--README11
-rw-r--r--SNDSHOV.H42
-rw-r--r--TDCONFIG.TDbin0 -> 1316 bytes
30 files changed, 28540 insertions, 0 deletions
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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT 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.
+
+ <signature of Ty Coon>, 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 ("<MORE>");
+ 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 ("<MORE>");
+ 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<NUMCHUNKS;i++)
+ if (grsegs[i] && !needgr[i])
+ MMSetPurge(&grsegs[i],3);
+
+ MMSortMem();
+
+//
+// load new stuff
+//
+ lseek(grhandle,0,SEEK_SET);
+ filepos = 0;
+
+ for (i=0;i<NUMCHUNKS;i++)
+ if (!grsegs[i] && needgr[i])
+ {
+ newpos = grstarts[i];
+ if (newpos!=filepos)
+ lseek(grhandle,newpos-filepos,SEEK_CUR);
+
+ compressed = grstarts[i+1]-grstarts[i]-4;
+
+ if (i>=STARTTILE8)
+ {
+ //
+ // tiles are of a known size
+ //
+ if (i<STARTTILE8M) // tile 8s are all in one chunk!
+ expanded = BLOCK*NUMTILE8;
+ else if (i<STARTTILE16)
+ expanded = MASKBLOCK*NUMTILE8M;
+ else if (i<STARTTILE16M) // all other tiles are one/chunk
+ expanded = BLOCK*4;
+ else if (i<STARTTILE32)
+ expanded = MASKBLOCK*4;
+ else if (i<STARTTILE32M)
+ expanded = BLOCK*16;
+ else
+ expanded = MASKBLOCK*16;
+
+ compressed = grstarts[i+1]-grstarts[i];
+ }
+ else
+ {
+ //
+ // other things have a length header at start of chunk
+ //
+ read(grhandle,&expanded,sizeof(expanded));
+ compressed = grstarts[i+1]-grstarts[i]-4;
+ }
+
+ //
+ // allocate space for expanded chunk
+ //
+ MMGetPtr(&grsegs[i],expanded);
+
+ //
+ // if the entire compressed length can't fit in the general purpose
+ // buffer, allocate a temporary memory block for it
+ //
+ if (compressed<=BUFFERSIZE)
+ {
+ SegRead(grhandle,bufferseg,compressed);
+ HuffExpand (bufferseg, grsegs[i], expanded,grhuffman);
+ }
+ else
+ {
+ MMGetPtr(&bigbufferseg,compressed);
+ SegRead(grhandle,bigbufferseg,compressed);
+ HuffExpand (bigbufferseg, grsegs[i], expanded,grhuffman);
+ MMFreePtr(&bigbufferseg);
+ }
+
+ filepos = grstarts[i+1]; // file pointer is now at start of next one
+ }
+
+}
+
+//==========================================================================
+
+
+/*
+=====================
+=
+= CachePic
+=
+= Make sure a graphic chunk is in memory
+=
+=====================
+*/
+
+void CachePic (int picnum)
+{
+ long expanded,compressed; // chunk lengths
+ memptr bigbufferseg; // for compressed
+
+ if (grsegs[picnum])
+ return;
+
+ lseek(grhandle,grstarts[picnum],SEEK_SET);
+
+ compressed = grstarts[picnum+1]-grstarts[picnum]-4;
+
+ if (picnum>=STARTTILE8)
+ {
+ //
+ // tiles are of a known size
+ //
+ if (picnum<STARTTILE8M) // tile 8s are all in one chunk!
+ expanded = BLOCK*NUMTILE8;
+ else if (picnum<STARTTILE16)
+ expanded = MASKBLOCK*NUMTILE8M;
+ else if (picnum<STARTTILE16M) // all other tiles are one/chunk
+ expanded = BLOCK*4;
+ else if (picnum<STARTTILE32)
+ expanded = MASKBLOCK*4;
+ else if (picnum<STARTTILE32M)
+ expanded = BLOCK*16;
+ else
+ expanded = MASKBLOCK*16;
+
+ compressed = grstarts[picnum+1]-grstarts[picnum];
+ }
+ else
+ {
+ //
+ // other things have a length header at start of chunk
+ //
+ read(grhandle,&expanded,sizeof(expanded));
+ compressed = grstarts[picnum+1]-grstarts[picnum]-4;
+ }
+
+ //
+ // allocate space for expanded chunk
+ //
+ MMGetPtr(&grsegs[picnum],expanded);
+
+ MMGetPtr(&bigbufferseg,compressed);
+ SegRead(grhandle,bigbufferseg,compressed);
+ HuffExpand (bigbufferseg, grsegs[picnum], expanded,grhuffman);
+ MMFreePtr(&bigbufferseg);
+}
+
+//==========================================================================
+
+void PatchPointers (void)
+{
+ fontseg = grsegs[STARTFONT];
+
+}
+
+//==========================================================================
+
+/*
+=====================
+==
+== Quit
+==
+=====================
+*/
+
+void Quit (char *error)
+{
+//char extern far PIRACY;
+
+ if (!(*error))
+ {
+ SaveCtrls ();
+ }
+
+ if (KBDstarted)
+ ShutdownKbd (); // shut down the interrupt driven stuff if needed
+ if (SNDstarted)
+ ShutdownSound ();
+ if (soundblaster)
+ jmShutSB ();
+
+ if (grhandle>0)
+ 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;y<levelheader->height;y++)
+ for (x=0;x<levelheader->width;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 (f<NUMFRAMES)
+ {
+ f+=inttime;
+ if (f>NUMFRAMES)
+ 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;i<DASHPIC;i++)
+ {
+ CachePic (STARTPICS+i);
+ SC_MakeShape(
+ grsegs[STARTPICS+i],
+ pictable[i].width,
+ pictable[i].height,
+ &scalesegs[i]);
+ MMFreePtr (&grsegs[STARTPICS+i]);
+ }
+
+//
+// load the basic graphics
+//
+
+ needgr[STARTFONT] = 1;
+ needgr[STARTTILE8] = 1;
+
+ for (i=DASHPIC;i<ENDPIC;i++)
+ needgr[STARTPICS+i]=1;
+
+ CacheGrFile (); // load all graphics now (no caching)
+
+ fontseg = grsegs[STARTFONT];
+}
+
+//==========================================================================
+
+//////////////////////////////////////////////////////
+//
+// Hardware Error Handler - called only by MS-DOS
+//
+//////////////////////////////////////////////////////
+
+#define IGNORE 0
+#define RETRY 1
+#define ABORT 2
+
+int ErrorHandler(int errval,int ax,int bx,int si)
+{
+ unsigned key;
+
+ key=ax+bx+si+errval;
+
+// screenofs=screenorigin=0;
+// SetScreen(0,0);
+ CenterWindow(32,3);
+ py++;
+ CPPrint("Disk I/O error! Press ENTER to\n");
+ CPPrint("resume, or ESC to abort:");
+ SetNormalPalette();
+
+ ClearKeys();
+
+ do{
+ key=(PGet()&0xff);
+ } while(key!=27 && key!=13);
+
+ if (key!=27)
+ hardresume(RETRY);
+
+ _AX = 3;
+ geninterrupt (0x10); // text mode
+
+ if (KBDstarted)
+ ShutdownKbd (); // shut down the interrupt driven stuff if needed
+ if (SNDstarted)
+ ShutdownSound ();
+
+ return ABORT;
+}
+
+
+
+/*=========================================================================*/
+
+////////////////////////////////////////////////////////////
+//
+// Allocate memory and load file in
+//
+////////////////////////////////////////////////////////////
+void LoadIn(char *filename,char huge **baseptr)
+{
+ int handle;
+ long len;
+ unsigned datapage;
+
+
+ if ((handle=open(filename,O_BINARY))==-1)
+ {
+ printf("Error loading file '%s'!\n",filename);
+ exit(1);
+ }
+
+ len=filelength(handle);
+ *baseptr=(char huge *)farmalloc(len);
+
+ LoadFile(filename,*baseptr);
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// US_CheckParm() - checks to see if a string matches one of a set of
+// strings. The check is case insensitive. The routine returns the
+// index of the string that matched, or -1 if no matches were found
+//
+///////////////////////////////////////////////////////////////////////////
+int
+US_CheckParm(char *parm,char **strings)
+{
+ char cp,cs,
+ *p,*s;
+ int i;
+
+ while (!isalpha(*parm)) // Skip non-alphas
+ parm++;
+
+ for (i = 0;*strings && **strings;i++)
+ {
+ for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)
+ {
+ cs = *s++;
+ if (!cs)
+ return(i);
+ cp = *p++;
+
+ if (isupper(cs))
+ cs = tolower(cs);
+ if (isupper(cp))
+ cp = tolower(cp);
+ }
+ }
+ return(-1);
+}
+///////////////////////////////////////////////////////////////////////////
+
+/*
+=================
+=
+= main
+=
+=================
+*/
+
+static char *EntryParmStrings[] = {"detour",0};
+
+void main(void)
+{
+ int i,x,xl,xh,y,plane,size;
+ SampledSound huge *samples;
+
+ boolean LaunchedFromShell = false;
+
+ if (stricmp(_argv[1], "/VER") == 0)
+ {
+ printf("HOVER TANK\n");
+ printf("Copyright 1992 Softdisk Publishing\n");
+ printf("Version 1.16\n");
+ exit(0);
+ }
+
+ for (i = 1;i < _argc;i++)
+ {
+ switch (US_CheckParm(_argv[i],EntryParmStrings))
+ {
+ case 0:
+ LaunchedFromShell = true;
+ break;
+ }
+ }
+
+ if (!LaunchedFromShell)
+ {
+ clrscr();
+ puts("You must type START at the DOS prompt to run HOVER TANK.");
+ exit(0);
+ }
+
+
+// puts("Hover Tank is executing...");
+
+//
+// detect video
+//
+ videocard = VideoID ();
+
+ if (videocard == EGAcard) {}
+// puts ("EGA card detected");
+ else if (videocard == VGAcard) {}
+// puts ("VGA card detected");
+ else
+ {
+ puts ("Hey, I don't see an EGA or VGA card here! Do you want to run the program ");
+ puts ("anyway (Y = go ahead, N = quit to dos) ?");
+ ClearKeys ();
+ i = toupper(bioskey(0) & 0xff);
+ if (i!='Y')
+ exit (1);
+ }
+
+ grmode = EGAgr;
+
+//
+// setup for sound blaster
+//
+ if (_argc == 1) // command line override
+ soundblaster = jmDetectSoundBlaster(-1);
+ else
+ soundblaster = 0;
+
+ if (soundblaster)
+ {
+// puts ("Sound Blaster detected! (HOVER NOBLASTER to void detection)");
+ LoadIn ("DSOUND.HOV",&(char huge *)samples);
+ jmStartSB ();
+ jmSetSamplePtr (samples);
+ }
+ else
+// puts ("Sound Blaster not detected");
+
+
+ LoadNearData (); // load some stuff before starting the memory manager
+
+ MMStartup ();
+ MMGetPtr(&bufferseg,BUFFERSIZE); // small general purpose buffer
+
+ BloadinMM ("SOUNDS."EXTENSION,&soundseg);
+
+ harderr(ErrorHandler); // critical error handler
+
+#ifdef ADAPTIVE
+ timerspeed = 0x2147; // 140 ints / second (2/VBL)
+ StartupSound (); // interrupt handlers that must be removed at quit
+ SNDstarted = 1;
+#endif
+
+ StartupKbd ();
+ KBDstarted = 1;
+
+ SetupGraphics ();
+
+ InitRndT (1); // setup random routines
+ InitRnd (1);
+
+ LoadCtrls ();
+
+ puts ("Calculating...");
+ BuildTables();
+ SC_Setup();
+
+ SetScreenMode(grmode);
+ SetLineWidth (SCREENWIDTH);
+
+ screencenterx=19;
+ screencentery=12;
+
+#if !(defined (PROFILE) || defined (TESTCASE))
+ if (!keydown[1]) // hold ESC to bypass intro
+ Intro ();
+#endif
+
+#ifdef PROFILE
+JoyXlow[1]=JoyYlow[1]=16;
+JoyXhigh[1]=JoyYhigh[1]=70;
+playermode[1] = joystick1;
+#endif
+
+ while (1)
+ {
+#if !(defined (PROFILE) || defined (TESTCASE))
+ DemoLoop (); // do title, demo, etc
+#endif
+ PlaySound (STARTGAMESND);
+ PlayGame();
+ }
+
+}
+
diff --git a/HOVACTS.C b/HOVACTS.C
new file mode 100644
index 0000000..6926a8b
--- /dev/null
+++ b/HOVACTS.C
@@ -0,0 +1,1550 @@
+/* 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"
+
+//==========================================================================
+
+#define GUNARM 50
+#define GUNCHARGE 70
+
+#define EXPLODEANM 8
+#define SHOTSPEED 8192l
+#define MSHOTSPEED 6000l
+
+#define REFUGEEANM 30
+#define WARPANM 10
+
+#define SPDMUTANT 2500l
+#define MUTANTANM 20
+#define MUTANTATTACK 120
+
+#define SPDDRONE 16384l
+#define DRONEANM 10
+
+#define TANKRELOAD 200
+
+#define ANGLESTEP 1
+#define PLAYERTHRUST 4096l
+#define PLAYERREVERSE 2048l
+#define PLAYERAFTERBURN 8192l
+
+#define SHIELDANM 10
+
+#define MINCHASE 4096
+
+dirtype opposite[9] =
+ {south,southwest,west,northwest,north,northeast,east,southeast,nodir};
+
+
+//==========================================================================
+
+enum {rearming,ready,charging,maxpower} gunstate;
+int guncount;
+
+//==========================================================================
+
+void SpawnPlayer (fixed gx, fixed gy);
+void GetRefugee (objtype *hit);
+void CheckFire (void);
+void DamagePlayer (void);
+void Thrust (void);
+void Reverse (void);
+void AfterBurn (void);
+void PlayerThink (void);
+
+void SpawnShot (fixed gx, fixed gy, int angle, classtype class);
+void ExplodeShot(void);
+int ClipPointMove (void);
+void ShotThink (void);
+void InertThink (void);
+void ExplodeThink (void);
+
+void SpawnWarp (fixed gx, fixed gy);
+void WarpThink (void);
+
+void SpawnRefugee (fixed gx, fixed gy,int sex);
+void KillRefugee (objtype *hit);
+void RefugeeThink (void);
+
+void SpawnDrone (fixed gx, fixed gy);
+void KillDrone (objtype *hit);
+void DroneThink (void);
+
+void SpawnTank (fixed gx, fixed gy);
+void KillTank (objtype *hit);
+void AimAtPlayer (void);
+void TankThink (void);
+
+void SpawnMutant (fixed gx, fixed gy);
+void KillMutant (objtype *hit);
+int Walk (void);
+void ChaseThing (objtype *chase);
+void MutantThink (void);
+
+void SpawnShield (fixed gx, fixed gy);
+void ShieldThink (void);
+
+/*
+=============================================================================
+
+ PLAYER
+
+=============================================================================
+*/
+
+
+/*
+===================
+=
+= SpawnPlayer
+=
+===================
+*/
+
+void SpawnPlayer (fixed gx, fixed gy)
+{
+ objlist[0].x = gx;
+ objlist[0].y = gy;
+ objlist[0].angle = 0;
+ objlist[0].think = PlayerThink;
+ objlist[0].class = playerobj;
+ objlist[0].size = MINDIST;
+ objlist[0].radarcolor = 15;
+ objlist[0].hitpoints = 3;
+
+ objlist[0].xl = objlist[0].x - objlist[0].size;
+ objlist[0].xh = objlist[0].x + objlist[0].size;
+ objlist[0].yl = objlist[0].y - objlist[0].size;
+ objlist[0].yh = objlist[0].y + objlist[0].size;
+
+ gunstate = ready;
+}
+
+
+/*
+===================
+=
+= GetRefugee
+=
+===================
+*/
+
+void GetRefugee (objtype *hit)
+{
+ PlaySound (SAVEHOSTAGESND);
+ hit->class = 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];check<lastobj;check++)
+ if (check->class == 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)<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;
+
+//
+// shoot at player if even aim and not reloading
+//
+ if (d[1]==nodir && !obon.stage)
+ {
+ xstep = ystep = 0;
+
+ if (deltax>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;i<steps;i++)
+ {
+ tx += xstep;
+ ty += ystep;
+ if (tilemap[tx][ty])
+ goto cantshoot; // shot is blocked
+ }
+ PlaySound (FIRESND);
+ SpawnShot (obon.x,obon.y,obon.angle,mshotobj);
+ obon.ticcount = 0;
+ obon.stage = 1;
+ }
+
+
+ if (d[1]!=nodir)
+ {
+ obon.dir=d[1];
+ if (Walk())
+ return;
+ }
+
+cantshoot:
+ 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
+}
+
+
+/*
+===================
+=
+= 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 (xh<xl)
+ Quit("DrawLine: xh<xl");
+ if (y<VIEWY)
+ Quit("DrawLine: y<VIEWY");
+ if (y>VIEWYH)
+ 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<wall.rightclip)
+ wall.rightclip = wall.x2;
+
+//
+// fill in the zbuffer
+//
+ height = (long)wall.height1<<16;
+ if (wall.x2 != wall.x1)
+ heightstep = ((long)(wall.height2-wall.height1)<<16)/(int)(wall.x2-wall.x1);
+ else
+ heightstep = 0;
+
+ i = wall.leftclip-wall.x1;
+ if (i)
+ height += heightstep*i; // adjust for clipped area
+
+ for (x=wall.leftclip;x<=wall.rightclip;x++)
+ {
+ zbuffer[x] = height>>16;
+ height+=heightstep;
+ }
+
+//
+// draw the wall to the line buffer
+//
+
+ if (y1l==y2l)
+ {
+ //
+ // rectangle, no slope
+ //
+ if (y1l<VIEWY)
+ y1l=VIEWY;
+ if (y1h>VIEWYH)
+ y1h=VIEWYH;
+ for (y=y1l;y<=y1h;y++)
+ ADDLINE(wall.leftclip,wall.rightclip,y,wall.color);
+ return;
+ }
+
+
+
+ if (y1l<y2l)
+ {
+ //
+ // slopes down to the right
+ //
+ slope = ((long)(wall.x2-wall.x1)<<6)/(y2l-y1l); // in 128ths
+
+ ysteps = y2l-y1l;
+ if (y1l<VIEWY)
+ ysteps -= VIEWY-y1l;
+ endfrac = wall.x2<<6;
+ for (y=1;y<ysteps;y++) // top and bottom slopes
+ {
+ endfrac-=slope;
+ end=endfrac>>6;
+ if (end>wall.rightclip)
+ end=wall.rightclip;
+ else
+ if (end<wall.leftclip) // the rest is hidden
+ break;
+
+ ADDLINE(wall.leftclip,end,y2l-y,wall.color);
+ ADDLINE(wall.leftclip,end,y2h+y,wall.color);
+ }
+ if (y2l<VIEWY)
+ y2l=VIEWY;
+ if (y2h>VIEWYH)
+ y2h=VIEWYH;
+ for (y=y2l;y<=y2h;y++) // middle
+ ADDLINE(wall.leftclip,wall.rightclip,y,wall.color);
+ }
+ else
+ {
+ //
+ // slopes down to the left
+ //
+ slope = ((long)(wall.x2-wall.x1)<<6)/(y1l-y2l); // in 128ths
+
+ ysteps = y1l-y2l;
+ if (y2l<VIEWY)
+ ysteps -= VIEWY-y2l;
+ endfrac = wall.x1<<6;
+ for (y=1;y<ysteps;y++) // top and bottom slopes
+ {
+ endfrac+=slope;
+ end=endfrac>>6;
+ if (end<wall.leftclip)
+ end=wall.leftclip;
+ else
+ if (end>wall.rightclip) // the rest is hidden
+ break;
+
+ ADDLINE(end,wall.rightclip,y1l-y,wall.color);
+ ADDLINE(end,wall.rightclip,y1h+y,wall.color);
+ }
+ if (y1l<VIEWY)
+ y1l=VIEWY;
+ if (y1h>VIEWYH)
+ y1h=VIEWYH;
+ for (y=y1l;y<=y1h;y++) // middle
+ ADDLINE(wall.leftclip,wall.rightclip,y,wall.color);
+
+ }
+
+}
+
+
+
+//==========================================================================
+
+
+/*
+=================
+=
+= TraceRay
+=
+= Used to find the left and rightmost tile in the view area to be traced from
+= Follows a ray of the given angle from viewx,viewy in the global map until
+= it hits a solid tile
+= sets:
+= tile.x,tile.y : tile coordinates of contacted tile
+= tilecolor : solid tile's color
+=
+==================
+*/
+
+int tilecolor;
+
+void TraceRay (unsigned angle)
+{
+ long tracex,tracey,tracexstep,traceystep,searchx,searchy;
+ fixed fixtemp;
+ int otx,oty,searchsteps;
+
+ tracexstep = costable[angle];
+ traceystep = sintable[angle];
+
+//
+// advance point so it is even with the view plane before we start checking
+//
+ fixtemp = FixedByFrac(prestep,tracexstep);
+ tracex = FixedAdd (viewx,fixtemp);
+ fixtemp = FixedByFrac(prestep,traceystep);
+ tracey = FixedAdd (viewy,fixtemp^SIGNBIT);
+
+ if (tracexstep&SIGNBIT) // use 2's complement, not signed magnitude
+ tracexstep = -(tracexstep&~SIGNBIT);
+
+ if (traceystep&SIGNBIT) // use 2's complement, not signed magnitude
+ traceystep = -(traceystep&~SIGNBIT);
+
+ tile.x = tracex>>TILESHIFT; // starting point in tiles
+ tile.y = tracey>>TILESHIFT;
+
+//
+// we assume viewx,viewy is not inside a solid tile, so go ahead one step
+//
+
+
+ do // until a solid tile is hit
+ {
+ otx = tile.x;
+ oty = tile.y;
+ tracex += tracexstep;
+ tracey -= traceystep;
+ tile.x = tracex>>TILESHIFT;
+ tile.y = tracey>>TILESHIFT;
+
+ if (tile.x!=otx && tile.y!=oty && (tilemap[otx][tile.y] || tilemap[tile.x][oty]) )
+ {
+ //
+ // trace crossed two solid tiles, so do a binary search along the line
+ // to find a spot where only one tile edge is crossed
+ //
+ searchsteps = 0;
+ searchx = tracexstep;
+ searchy = traceystep;
+ do
+ {
+ searchx/=2;
+ searchy/=2;
+ if (tile.x!=otx && tile.y!=oty)
+ {
+ // still too far
+ tracex -= searchx;
+ tracey += searchy;
+ }
+ else
+ {
+ // not far enough, no tiles crossed
+ tracex += searchx;
+ tracey -= searchy;
+ }
+
+ //
+ // if it is REAL close, go for the most clockwise intersection
+ //
+ if (++searchsteps == 16)
+ {
+ tracex = (long)otx<<TILESHIFT;
+ tracey = (long)oty<<TILESHIFT;
+ if (tracexstep>0)
+ {
+ if (traceystep<0)
+ {
+ tracex += TILEGLOBAL-1;
+ tracey += TILEGLOBAL;
+ }
+ else
+ {
+ tracex += TILEGLOBAL;
+ }
+ }
+ else
+ {
+ if (traceystep<0)
+ {
+ tracex --;
+ tracey += TILEGLOBAL-1;
+ }
+ else
+ {
+ tracey --;
+ }
+ }
+ }
+
+ tile.x = tracex>>TILESHIFT;
+ tile.y = tracey>>TILESHIFT;
+
+ } while (( tile.x!=otx && tile.y!=oty) || (tile.x==otx && tile.y==oty) );
+ }
+ } while (!(tilecolor = tilemap[tile.x][tile.y]) );
+
+}
+
+//==========================================================================
+
+
+/*
+========================
+=
+= FixedByFrac
+=
+= multiply a 16/16 bit fixed point number by a 16 bit fractional number
+= both unsigned (handle signs seperately)
+=
+========================
+*/
+
+
+fixed FixedByFrac (fixed a, fixed b)
+{
+ fixed value;
+
+asm mov si,[WORD PTR a+2]
+asm xor si,[WORD PTR b+2]
+asm and si,0x8000 // si is high word of result (sign bit)
+
+asm mov bx,[WORD PTR b]
+asm mov ax,[WORD PTR a]
+asm mul bx // fraction*fraction
+asm mov di,dx // di is low word of result
+asm mov ax,[WORD PTR a+2]
+asm and ax,0x7fff // strip sign bit
+asm mul bx // units*fraction
+asm add ax,di
+asm adc dx,0
+asm or dx,si
+
+asm mov [WORD PTR value],ax
+asm mov [WORD PTR value+2],dx
+
+ return value;
+}
+
+
+/*
+=========================
+=
+= FixedAdd
+=
+= add two 16 bit fixed point numbers
+= to subtract, invert the sign of B before invoking
+=
+=========================
+*/
+
+fixed FixedAdd (fixed a, fixed b)
+{
+ fixed value;
+
+asm mov ax,[WORD PTR a]
+asm mov dx,[WORD PTR a+2]
+
+asm mov bx,[WORD PTR b]
+asm mov cx,[WORD PTR b+2]
+
+asm or dx,dx
+asm jns aok: // negative?
+asm and dx,0x7fff
+asm not ax // convert a from signed magnitude to 2's compl
+asm not dx
+asm add ax,1
+asm adc dx,0
+aok:
+
+asm or cx,cx
+asm jns bok: // negative?
+asm and cx,0x7fff
+asm not bx // convert b from signed magnitude to 2's compl
+asm not cx
+asm add bx,1
+asm adc cx,0
+bok:
+
+asm add ax,bx // perform the addition
+asm adc dx,cx
+asm jns done
+
+asm and dx,0x7fff // value was negative
+asm not ax // back to signed magnitude
+asm not dx
+asm add ax,1
+asm adc dx,0
+
+done:
+
+asm mov [WORD PTR value],ax
+asm mov [WORD PTR value+2],dx
+
+ return value;
+}
+
+//==========================================================================
+
+
+/*
+========================
+=
+= TransformPoint
+=
+= Takes paramaters:
+= gx,gy : globalx/globaly of point
+=
+= globals:
+= viewx,viewy : point of view
+= viewcos,viewsin : sin/cos of viewangle
+=
+=
+= defines:
+= CENTERX : pixel location of center of view window
+= TILEGLOBAL : size of one
+= FOCALLENGTH : distance behind viewx/y for center of projection
+= scale : conversion from global value to screen value
+=
+= returns:
+= screenx,screenheight: projected edge location and size
+=
+========================
+*/
+
+#define MINRATIO 16
+
+void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight)
+{
+ int ratio;
+ fixed gxt,gyt,nx,ny;
+
+//
+// translate point to view centered coordinates
+//
+ gx = FixedAdd(gx,viewx|SIGNBIT);
+ gy = FixedAdd(gy,viewy|SIGNBIT);
+
+//
+// calculate newx
+//
+ gxt = FixedByFrac(gx,viewcos);
+ gyt = FixedByFrac(gy,viewsin);
+ nx = FixedAdd(gxt,gyt^SIGNBIT);
+
+//
+// calculate newy
+//
+ gxt = FixedByFrac(gx,viewsin);
+ gyt = FixedByFrac(gy,viewcos);
+ ny = FixedAdd(gyt,gxt);
+
+//
+// calculate perspective ratio
+//
+ if (nx<0)
+ nx = 0;
+
+ ratio = nx*scale/FOCALLENGTH;
+
+ if (ratio<=MINRATIO)
+ ratio = MINRATIO;
+
+ if (ny & SIGNBIT)
+ *screenx = CENTERX - (ny&~SIGNBIT)/ratio;
+ else
+ *screenx = CENTERX + ny/ratio;
+
+ *screenheight = TILEGLOBAL/ratio;
+
+}
+
+//==========================================================================
+
+fixed TransformX (fixed gx, fixed gy)
+{
+ int ratio;
+ fixed gxt,gyt,nx,ny;
+
+//
+// translate point to view centered coordinates
+//
+ gx = FixedAdd(gx,viewx|SIGNBIT);
+ gy = FixedAdd(gy,viewy|SIGNBIT);
+
+//
+// calculate newx
+//
+ gxt = FixedByFrac(gx,viewcos);
+ gyt = FixedByFrac(gy,viewsin);
+ return FixedAdd(gxt,gyt^SIGNBIT);
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= BuildTables
+=
+= Calculates:
+=
+= scale projection constant
+= sintable/costable overlapping fractional tables
+= firstangle/lastangle angles from focalpoint to left/right view edges
+= prestep distance from focal point before checking for tiles
+= yshift[] screen bouncing patters
+=
+==================
+*/
+#define PI 3.141592657
+#define ANGLEQUAD (ANGLES/4)
+void BuildTables (void)
+{
+ int i,intang;
+ float angle,anglestep;
+ fixed value;
+
+//
+// calculate scale value so one tile at mindist allmost fills the view vertical
+//
+ scale = GLOBAL1/VIEWWIDTH; // GLOBALVIEWHEIGHT/viewheight;
+ scale *= focallength;
+ scale /= (focallength+mindist);
+
+//
+// costable overlays sintable with a quarter phase shift
+// ANGLES is assumed to be divisable by four
+//
+
+ angle = 0;
+ anglestep = PI/2/ANGLEQUAD;
+ for (i=0;i<=ANGLEQUAD;i++)
+ {
+ value=GLOBAL1*sin(angle);
+ sintable[i]=
+ sintable[i+ANGLES]=
+ sintable[ANGLES/2-i] = value;
+ sintable[ANGLES-i]=
+ sintable[ANGLES/2+i] = value | SIGNBIT;
+ angle += anglestep;
+ }
+
+//
+// figure trace angles for first and last pixel on screen
+//
+ angle = atan((float)VIEWWIDTH/2*scale/FOCALLENGTH);
+ angle *= ANGLES/(PI*2);
+
+ intang = (int)angle+1;
+ firstangle = intang;
+ lastangle = -intang;
+
+ prestep = GLOBAL1*((float)FOCALLENGTH/costable[firstangle]);
+
+//
+// hover screen shifting
+//
+ for (i=0;i<SHIFTFRAMES;i++)
+ {
+ angle = (long)ANGLES*i/SHIFTFRAMES;
+ value = FixedByFrac(7*GLOBAL1,sintable[angle]);
+ yshift[i] = SCREENWIDTH*(FixedAdd(value,8*GLOBAL1)>>16);
+ }
+
+//
+// misc stuff
+//
+ walls[0].x2 = VIEWX-1;
+ walls[0].height2 = 32000;
+}
+
+
+//==========================================================================
+
+/*
+=================
+=
+= StartView
+=
+= Called by player think
+=
+=================
+*/
+
+void StartView (void)
+{
+ int tracedir;
+
+//
+// set up variables for this view
+//
+ viewangle = objlist[0].angle;
+ viewsin = sintable[viewangle];
+ viewcos = costable[viewangle];
+ viewx = FixedAdd( objlist[0].x,FixedByFrac(FOCALLENGTH,viewcos)^SIGNBIT );
+ viewy = FixedAdd( objlist[0].y,FixedByFrac(FOCALLENGTH,viewsin) );
+
+ focal.x = viewx>>TILESHIFT;
+ focal.y = viewy>>TILESHIFT;
+
+//
+// find the rightmost visable tile in view
+//
+ tracedir = viewangle + lastangle;
+ if (tracedir<0)
+ tracedir+=ANGLES;
+ else if (tracedir>=ANGLES)
+ tracedir-=ANGLES;
+ TraceRay( tracedir );
+ right.x = tile.x;
+ right.y = tile.y;
+
+//
+// find the leftmost visable tile in view
+//
+ tracedir = viewangle + firstangle;
+ if (tracedir<0)
+ tracedir+=ANGLES;
+ else if (tracedir>=ANGLES)
+ tracedir-=ANGLES;
+ TraceRay( tracedir );
+
+//
+// follow the walls from there to the right
+//
+ rightwall = &walls[1];
+
+ FollowWalls ();
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= DrawWallList
+=
+= Clips and draws all the walls traced this refresh
+=
+=====================
+*/
+
+void DrawWallList (void)
+{
+ int i,leftx,newleft,rightclip;
+ walltype *wall, *check;
+
+ memset(segstart,0,sizeof(segstart)); // start lines at 0
+ memset(segend,0xff,sizeof(segend)); // end lines at -1
+ memset(segcolor,0xff,sizeof(segcolor)); // with color -1
+
+ rightwall->x1 = VIEWXH+1;
+ rightwall->height1 = 32000;
+ (rightwall+1)->x1 = 32000;
+
+ leftx = -1;
+
+ for (wall=&walls[1];wall<rightwall && leftx<=VIEWXH ;wall++)
+ {
+ if (leftx >= wall->x2)
+ continue;
+
+ rightclip = wall->x2;
+
+ check = wall+1;
+ while (check->x1 <= rightclip && check->height1 >= wall->height2)
+ {
+ rightclip = check->x1-1;
+ check++;
+ }
+
+ if (rightclip>VIEWXH)
+ rightclip=VIEWXH;
+
+ if (leftx < wall->x1 - 1)
+ newleft = wall->x1-1; // there was black space between walls
+ else
+ newleft = leftx;
+
+ if (rightclip > newleft)
+ {
+ wall->leftclip = newleft+1;
+ wall->rightclip = rightclip;
+ DrawWall (wall);
+ leftx = rightclip;
+ }
+ }
+
+//
+// finish all lines to the right edge
+//
+ for (i=0;i<CENTERY;i++)
+ if (segend[i]<VIEWXH)
+ DrawLine(segend[i]+1,VIEWXH,i,0);
+
+ for (;i<VIEWHEIGHT;i++)
+ if (segend[i]<VIEWXH)
+ DrawLine(segend[i]+1,VIEWXH,i,8);
+
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= DrawScaleds
+=
+= Draws all objects that are visable
+=
+=====================
+*/
+
+int depthsort[MAXOBJECTS],
+ sortheight[MAXOBJECTS],
+ obscreenx[MAXOBJECTS],
+ obscreenheight[MAXOBJECTS],
+ obshapenum[MAXOBJECTS];
+
+void DrawScaleds (void)
+{
+ int i,j,least,leastnum,screenx,numvisable;
+ unsigned ratio,screenratio,scaleratio,screenheight;
+ fixed viewx;
+ objtype *obj;
+
+ numvisable = 0;
+
+//
+// calculate base positions of all objects
+//
+ for (obj = &objlist[1];obj<=lastobj;obj++)
+ if (obj->class)
+ {
+ viewx = obj->viewx - obj->size; // now value of nearest edge
+ if (viewx >= FOCALLENGTH+MINDIST)
+ {
+ ratio = viewx*scale/FOCALLENGTH;
+ screenx = CENTERX + obj->viewy/ratio;
+ screenheight = TILEGLOBAL/ratio;
+ if (screenx > -128 && screenx < 320+128)
+ {
+ obscreenx[numvisable] = screenx;
+ obscreenheight[numvisable] = screenheight;
+ obshapenum[numvisable] = obj->shapenum;
+ numvisable++;
+ }
+ }
+ }
+
+ if (!numvisable)
+ return;
+
+//
+// sort in order of increasing height
+//
+ for (i=0;i<numvisable;i++)
+ {
+ least = 32000;
+ for (j=0;j<numvisable;j++)
+ if (obscreenheight[j] < least)
+ {
+ leastnum = j;
+ least = obscreenheight[j];
+ }
+ depthsort[i] = leastnum;
+ sortheight[i] = least;
+ obscreenheight[leastnum] = 32000;
+ }
+
+//
+// draw in order
+//
+ for (i=0;i<numvisable;i++)
+ {
+ j = depthsort[i];
+ SC_ScaleShape(obscreenx[j],CENTERY+5,sortheight[i]
+ ,scalesegs[obshapenum[j]]);
+ }
+}
+
+//==========================================================================
+
+/*
+====================
+=
+= DrawCrossHairs
+=
+= Should still be in write mode 2
+=
+====================
+*/
+
+#define CROSSSIZE 40
+
+void DrawCrossHairs (void)
+{
+ EGABITMASK (60);
+
+ asm mov es,[screenseg]
+ asm mov cx,CROSSSIZE
+ asm mov di,SCREENWIDTH*(64-CROSSSIZE/2)+20
+ asm add di,[screenofs]
+ asm mov dx,SCREENWIDTH
+vert1:
+ asm mov al,0
+ asm xchg al,[BYTE PTR es:di] // write color 0
+ asm add di,dx
+ asm loop vert1
+
+ EGABITMASK (255);
+
+ asm mov di,SCREENWIDTH*(82-CROSSSIZE/2)+18
+ asm add di,[screenofs]
+ asm mov al,0
+ asm mov cx,5
+ asm rep stosb
+ asm add di,SCREENWIDTH-5
+ asm mov cx,5
+ asm rep stosb
+ asm add di,SCREENWIDTH-5
+ asm mov cx,5
+ asm rep stosb
+ asm add di,SCREENWIDTH-5
+ asm mov cx,5
+ asm rep stosb
+
+ asm mov di,SCREENWIDTH*(83-CROSSSIZE/2)+19
+ asm add di,[screenofs]
+ asm mov al,15
+ asm mov cx,3
+ asm rep stosb
+ asm add di,SCREENWIDTH-3
+ asm mov cx,3
+ asm rep stosb
+
+
+ EGABITMASK (127);
+
+ asm mov di,SCREENWIDTH*(83-CROSSSIZE/2)+18
+ asm add di,[screenofs]
+ asm mov al,15
+ asm xchg al,[es:di]
+ asm mov al,15
+ asm xchg al,[es:di+SCREENWIDTH]
+
+ EGABITMASK (254);
+
+ asm mov di,SCREENWIDTH*(83-CROSSSIZE/2)+18
+ asm add di,[screenofs]
+ asm mov al,15
+ asm xchg al,[es:di+4]
+ asm mov al,15
+ asm xchg al,[es:di+4+SCREENWIDTH]
+
+ EGABITMASK (24);
+
+ asm mov cx,CROSSSIZE-2
+ asm mov di,SCREENWIDTH*(65-CROSSSIZE/2)+20
+ asm add di,[screenofs]
+ asm mov dx,SCREENWIDTH
+vert2:
+ asm mov al,15
+ asm xchg al,[es:di] // write color 15
+ asm add di,dx
+ asm loop vert2
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= FinishView
+=
+=====================
+*/
+
+void FinishView (void)
+{
+ int screenx,pixelscale,screenheight,ratio;
+
+ if (++screenpage == 3)
+ screenpage = 0;
+
+ screenorigin = screenofs = screenloc[screenpage];
+
+ EGAWRITEMODE(2);
+
+//
+// draw the wall list
+//
+ DrawWallList();
+
+//
+// draw all the scaled images
+//
+ DrawScaleds();
+
+//
+// show screen and time last cycle
+//
+ screenofs += yshift[(unsigned)inttime&0xff]; // hover effect
+
+ DrawCrossHairs ();
+
+ EGAWRITEMODE(0);
+
+asm cli
+
+asm mov dx,GC_INDEX
+asm mov ax,GC_BITMASK + 255*256
+asm out dx,ax // no bit mask
+
+asm mov cx,[screenofs]
+asm mov dx,3d4h // CRTC address register
+asm mov al,0ch // start address high register
+asm out dx,al
+asm inc dx
+asm mov al,ch
+asm out dx,al // set the high byte
+asm dec dx
+asm mov al,0dh // start address low register
+asm out dx,al
+asm inc dx
+asm mov al,cl
+asm out dx,al // set the low byte
+
+asm sti
+
+
+#ifdef ADAPTIVE
+ while ( (tics = (timecount - lasttimecount)/2)<2 )
+ ;
+
+ lasttimecount = timecount&(~1l);
+#else
+ tics = 2;
+#endif
+
+ if (tics>MAXTICS)
+ tics = MAXTICS;
+
+}
+
+
diff --git a/HOVER.DSK b/HOVER.DSK
new file mode 100644
index 0000000..ea9a5c7
--- /dev/null
+++ b/HOVER.DSK
Binary files differ
diff --git a/HOVER.PRJ b/HOVER.PRJ
new file mode 100644
index 0000000..c624972
--- /dev/null
+++ b/HOVER.PRJ
Binary files differ
diff --git a/HOVERDEF.H b/HOVERDEF.H
new file mode 100644
index 0000000..9ba1d5b
--- /dev/null
+++ b/HOVERDEF.H
@@ -0,0 +1,271 @@
+/* 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.
+ */
+
+/*
+=============================================================================
+
+ HOVERTANK MAIN
+
+=============================================================================
+*/
+#include "JM_SB.H"
+#include "IDLIB.H"
+#include <MATH.H>
+
+//#define PROFILE
+
+#ifndef PROFILE
+#define ADAPTIVE
+#endif
+
+
+//#define TESTCASE
+
+#define MAXTICS 8
+
+#define NUMLEVELS 20
+
+/*
+=============================================================================
+
+ REFRESH
+
+=============================================================================
+*/
+
+#define VIEWX 0 // corner of view window
+#define VIEWY 0
+#define VIEWWIDTH (40*8) // size of view window
+#define VIEWHEIGHT (18*8)
+#define VIEWXH (VIEWX+VIEWWIDTH-1)
+#define VIEWYH (VIEWY+VIEWHEIGHT-1)
+
+#define CENTERX (VIEWX+VIEWWIDTH/2) // middle of view window
+#define CENTERY (VIEWY+VIEWHEIGHT/2)
+
+#define STATUSLINES (9*8) // dash board
+
+#define GLOBAL1 (1l<<16)
+#define TILEGLOBAL GLOBAL1
+#define TILESHIFT 16
+
+#define MINDIST (2*GLOBAL1/5)
+#define FOCALLENGTH (TILEGLOBAL) // in global coordinates
+
+#define ANGLES 360 // must be divisable by 4
+
+#define MAPSIZE 64 // maps are 64*64 max
+#define MAXOBJECTS 100 // max number of tanks, etc / map
+
+//
+// 1 sign bit
+// 15 bits units
+// 16 bits fractional
+//
+#define SIGNBIT 0x80000000l
+
+typedef long fixed;
+
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+/*
+=============================================================================
+
+ DASH INSTRUMENTS
+
+=============================================================================
+*/
+
+#define TIMESECX 3
+#define TIMESECY 54
+#define TIMEMINX 1
+#define TIMEMINY 54
+
+#define RADARX 284 // center of radar
+#define RADARY 36
+#define RADARSIZE 26 // each way
+#define RADARRANGE (TILEGLOBAL*18) // each way
+#define RADARSCALE (RADARRANGE/RADARSIZE)
+
+/*
+=============================================================================
+
+ HOVMAIN
+
+=============================================================================
+*/
+
+extern int tedlevel;
+extern memptr scalesegs[NUMPICS];
+
+
+/*
+=============================================================================
+
+ HOVDRAW
+
+=============================================================================
+*/
+
+
+typedef struct {int x,y;} tilept;
+typedef struct {fixed x,y;} globpt;
+
+typedef struct
+{
+ int x1,x2,leftclip,rightclip;// first pixel of wall (may not be visable)
+ unsigned height1,height2,color;
+} walltype;
+
+#define MAXWALLS 100
+#define DANGERHIGH 90
+#define DANGERLOW 10
+
+#define MIDWALL (MAXWALLS/2)
+
+
+//==========================================================================
+
+extern tilept tile,lasttile,focal,left,mid,right;
+
+extern globpt edge,view;
+
+extern unsigned screenloc[3];
+
+extern int screenpage,tics;
+
+extern long lasttimecount;
+#define SHIFTFRAMES 256
+extern int yshift[SHIFTFRAMES]; // screen sliding variables
+
+extern int firstangle,lastangle;
+
+extern fixed prestep;
+
+extern int traceclip,tracetop;
+
+extern fixed sintable[ANGLES+ANGLES/4],*costable;
+
+extern fixed viewx,viewy,viewsin,viewcos; // the focal point
+extern int viewangle;
+
+extern fixed scale,scaleglobal;
+extern unsigned slideofs;
+
+extern int zbuffer[VIEWXH+1];
+
+extern walltype walls[MAXWALLS],*leftwall,*rightwall;
+
+
+//==========================================================================
+
+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);
+void TransformPoint (fixed gx, fixed gy, int *screenx, unsigned *screenheight);
+fixed TransformX (fixed gx, fixed gy);
+int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max);
+void ForwardTrace (void);
+int FinishWall (void);
+int TurnClockwise (void);
+int TurnCounterClockwise (void);
+void FollowWall (void);
+
+void NewScene (void);
+void BuildTables (void);
+
+
+/*
+=============================================================================
+
+ HOVLOOP
+
+=============================================================================
+*/
+
+//
+// temp stuff
+//
+extern int statx,staty;
+
+
+extern unsigned tilemap[MAPSIZE][MAPSIZE];
+
+typedef enum
+ {nothing,playerobj,refugeeobj,droneobj,tankobj,mutantobj,warpobj,
+ pshotobj,pbigshotobj,mshotobj,inertobj,shieldobj} classtype;
+
+typedef struct
+{
+ int active;
+ classtype class;
+ fixed x,y;
+ fixed viewx,viewy; // x,y in view coordinate space (NOT pixels!)
+ int angle;
+ int hitpoints;
+ int radarx,radary,radarcolor;
+ long speed;
+ unsigned size; // global radius for hit rect calculation
+ fixed xl,xh,yl,yh; // hit rectangle
+ int ticcount;
+ int shapenum,stage;
+ int temp1,temp2;
+ dirtype dir;
+ void (*think)();
+} objtype;
+
+typedef struct {int min,sec;} timetype;
+extern timetype timestruct;
+
+extern ControlStruct c;
+
+extern int guncount,bordertime;
+
+extern fixed warpx,warpy; // where to spawn warp gate
+extern fixed xmove,ymove;
+
+
+extern int godmode,singlestep,leveldone,resetgame;
+extern int numrefugees,totalrefugees,savedcount,killedcount;
+
+extern objtype objlist[MAXOBJECTS],obon,*new,*obj,*lastobj,*check;
+
+void PlayerThink (void);
+
+void PlayLoop (void);
+void PlayGame (void);
+
+
+/*
+=============================================================================
+
+ HOVSCALE
+
+=============================================================================
+*/
+
+extern unsigned scaleblockwidth,
+ scaleblockheight,
+ scaleblockdest;
+
+int SC_ScaleShape (int x,int y,unsigned scale, memptr shape);
diff --git a/HOVLOOP.C b/HOVLOOP.C
new file mode 100644
index 0000000..815297a
--- /dev/null
+++ b/HOVLOOP.C
@@ -0,0 +1,1085 @@
+/* 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
+
+//==========================================================================
+
+//
+// map arrays
+//
+unsigned tilemap[MAPSIZE][MAPSIZE];
+
+
+//
+// play stuff
+//
+
+int godmode,singlestep,leveldone,startlevel,bestlevel;
+
+timetype timestruct;
+
+objtype objlist[MAXOBJECTS],obon,*new,*obj,*lastobj,*check;
+
+ControlStruct c;
+
+int numrefugees,totalrefugees,savedcount,killedcount;
+
+int bordertime;
+
+//
+// actor stuff
+//
+fixed warpx,warpy; // where to spawn warp gate
+fixed xmove,ymove;
+
+
+#define TIMEPOINTS 100
+#define REFUGEEPOINTS 10000
+
+//==========================================================================
+
+void DrawCockpit (void);
+void DrawScore (void);
+void FindFreeObj (void);
+void StartLevel (unsigned far *plane1);
+void DropTime (void);
+void ClipMove (void);
+void Thrust (void);
+void Reverse (void);
+void AfterBurn (void);
+void CalcBounds (void);
+void TransformObon (void);
+
+void SpawnPlayer (fixed gx, fixed gy);
+void PlayerThink (void);
+void SpawnShot (fixed gx, fixed gy, int angle, classtype class);
+void ShotThink (void);
+void ExplodeThink (void);
+void SpawnRefugee (fixed gx, fixed gy, int sex);
+void KillRefugee (objtype *hit);
+void RefugeeThink (void);
+void SpawnDrone (fixed gx, fixed gy);
+void DroneThink (void);
+void SpawnTank (fixed gx, fixed gy);
+void TankThink (void);
+void SpawnMutant (fixed gx, fixed gy);
+void MutantThink (void);
+void SpawnWarp (fixed gx, fixed gy);
+void WarpThink (void);
+
+void PlayLoop (void);
+void PlayGame (void);
+
+//==========================================================================
+
+/*
+==================
+=
+= DrawCockpit
+=
+==================
+*/
+
+void DrawCockpit (void)
+{
+ screenofs = 0;
+
+ screencenterx=19;
+ screencentery=7;
+
+ EGAWRITEMODE(0);
+ DrawPic (0,0,DASHPIC);
+ DrawScore ();
+}
+
+//==========================================================================
+
+/*
+===================
+=
+= DrawScore
+=
+===================
+*/
+
+void DrawScore (void)
+{
+ int i;
+
+ ltoa(score,str,10);
+ sx = 22-strlen(str);
+ sy = 7;
+ screenofs = linewidth*2;
+ for (i=0;i<strlen(str);i++)
+ str[i]-= ('0' - 23); // the digit pictures start at 23
+ Print (str);
+ screenofs = 0;
+}
+
+//==========================================================================
+
+
+void BadThink (void)
+{
+ Quit ("BadThink called!");
+}
+
+
+/*
+===============
+=
+= FindFreeobj
+=
+= Assigned global variable *new to a free spot in the object list
+=
+===============
+*/
+
+void FindFreeObj (void)
+{
+ new=&objlist[1];
+ while (new->class != nothing && new<=lastobj)
+ new++;
+
+ if (new>lastobj)
+ {
+ lastobj++;
+ if (lastobj>=&objlist[MAXOBJECTS])
+ Quit("Object list overflow!");
+ }
+
+ memset (new,0,sizeof(*new));
+
+ new->think = BadThink;
+}
+
+
+//==========================================================================
+
+/*
+==================
+=
+= StartLevel
+=
+==================
+*/
+
+void StartLevel (unsigned far *plane1)
+{
+ unsigned x,y,tile,dir;
+ int angle;
+ fixed gx,gy;
+
+ numrefugees = 0;
+
+ for (y=0;y<levelheader->height;y++)
+ for (x=0;x<levelheader->width;x++)
+ if ( (tile=*plane1++) > 0 )
+ {
+ dir = tile>>8; // high byte gives starting dir
+ tile &= 0xff;
+ gx = x*TILEGLOBAL+TILEGLOBAL/2;
+ gy = y*TILEGLOBAL+TILEGLOBAL/2;
+ switch (tile)
+ {
+ case 1:
+ SpawnRefugee (gx,gy,1);
+ break;
+ case 2:
+ SpawnDrone (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2);
+ break;
+ case 3:
+ SpawnTank (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2);
+ break;
+ case 4:
+ SpawnMutant (gx+TILEGLOBAL/2,gy+TILEGLOBAL/2);
+ break;
+ case 5:
+ SpawnShield (gx,gy);
+ break;
+ case 6:
+ SpawnRefugee (gx,gy,0);
+ break;
+ case 0xfe:
+ warpx =gx; // warp gate is spawned when all men are done
+ warpy =gy;
+ break;
+ case 0xff:
+ SpawnPlayer (gx,gy);
+ angle = ANGLES/4-dir*ANGLES/4;
+ if (angle<0)
+ angle+= ANGLES;
+ objlist[0].angle = angle;
+ break;
+ }
+ }
+
+ totalrefugees = numrefugees;
+}
+
+
+//==========================================================================
+
+/*
+=====================
+=
+= DropTime
+=
+=====================
+*/
+
+void DropTime (void)
+{
+ static long secondtics;
+ int now;
+
+ secondtics+= tics;
+ if (secondtics<70)
+ return;
+
+ secondtics=0; // give the slow systems a little edge
+
+ if (--timestruct.sec<0)
+ {
+ timestruct.sec = 59;
+ if (--timestruct.min<0)
+ leveldone = -1;
+ else
+//
+// draw new minutes
+//
+ DrawPic (6,48,DIGIT0PIC+timestruct.min);
+ }
+//
+// draw new seconds
+//
+ DrawPic (9,48,DIGIT0PIC+timestruct.sec/10);
+ DrawPic (11,48,DIGIT0PIC+timestruct.sec%10);
+
+ if (timestruct.min==0 && timestruct.sec<=20)
+ PlaySound (LOWTIMESND);
+}
+
+//==========================================================================
+
+/*
+===================
+=
+= ClipMove
+=
+= Only checks corners, so the object better be less than one tile wide!
+=
+===================
+*/
+
+void ClipMove (void)
+{
+ int xl,yl,xh,yh,tx,ty,nt1,nt2;
+ long intersect,basex,basey,pointx,pointy;
+ unsigned inside,total;
+
+//
+// move player and check to see if any corners are in solid tiles
+//
+
+ if (xmove<0)
+ xmove=-(xmove^SIGNBIT);
+ if (ymove<0)
+ ymove=-(ymove^SIGNBIT);
+
+ obon.x += xmove;
+ obon.y += ymove;
+
+ CalcBounds ();
+
+ xl = obon.xl>>TILESHIFT;
+ yl = obon.yl>>TILESHIFT;
+
+ xh = obon.xh>>TILESHIFT;
+ yh = obon.yh>>TILESHIFT;
+
+
+ if (!tilemap[xl][yl] && !tilemap[xh][yl]
+ && !tilemap[xh][yh] && !tilemap[xl][yh] )
+ return; // no corners in wall
+
+ if (!SoundPlaying())
+ PlaySound (BUMPWALLSND);
+
+
+//
+// intersect the path with the tile edges to determine point of impact
+//
+
+//
+// clip to east / west walls
+//
+ if (xmove>0)
+ {
+ inside = obon.xh & 0xffff;
+ total = xmove;
+ if (inside<=total)
+ {
+ if (total>1)
+ intersect = ymove*inside/(total-1);
+ else
+ intersect = ymove;
+ nt1 = (obon.yl-intersect)>>TILESHIFT;
+ nt2 = (obon.yh-intersect)>>TILESHIFT;
+ if ( ( tilemap[xh][nt1] && !tilemap[xh-1][nt1] )
+ || ( tilemap[xh][nt2] && !tilemap[xh-1][nt2] ) )
+ obon.x = (obon.xh & 0xffff0000) - (MINDIST + 1);
+ }
+ }
+ else if (xmove<0)
+ {
+ inside = TILEGLOBAL- (obon.xl & 0xffff);
+ total = -xmove;
+ if (inside<=total)
+ {
+ if (total>1)
+ intersect = ymove*inside/(total-1);
+ else
+ intersect = ymove;
+ nt1 = (obon.yl-intersect)>>TILESHIFT;
+ nt2 = (obon.yh-intersect)>>TILESHIFT;
+ if ( ( tilemap[xl][nt1] && !tilemap[xl+1][nt1] )
+ || ( tilemap[xl][nt2] && !tilemap[xl+1][nt2] ) )
+ obon.x = (obon.xl & 0xffff0000) + TILEGLOBAL + (MINDIST + 1);
+ }
+ }
+
+//
+// clip to north / south walls
+//
+ if (ymove>0)
+ {
+ inside = obon.yh & 0xffff;
+ total = ymove;
+ if (inside<=total)
+ {
+ if (total>1)
+ intersect = xmove*inside/(total-1);
+ else
+ intersect = xmove;
+ nt1 = (obon.xl-intersect)>>TILESHIFT;
+ nt2 = (obon.xh-intersect)>>TILESHIFT;
+ if ( ( tilemap[nt1][yh] && !tilemap[nt1][yh-1] )
+ || ( tilemap[nt2][yh] && !tilemap[nt2][yh-1] ) )
+ obon.y = (obon.yh & 0xffff0000) - (MINDIST + 1);
+ }
+ }
+ else if (ymove<0)
+ {
+ inside = TILEGLOBAL- (obon.yl & 0xffff);
+ total = -ymove;
+ if (inside<=total)
+ {
+ if (total>1)
+ intersect = xmove*inside/(total-1);
+ else
+ intersect = xmove;
+ nt1 = (obon.xl-intersect)>>TILESHIFT;
+ nt2 = (obon.xh-intersect)>>TILESHIFT;
+ if ( ( tilemap[nt1][yl] && !tilemap[nt1][yl+1] )
+ || ( tilemap[nt2][yl] && !tilemap[nt2][yl+1] ) )
+ obon.y = (obon.yl & 0xffff0000) + TILEGLOBAL + (MINDIST + 1);
+ }
+ }
+
+}
+
+
+//==========================================================================
+
+/*
+==================
+=
+= CalcBounds
+=
+==================
+*/
+void CalcBounds (void)
+{
+//
+// calculate hit rect
+//
+ obon.xl = obon.x - obon.size;
+ obon.xh = obon.x + obon.size;
+ obon.yl = obon.y - obon.size;
+ obon.yh = obon.y + obon.size;
+}
+
+void CalcBoundsNew (void)
+{
+//
+// calculate hit rect
+//
+ new->xl = new->x - new->size;
+ new->xh = new->x + new->size;
+ new->yl = new->y - new->size;
+ new->yh = new->y + new->size;
+}
+
+//==========================================================================
+
+/*
+==================
+=
+= TransformObon
+=
+= Calculates transformed position and updates radar
+=
+==================
+*/
+
+void TransformObon (void)
+{
+ int ratio,screenx,pixelscale;
+ fixed gx,gy,gxt,gyt;
+ long absdx,absdy;
+
+//
+// translate point to view centered coordinates
+//
+ gx = FixedAdd(obon.x,viewx|SIGNBIT);
+ gy = FixedAdd(obon.y,viewy|SIGNBIT);
+
+//
+// calculate newx
+//
+ gxt = FixedByFrac(gx,viewcos);
+ gyt = FixedByFrac(gy,viewsin);
+ obon.viewx = FixedAdd(gxt,gyt^SIGNBIT);
+
+//
+// calculate newy
+//
+ gxt = FixedByFrac(gx,viewsin);
+ gyt = FixedByFrac(gy,viewcos);
+ obon.viewy = FixedAdd(gyt,gxt);
+
+//
+// update radar
+//
+ if (obon.radarx)
+ XPlot (obon.radarx,obon.radary,obon.radarcolor);
+
+ absdx = obon.viewx&(~SIGNBIT);
+ absdy = obon.viewy&(~SIGNBIT);
+
+ if (obon.viewx<0)
+ obon.viewx = -absdx;
+ if (obon.viewy<0)
+ obon.viewy = -absdy;
+
+ if (absdx<RADARRANGE && absdy<RADARRANGE)
+ {
+ obon.radarx= RADARX + obon.viewy/RADARSCALE;
+ obon.radary= RADARY - obon.viewx/RADARSCALE;
+ XPlot (obon.radarx,obon.radary,obon.radarcolor);
+ }
+ else
+ obon.radarx = 0;
+
+}
+
+
+//==========================================================================
+
+/*
+=====================
+=
+= WarpEffect
+=
+=====================
+*/
+
+void Block (x,y,color)
+{
+ int dest;
+
+ dest = ylookup[y<<3]+x+screenofs;
+
+asm {
+ mov es,[screenseg]
+ mov di,[dest]
+ mov al,[BYTE PTR color]
+ mov [es:di],al
+ mov [es:di+SCREENWIDTH*1],al
+ mov [es:di+SCREENWIDTH*2],al
+ mov [es:di+SCREENWIDTH*3],al
+ mov [es:di+SCREENWIDTH*4],al
+ mov [es:di+SCREENWIDTH*5],al
+ mov [es:di+SCREENWIDTH*6],al
+ mov [es:di+SCREENWIDTH*7],al
+ }
+}
+
+void Frame(xl,yl,xh,yh,color)
+{
+ int x,y;
+
+ for (x=xl;x<=xh;x++)
+ {
+ Block (x,yl,color);
+ Block (x,yh,color);
+ }
+ for (y=yl+1;y<yh;y++)
+ {
+ Block (xl,y,color);
+ Block (xh,y,color);
+ }
+}
+
+#define NUMCYCLES 3
+#define WARPSTEPS 200
+#define CYCLETIME 6
+#define FOCUS 10
+
+int cyclecolors[NUMCYCLES] = {3,3,11};
+
+void WarpEffect (void)
+{
+ int i,size;
+ long oldtime,time;
+
+ screenofs = screenloc[screenpage];
+ SetScreen ( screenofs,0);
+
+ memset (zbuffer,0,sizeof(zbuffer));
+
+ EGAWRITEMODE(2);
+
+ for (size=0;size<8;size++)
+ {
+ screenofs = screenloc[screenpage];
+ Frame (size,size,39-size,15-size,cyclecolors[size%NUMCYCLES]);
+ screenofs = screenloc[(screenpage+1)%3];
+ Frame (size,size,39-size,15-size,cyclecolors[(size+1)%NUMCYCLES]);
+ screenofs = screenloc[(screenpage+2)%3];
+ Frame (size,size,39-size,15-size,cyclecolors[(size+2)%NUMCYCLES]);
+ }
+
+ oldtime = timecount;
+
+ PlaySound (WARPGATESND);
+
+ do
+ {
+ time = timecount - oldtime;
+ if (time > WARPSTEPS)
+ time = WARPSTEPS;
+
+ screenofs = screenloc[(screenpage+ time/CYCLETIME )%3];
+
+ SC_ScaleShape (CENTERX,64,255*FOCUS / (WARPSTEPS+FOCUS-time),
+ scalesegs[WARP1PIC+ (time/CYCLETIME)%4] );
+
+ SetScreen (screenloc[(screenpage+ time/CYCLETIME )%3],0);
+ } while (time<WARPSTEPS && NBKascii != 27);
+
+ ClearKeys();
+
+ EGAWRITEMODE(0);
+ EGABITMASK(255);
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= GameOver
+=
+=====================
+*/
+
+void GameOver (void)
+{
+ if (level != 21)
+ {
+ FadeUp();
+ CacheDrawPic(DEATHPIC);
+ PlaySound (NUKESND);
+ FadeDown();
+ Ack();
+ }
+
+//
+// high score?
+//
+
+ if (score>highscore)
+ {
+ PlaySound (HIGHSCORESND);
+ ExpWin(18,11);
+ py+=3;
+ CPPrint ("New High Score!\n");
+ py+=5;
+ CPPrint ("Score\n");
+ ltoa(score,str,10);
+ CPPrint (str);
+ PPrint ("\n\n");
+ CPPrint ("Old\n");
+ ltoa(highscore,str,10);
+ CPPrint (str);
+ PPrint ("\n");
+ py+=5;
+ CPPrint ("Congratulations!\n");
+ CPPrint ("");
+ Ack();
+ highscore = score;
+ }
+
+}
+
+//==========================================================================
+
+/*
+=====================
+=
+= Victory
+=
+=====================
+*/
+
+void Victory (void)
+{
+ FadeOut();
+ CacheDrawPic(ENDPIC);
+ FadeIn();
+ DrawWindow (0,0,39,6);
+ CPPrint ("Crowds of cheering people surround\n");
+ CPPrint ("your tank. Cargo lifts deliver your\n");
+ CPPrint ("impressive bounty. The crowd quiets\n");
+ CPPrint ("as a distinguished man steps forward.\n");
+
+ Ack();
+ EraseWindow();
+
+ CPPrint ("'Well done,' says the UFA President.\n");
+ CPPrint ("'You have saved many deserving people.'\n");
+ CPPrint ("\n");
+ CPPrint ("'Mr. Sledge? I said you've done well.'\n");
+
+ Ack();
+ EraseWindow();
+
+ CPPrint ("You ignore him and count the reward\n");
+ CPPrint ("again. He says, 'Too bad about those\n");
+ CPPrint ("ones you lost...'\n");
+ CPPrint ("'What? I dropped some bills?' you say.\n");
+
+ Ack();
+
+ DrawWindow (10,21,30,24);
+ py+=3;
+ CPPrint ("Game Over!");
+
+ Ack();
+}
+
+//==========================================================================
+
+#include "HOVTEXT.C"
+
+/*
+=====================
+=
+= BaseScreen
+=
+= Drop off hostages, get score, start new level
+=
+=====================
+*/
+
+void BaseScreen (void)
+{
+ int i;
+ unsigned topofs;
+
+#ifdef TESTCASE
+ level++;
+ LoadLevel();
+ StopDrive();
+ return;
+#endif
+
+
+ CachePic (STARTPICS+MISSIONPIC);
+//
+// cash screen
+//
+ if (level!=startlevel) // send them straight into the first level
+ {
+#ifndef PROFILE
+ WarpEffect();
+#endif
+
+ CachePic (STARTPICS+UFAPIC);
+ DrawPic (0,0,UFAPIC);
+ if (killedcount>=savedcount)
+ {
+ CachePic (STARTPICS+MADUFAPIC);
+ DrawPic (0,0,MADUFAPIC);
+ MMSetPurge (&grsegs[STARTPICS+MADUFAPIC],3);
+ }
+ MMSetPurge (&grsegs[STARTPICS+UFAPIC],3);
+
+ pxl= 176;
+ pxh= 311;
+
+ py=10;
+ CPPrint ("UFA Headquarters\n");
+ py += 5;
+ PPrint ("Saved:");
+ PPrintInt (savedcount);
+ PPrint ("\nLost:");
+ PPrintInt (killedcount);
+ topofs = screenofs;
+
+
+ py += 5;
+ PPrint ("\nSavior reward...");
+ screenofs = 0; // draw into the split screen
+
+ //
+ // points for saving refugees
+ //
+ for (i=1;i<=savedcount;i++)
+ {
+ DrawPic (1+2*(savedcount-i),6,EMPTYGUYPIC);
+ score += REFUGEEPOINTS;
+ PlaySound (GUYSCORESND);
+ DrawScore ();
+#ifndef PROFILE
+ if (NBKascii != 27)
+ WaitVBL(30);
+#endif
+ }
+
+ screenofs = topofs;
+ py += 5;
+ PPrint ("\nTime bonus...\n");
+ screenofs = 0; // draw into the split screen
+
+ //
+ // points for time remaining
+ //
+ while (timestruct.sec || timestruct.min)
+ {
+ score += TIMEPOINTS;
+
+ if (--timestruct.sec<0)
+ {
+ timestruct.sec = 59;
+ if (--timestruct.min<0)
+ {
+ timestruct.sec = timestruct.min = 0;
+ }
+ DrawPic (6,48,DIGIT0PIC+timestruct.min);
+ }
+ DrawPic (9,48,DIGIT0PIC+timestruct.sec/10);
+ DrawPic (11,48,DIGIT0PIC+timestruct.sec%10);
+
+ if ( !(timestruct.sec%5) )
+ PlaySound (TIMESCORESND);
+ DrawScore ();
+#ifndef PROFILE
+ if (NBKascii != 27)
+ WaitVBL(2);
+#endif
+ }
+
+ if (objlist[0].hitpoints<3)
+ {
+ screenofs = topofs;
+ PPrint ("\nRepairing tank...");
+ screenofs = 0; // draw into the split screen
+ //
+ // heal tank
+ //
+ while (objlist[0].hitpoints<3 && score>10000)
+ {
+ score -= 10000;
+ DrawScore ();
+ HealPlayer ();
+#ifndef PROFILE
+ if (NBKascii != 27)
+ WaitVBL(60);
+#endif
+ ColorBorder (0);
+ bordertime = 0;
+ }
+ }
+
+ screenofs = topofs;
+ py = 110;
+ if (level == NUMLEVELS)
+ CPPrint ("Mission completed!");
+ else
+ CPPrint ("GO TO NEXT SECTOR");
+
+ StopDrive ();
+
+#ifndef PROFILE
+ Ack();
+#endif
+
+ if (level == NUMLEVELS)
+ {
+ Victory();
+ level++;
+ return;
+ }
+ }
+
+ MMSetPurge (&grsegs[STARTPICS+MISSIONPIC],3);
+ MMSortMem(); // push all purgable stuff high for good cache
+ FadeOut();
+
+//
+// briefing screen
+//
+ level++;
+ LoadLevel();
+ StopDrive();
+
+ EGAWRITEMODE(0);
+ _fmemset (MK_FP(0xa000,0),0,0xffff);
+ EGASplitScreen(200-STATUSLINES);
+ SetLineWidth(SCREENWIDTH);
+ DrawCockpit();
+
+//
+// draw custom dash stuff
+//
+ DrawPic (1,48,DIGIT0PIC+level/10);
+ DrawPic (3,48,DIGIT0PIC+level%10);
+ for (i=0;i<numrefugees;i++)
+ DrawPic (1+2*i,6,EMPTYGUYPIC);
+
+//
+// do mission briefing
+//
+
+ screenofs = screenloc[0];
+ SetScreen (screenofs,0);
+ DrawPic (0,0,MISSIONPIC);
+
+ pxl= 10;
+ pxh= 310;
+
+ py = 10;
+ CPPrint (levnames[level-1]);
+
+ py=37;
+ px=pxl;
+
+ PPrint (levtext[level-1]);
+
+ FadeIn();
+ ClearKeys();
+#ifndef PROFILE
+ Ack();
+
+ WarpEffect();
+#endif
+}
+
+//==========================================================================
+
+
+
+/*
+===================
+=
+= PlayLoop
+=
+===================
+*/
+
+void PlayLoop (void)
+{
+ do
+ {
+ c=ControlPlayer(1);
+
+ screenofs = 0; // draw in split screen (radar, time, etc)
+
+ for (obj = &objlist[0];obj<=lastobj;obj++)
+ {
+ if (obj->class)
+ {
+ obon=*obj;
+ obon.think();
+ *obj=obon;
+ }
+ }
+
+ DropTime();
+
+ if (keydown[0x57]) // DEBUG!
+ {
+ DamagePlayer();
+ ClearKeys();
+ }
+
+ if (bordertime && (bordertime-=tics) <=0)
+ {
+ bordertime = 0;
+ ColorBorder (0);
+ }
+
+ FinishView(); // base drawn by player think
+ CheckKeys();
+
+ }while (!leveldone);
+
+}
+
+
+
+/*
+===================
+=
+= PlayGame
+=
+===================
+*/
+
+int levmin[20] =
+{
+3,3,4,4,6,
+5,5,5,5,5,
+7,7,7,7,7,
+9,9,9,9,9
+};
+
+void PlayGame (void)
+{
+ int i,xl,yl,xh,yh;
+ char num[20];
+
+ level = startlevel = 0;
+
+ if (bestlevel>1)
+ {
+ ExpWin(28,3);
+ py+=6;
+ PPrint(" Start at what level (1-");
+ itoa(bestlevel,str,10);
+ PPrint (str);
+ PPrint (")?");
+ i = InputInt();
+ if (i>=1 && i<=bestlevel)
+ {
+ level = startlevel = i-1;
+ }
+ }
+
+restart:
+
+ resetgame = score = 0;
+
+ do
+ {
+
+ lastobj = &objlist[0];
+
+#ifdef TESTCASE
+ level = 12;
+#endif
+
+ BaseScreen ();
+ if (level==21)
+ break;
+
+#ifdef TESTCASE
+ objlist[0].x = 3126021;
+ objlist[0].y = 522173;
+ objlist[0].angle = 170;
+#endif
+
+ savedcount = killedcount = 0;
+
+ timestruct.min = levmin[level-1];
+ timestruct.sec = 0;
+ if (level == 20)
+ timestruct.sec = 59;
+
+ screenofs = 0;
+ DrawPic (6,48,DIGIT0PIC+timestruct.min);
+ DrawPic (9,48,DIGIT0PIC+timestruct.sec/10);
+ DrawPic (11,48,DIGIT0PIC+timestruct.sec%10);
+
+ lasttimecount = timecount;
+ tics = 1;
+ leveldone = 0;
+
+ if (level>bestlevel)
+ bestlevel = level;
+
+ PlayLoop ();
+
+ screenofs = 0;
+ for (obj=&objlist[1];obj<lastobj;obj++)
+ if (obj->class && obj->radarx)
+ XPlot (obj->radarx,obj->radary,obj->radarcolor);
+
+ if (bordertime)
+ {
+ bordertime = 0;
+ ColorBorder (0);
+ }
+
+ }
+ while (leveldone>0);
+
+ if (resetgame)
+ return;
+
+ GameOver();
+
+//
+// continue
+//
+
+ if (level>2 && level<21)
+ {
+ DrawWindow (10,20,30,23);
+ py+=3;
+ CPPrint ("Continue game ?");
+ ClearKeys();
+ ch = PGet();
+ if (toupper(ch)=='Y')
+ {
+ level--;
+ startlevel = level; // don't show base screen
+ goto restart;
+ }
+ }
+
+}
+
+
+
+
diff --git a/HOVMAIN.C b/HOVMAIN.C
new file mode 100644
index 0000000..ef69df1
--- /dev/null
+++ b/HOVMAIN.C
@@ -0,0 +1,1408 @@
+/* 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.
+ */
+
+#define CATALOG
+
+#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 ("<MORE>");
+ 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 ("<MORE>");
+ 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<NUMCHUNKS;i++)
+ if (grsegs[i] && !needgr[i])
+ MMSetPurge(&grsegs[i],3);
+
+ MMSortMem();
+
+//
+// load new stuff
+//
+ lseek(grhandle,0,SEEK_SET);
+ filepos = 0;
+
+ for (i=0;i<NUMCHUNKS;i++)
+ if (!grsegs[i] && needgr[i])
+ {
+ newpos = grstarts[i];
+ if (newpos!=filepos)
+ lseek(grhandle,newpos-filepos,SEEK_CUR);
+
+ compressed = grstarts[i+1]-grstarts[i]-4;
+
+ if (i>=STARTTILE8)
+ {
+ //
+ // tiles are of a known size
+ //
+ if (i<STARTTILE8M) // tile 8s are all in one chunk!
+ expanded = BLOCK*NUMTILE8;
+ else if (i<STARTTILE16)
+ expanded = MASKBLOCK*NUMTILE8M;
+ else if (i<STARTTILE16M) // all other tiles are one/chunk
+ expanded = BLOCK*4;
+ else if (i<STARTTILE32)
+ expanded = MASKBLOCK*4;
+ else if (i<STARTTILE32M)
+ expanded = BLOCK*16;
+ else
+ expanded = MASKBLOCK*16;
+
+ compressed = grstarts[i+1]-grstarts[i];
+ }
+ else
+ {
+ //
+ // other things have a length header at start of chunk
+ //
+ read(grhandle,&expanded,sizeof(expanded));
+ compressed = grstarts[i+1]-grstarts[i]-4;
+ }
+
+ //
+ // allocate space for expanded chunk
+ //
+ MMGetPtr(&grsegs[i],expanded);
+
+ //
+ // if the entire compressed length can't fit in the general purpose
+ // buffer, allocate a temporary memory block for it
+ //
+ if (compressed<=BUFFERSIZE)
+ {
+ SegRead(grhandle,bufferseg,compressed);
+ HuffExpand (bufferseg, grsegs[i], expanded,grhuffman);
+ }
+ else
+ {
+ MMGetPtr(&bigbufferseg,compressed);
+ SegRead(grhandle,bigbufferseg,compressed);
+ HuffExpand (bigbufferseg, grsegs[i], expanded,grhuffman);
+ MMFreePtr(&bigbufferseg);
+ }
+
+ filepos = grstarts[i+1]; // file pointer is now at start of next one
+ }
+
+}
+
+//==========================================================================
+
+
+/*
+=====================
+=
+= CachePic
+=
+= Make sure a graphic chunk is in memory
+=
+=====================
+*/
+
+void CachePic (int picnum)
+{
+ long expanded,compressed; // chunk lengths
+ memptr bigbufferseg; // for compressed
+
+ if (grsegs[picnum])
+ return;
+
+ lseek(grhandle,grstarts[picnum],SEEK_SET);
+
+ compressed = grstarts[picnum+1]-grstarts[picnum]-4;
+
+ if (picnum>=STARTTILE8)
+ {
+ //
+ // tiles are of a known size
+ //
+ if (picnum<STARTTILE8M) // tile 8s are all in one chunk!
+ expanded = BLOCK*NUMTILE8;
+ else if (picnum<STARTTILE16)
+ expanded = MASKBLOCK*NUMTILE8M;
+ else if (picnum<STARTTILE16M) // all other tiles are one/chunk
+ expanded = BLOCK*4;
+ else if (picnum<STARTTILE32)
+ expanded = MASKBLOCK*4;
+ else if (picnum<STARTTILE32M)
+ expanded = BLOCK*16;
+ else
+ expanded = MASKBLOCK*16;
+
+ compressed = grstarts[picnum+1]-grstarts[picnum];
+ }
+ else
+ {
+ //
+ // other things have a length header at start of chunk
+ //
+ read(grhandle,&expanded,sizeof(expanded));
+ compressed = grstarts[picnum+1]-grstarts[picnum]-4;
+ }
+
+ //
+ // allocate space for expanded chunk
+ //
+ MMGetPtr(&grsegs[picnum],expanded);
+
+ MMGetPtr(&bigbufferseg,compressed);
+ SegRead(grhandle,bigbufferseg,compressed);
+ HuffExpand (bigbufferseg, grsegs[picnum], expanded,grhuffman);
+ MMFreePtr(&bigbufferseg);
+}
+
+//==========================================================================
+
+void PatchPointers (void)
+{
+ fontseg = grsegs[STARTFONT];
+
+}
+
+//==========================================================================
+
+/*
+=====================
+==
+== Quit
+==
+=====================
+*/
+
+void Quit (char *error)
+{
+//char extern far PIRACY;
+
+ if (!(*error))
+ {
+ SaveCtrls ();
+ }
+
+ MMShutdown();
+ if (KBDstarted)
+ ShutdownKbd (); // shut down the interrupt driven stuff if needed
+ if (SNDstarted)
+ ShutdownSound ();
+ if (soundblaster)
+ jmShutSB ();
+
+ if (grhandle>0)
+ close(grhandle);
+ if (levelhandle>0)
+ close(levelhandle);
+ if (soundhandle>0)
+ close(soundhandle);
+
+ _AX = 3;
+ geninterrupt (0x10); // text mode
+
+ if (!(*error))
+ {
+#if 0
+ movedata (FP_SEG(&PIRACY),FP_OFF(&PIRACY),0xb800,0,4000);
+ bioskey (0);
+ clrscr();
+#endif
+
+#ifndef CATALOG
+ _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);
+ }
+#endif
+
+ }
+ 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;y<levelheader->height;y++)
+ for (x=0;x<levelheader->width;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;
+#ifndef CATALOG
+ CPPrint ("Copyright (c) 1991-93 Softdisk Publishing\n");
+// CPPrint ("'I' for information");
+#endif
+ 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],
+ 0,
+ 0,
+ &shapeseg);
+
+// 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 (f<NUMFRAMES)
+ {
+ f+=inttime;
+ if (f>NUMFRAMES)
+ 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 0
+ 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;
+#endif
+
+ }
+ }
+
+ 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;i<DASHPIC;i++)
+ {
+ CachePic (STARTPICS+i);
+ SC_MakeShape(
+ grsegs[STARTPICS+i],
+ pictable[i].width,
+ pictable[i].height,
+ &scalesegs[i]);
+ MMFreePtr (&grsegs[STARTPICS+i]);
+ }
+
+//
+// load the basic graphics
+//
+
+ needgr[STARTFONT] = 1;
+ needgr[STARTTILE8] = 1;
+
+ for (i=DASHPIC;i<ENDPIC;i++)
+ needgr[STARTPICS+i]=1;
+
+ CacheGrFile (); // load all graphics now (no caching)
+
+ fontseg = grsegs[STARTFONT];
+}
+
+//==========================================================================
+
+//////////////////////////////////////////////////////
+//
+// Hardware Error Handler - called only by MS-DOS
+//
+//////////////////////////////////////////////////////
+
+#define IGNORE 0
+#define RETRY 1
+#define ABORT 2
+
+int ErrorHandler(int errval,int ax,int bx,int si)
+{
+ unsigned key;
+
+ key=ax+bx+si+errval;
+
+// screenofs=screenorigin=0;
+// SetScreen(0,0);
+ CenterWindow(32,3);
+ py++;
+ CPPrint("Disk I/O error! Press ENTER to\n");
+ CPPrint("resume, or ESC to abort:");
+ SetNormalPalette();
+
+ ClearKeys();
+
+ do{
+ key=(PGet()&0xff);
+ } while(key!=27 && key!=13);
+
+ if (key!=27)
+ hardresume(RETRY);
+
+ _AX = 3;
+ geninterrupt (0x10); // text mode
+
+ if (KBDstarted)
+ ShutdownKbd (); // shut down the interrupt driven stuff if needed
+ if (SNDstarted)
+ ShutdownSound ();
+
+ return ABORT;
+}
+
+
+
+/*=========================================================================*/
+
+////////////////////////////////////////////////////////////
+//
+// Allocate memory and load file in
+//
+////////////////////////////////////////////////////////////
+void LoadIn(char *filename,char huge **baseptr)
+{
+ int handle;
+ long len;
+ unsigned datapage;
+
+
+ if ((handle=open(filename,O_BINARY))==-1)
+ {
+ printf("Error loading file '%s'!\n",filename);
+ exit(1);
+ }
+
+ len=filelength(handle);
+ *baseptr=(char huge *)farmalloc(len);
+
+ LoadFile(filename,*baseptr);
+}
+
+///////////////////////////////////////////////////////////////////////////
+//
+// US_CheckParm() - checks to see if a string matches one of a set of
+// strings. The check is case insensitive. The routine returns the
+// index of the string that matched, or -1 if no matches were found
+//
+///////////////////////////////////////////////////////////////////////////
+int
+US_CheckParm(char *parm,char **strings)
+{
+ char cp,cs,
+ *p,*s;
+ int i;
+
+ while (!isalpha(*parm)) // Skip non-alphas
+ parm++;
+
+ for (i = 0;*strings && **strings;i++)
+ {
+ for (s = *strings++,p = parm,cs = cp = 0;cs == cp;)
+ {
+ cs = *s++;
+ if (!cs)
+ return(i);
+ cp = *p++;
+
+ if (isupper(cs))
+ cs = tolower(cs);
+ if (isupper(cp))
+ cp = tolower(cp);
+ }
+ }
+ return(-1);
+}
+///////////////////////////////////////////////////////////////////////////
+
+/*
+=================
+=
+= main
+=
+=================
+*/
+
+static char *EntryParmStrings[] = {"detour",0};
+static char *SBlasterStrings[] = {"NOBLASTER",0};
+
+void main(void)
+{
+ int i,x,xl,xh,y,plane,size;
+ SampledSound huge *samples;
+
+ boolean LaunchedFromShell = false;
+
+ textbackground(0);
+ textcolor(7);
+ if (stricmp(_argv[1], "/VER") == 0)
+ {
+ printf("HOVERTANK 3-D\n");
+ printf("Copyright 1991-93 Softdisk Publishing\n");
+ printf("Version 1.17\n");
+ exit(0);
+ }
+
+ for (i = 1;i < _argc;i++)
+ {
+ switch (US_CheckParm(_argv[i],EntryParmStrings))
+ {
+ case 0:
+ LaunchedFromShell = true;
+ break;
+ }
+ }
+#ifndef CATALOG
+ if (!LaunchedFromShell)
+ {
+ clrscr();
+ puts("You must type START at the DOS prompt to run HOVERTANK 3-D.");
+ exit(0);
+ }
+#endif
+
+// puts("HoverTank 3-D is executing...");
+
+//
+// detect video
+//
+ videocard = VideoID ();
+
+ if (videocard == EGAcard) {}
+// puts ("EGA card detected");
+ else if (videocard == VGAcard) {}
+// puts ("VGA card detected");
+ else
+ {
+ clrscr();
+ puts ("Hey, I don't see an EGA or VGA card here! Do you want to run the program ");
+ puts ("anyway (Y = go ahead, N = quit to dos) ?");
+ ClearKeys ();
+ i = toupper(bioskey(0) & 0xff);
+ if (i!='Y')
+ exit (1);
+ }
+
+ grmode = EGAgr;
+
+//
+// setup for sound blaster
+//
+ soundblaster = 1;
+ for (i = 1;i < _argc;i++)
+ {
+ switch (US_CheckParm(_argv[i],SBlasterStrings))
+ {
+ case 0:
+ soundblaster = 0;
+ break;
+ }
+ }
+
+ if (soundblaster)
+ soundblaster = jmDetectSoundBlaster(-1);
+
+#if 0
+ if (stricmp(_argv[1], "NOBLASTER") == 0)
+ soundblaster = 0;
+ else
+ soundblaster = jmDetectSoundBlaster(-1);
+
+#endif
+
+
+
+
+ if (soundblaster)
+ {
+// puts ("Sound Blaster detected! (HOVER NOBLASTER to void detection)");
+ LoadIn ("DSOUND.HOV",&(char huge *)samples);
+ jmStartSB ();
+ jmSetSamplePtr (samples);
+ }
+// else
+// puts ("Sound Blaster not detected");
+
+
+ LoadNearData (); // load some stuff before starting the memory manager
+
+ MMStartup ();
+ MMGetPtr(&bufferseg,BUFFERSIZE); // small general purpose buffer
+
+ BloadinMM ("SOUNDS."EXTENSION,&soundseg);
+
+ harderr(ErrorHandler); // critical error handler
+
+#ifdef ADAPTIVE
+ timerspeed = 0x2147; // 140 ints / second (2/VBL)
+ StartupSound (); // interrupt handlers that must be removed at quit
+ SNDstarted = 1;
+#endif
+
+ StartupKbd ();
+ KBDstarted = 1;
+
+ SetupGraphics ();
+
+ InitRndT (1); // setup random routines
+ InitRnd (1);
+
+ LoadCtrls ();
+
+// puts ("Calculating...");
+ BuildTables();
+ SC_Setup();
+
+ SetScreenMode(grmode);
+ SetLineWidth (SCREENWIDTH);
+
+ screencenterx=19;
+ screencentery=12;
+
+#if !(defined (PROFILE) || defined (TESTCASE))
+ if (!keydown[1]) // hold ESC to bypass intro
+ Intro ();
+#endif
+
+#ifdef PROFILE
+JoyXlow[1]=JoyYlow[1]=16;
+JoyXhigh[1]=JoyYhigh[1]=70;
+playermode[1] = joystick1;
+#endif
+
+ while (1)
+ {
+#if !(defined (PROFILE) || defined (TESTCASE))
+ DemoLoop (); // do title, demo, etc
+#endif
+ PlaySound (STARTGAMESND);
+ PlayGame();
+ }
+
+}
+
diff --git a/HOVSCALE.C b/HOVSCALE.C
new file mode 100644
index 0000000..f897164
--- /dev/null
+++ b/HOVSCALE.C
@@ -0,0 +1,530 @@
+/* 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"
+
+/*
+=============================================================================
+
+ Id Software EGA scaling routines
+
+ by John Carmack, 4-16-91
+
+ ------------------------
+
+
+These routines implement SPARSE SCALING, a very fast way to draw a given
+shape at various sizes.
+
+SC_Setup
+--------
+Builds tables used by the drawing routines to select which pixels to draw
+at different scales. A scale of 256 is regular size, 128 half size, 512
+double size, etc. Usually you won't need exact precision in scaling, so
+some tables are used for a few scales. Basetables convert from a given
+pixel offset on the original shape to pixels on the scaled shape, screentables
+convert from a scaled offset to the original offset.
+
+SC_MakeShape
+------------
+Converts a standard four plane pic or sprite of the given width/height to
+sparse scaling format. The pixels are converted from four individual bits
+to segments of byte values (0-15). Pixels of BACKGROUND color are considered
+masks, and will not apear in the scaled shape. By considering the shape
+as a list of vertical line segments no masking is needed, as only visable
+pixels are scaled.
+
+SC_ScaleShape
+-------------
+Draws the shape CENTERED at the given x,y at the given scale, clipped to
+scalexl,scalexh,scaleyl,scaleyh (inclusive). The drawing is done vertically
+so the bit mask register need only be set once for each line.
+
+SC_ScaleLine (ASM)
+------------
+Low level scaling routine to scale a given source of byte values (0-15) to
+a given point on the screen. No bounds checking. This is self modifying
+unwound code (coding purists go hide), with a string of 200 scaling
+operations that get a RET stuck in the code after the number of pixels
+that need to be scaled have been.
+
+
+DEPENDENCIES
+------------
+
+
+LIMITATIONS
+-----------
+Shapes must never scale over MAXHEIGHT pixels high, or the scale tables are
+invalid. Greater than 256 character height is impossible without major
+changes in any case.
+
+The clipping bounds must be between 0 and 320 horizontally or the byte/mask
+tables are invalid.
+
+The segmented scaling isn't perfect
+
+
+POSSIBLE IMPROVEMENTS
+---------------------
+256 color VGA scaling can be done over twice as fast as 16 color EGA
+because the pixels can be written out without having to load the latches!
+Sparsing the shape with horizontal scans would also make an improvement.
+
+SCALESTEP probably shouldn't be linear, as size change perception varies
+with the original size
+
+Seperate horizontal/vertical scaling for stretching effects
+
+vertical clipping
+
+Bitmap holography... (coming soon!)
+
+=============================================================================
+*/
+
+#define MAXPICHEIGHT 256 // tallest pic to be scaled
+#define BACKGROUND 5 // background pixel for make shape
+
+#define BASESCALE 64 // normal size
+#define MAXSCALE 256 // largest scale possible
+#define SCALESTEP 3
+#define DISCREETSCALES (MAXSCALE/SCALESTEP)
+
+
+
+typedef struct scseg
+{
+ int start; // relative to top of shape
+ int length; // pixels in this segment
+ unsigned next; // offset from segment, NULL if last segment
+ char data[]; // pixel values
+} scaleseg;
+
+typedef struct
+{
+ int width; // number of vertical lines
+ int height; // only used for centering
+ unsigned first[]; // offsets from segment to topmost segment on
+ // each line, NULL if no pixels on line
+} scaleshape;
+
+
+#define SCREENPIXELS 320
+
+unsigned char bytetable[SCREENPIXELS],masktable[SCREENPIXELS];
+
+memptr basetableseg,screentableseg; // segment of basetables and screentables
+unsigned basetables[DISCREETSCALES], // offsets in basetableseg
+ screentables[DISCREETSCALES]; // offsets in screentableseg
+
+int scalexl = 0,
+ scalexh = 319,
+ scaleyl = 0,
+ scaleyh = 144;
+
+unsigned scaleblockwidth,
+ scaleblockheight,
+ scaleblockdest;
+
+//==========================================================================
+
+/*
+===========================
+=
+= SC_Setup
+=
+===========================
+*/
+
+void SC_Setup (void)
+{
+ unsigned mask,i,step,scale,space;
+ unsigned char far *baseptr, far *screenptr;
+ unsigned offset1,offset2,size;
+
+ //
+ // fast ploting tables
+ //
+ mask = 128;
+ for (i=0;i<320;i++)
+ {
+ bytetable[i]=i/8;
+ masktable[i]=mask;
+ if (!(mask>>=1))
+ mask = 128;
+ }
+
+ //
+ // fast scaling tables
+ //
+
+ offset1 = offset2 = 0;
+
+ for (step=0;step<DISCREETSCALES;step++)
+ {
+ screentables [step] = offset1;
+ scale = (step+1)*SCALESTEP;
+ size = scale*MAXPICHEIGHT/BASESCALE;
+ offset1 += size+1;
+ basetables [step] = offset2;
+ offset2 += MAXPICHEIGHT;
+ }
+
+ MMGetPtr(&basetableseg,offset2);
+ MMGetPtr(&screentableseg,offset1);
+
+ for (step=0;step<DISCREETSCALES;step++)
+ {
+ baseptr = (unsigned char _seg *)basetableseg + basetables[step];
+ screenptr = (unsigned char _seg *)screentableseg + screentables[step];
+
+ scale = (step+1)*SCALESTEP;
+ size = scale*MAXPICHEIGHT/BASESCALE;
+
+ for (i=0;i<MAXPICHEIGHT;i++)
+ *baseptr++ = scale*i/BASESCALE; // basetable
+
+ for (i=0;i<=size;i++)
+ *screenptr++ = i*BASESCALE/scale; // screentable
+ }
+
+}
+
+//==========================================================================
+
+/*
+===========================
+=
+= MakeShape
+=
+= Takes a raw bit map of width bytes by height and creates a scaleable shape
+=
+= Returns the length of the shape in bytes
+=
+===========================
+*/
+
+
+void SC_MakeShape (memptr src,int width,int height, memptr *shapeseg)
+{
+ int pixwidth,x,y;
+
+//
+// bit plane to byte vars
+//
+ unsigned char far *plane0,far *plane1,far *plane2,far *plane3;
+ unsigned char by0,by1,by2,by3;
+ unsigned b,offset,color,shift;
+
+//
+// sparse convert vars
+//
+ int hitpixel,start,length;
+ unsigned far *segptr;
+ char far *saveptr;
+ char far *byteptr, far *dataptr;
+ memptr byteseg;
+ scaleshape _seg *tempseg;
+
+
+ pixwidth = width*8;
+
+ MMGetPtr(&(memptr)tempseg,pixwidth*(height+20)); // larger than needed buffer
+
+ tempseg->width = pixwidth; // pixel dimensions
+ tempseg->height = height;
+
+//
+// convert ega pixels to byte color values in a temp buffer
+//
+// Stored in a collumn format, not rows!
+//
+ MMGetPtr(&byteseg,pixwidth*height);
+
+ byteptr = (char far *)byteseg;
+
+ plane0 = src;
+ plane1 = plane0 + width*height;
+ plane2 = plane1 + width*height;
+ plane3 = plane2 + width*height;
+
+ for (x=0;x<width;x++)
+ for (b=0;b<8;b++)
+ {
+ shift=8-b;
+ offset = x;
+
+ for (y=0;y<height;y++)
+ {
+ by0 = *(plane0+offset);
+ by1 = *(plane1+offset);
+ by2 = *(plane2+offset);
+ by3 = *(plane3+offset);
+ offset+=width;
+
+ color = 0;
+ asm mov cl,[BYTE PTR shift]
+ asm mov al,[BYTE PTR by3]
+ asm rcr al,cl;
+ asm rcl [BYTE PTR color],1;
+
+ asm mov cl,[BYTE PTR shift]
+ asm mov al,[BYTE PTR by2]
+ asm rcr al,cl;
+ asm rcl [BYTE PTR color],1;
+
+ asm mov cl,[BYTE PTR shift]
+ asm mov al,[BYTE PTR by1]
+ asm rcr al,cl;
+ asm rcl [BYTE PTR color],1;
+
+ asm mov cl,[BYTE PTR shift]
+ asm mov al,[BYTE PTR by0]
+ asm rcr al,cl;
+ asm rcl [BYTE PTR color],1;
+
+ *byteptr++ = color;
+ } // Y
+
+ } // B / X
+
+//
+// convert byte map to sparse scaling format
+//
+ saveptr = (char far *)&tempseg->first[pixwidth];
+ // start filling in data after all pointers to line segments
+
+ byteptr = byteseg; // first pixel in byte array
+
+ for (x=0;x<pixwidth;x++)
+ {
+//
+// each vertical line can have 0 or more segments of pixels in it
+//
+ y= 0;
+ segptr = (unsigned far *)&tempseg->first[x];
+ *segptr = 0; // in case there are no segments on line
+ do
+ {
+ // scan for first pixel to be scaled
+ while (*byteptr == BACKGROUND && y<height)
+ {
+ byteptr++;
+ y++;
+ }
+ if (y==height) // if not, the line is finished
+ continue;
+
+//
+// start a segment by pointing the last link (either shape.first[x] if it
+// is the first segment, or a seg.next if not) to the current spot in
+// the tempseg, setting segptr to this segments next link, and copying
+// all the pixels in the segment
+//
+ *segptr = FP_OFF(saveptr); // pointer to start of this segment
+
+ start = y;
+ length = 0;
+
+ dataptr = &((scaleseg far *)saveptr)->data[0];
+
+ //
+ // copy bytes in the segment to the shape
+ //
+ while (*byteptr != BACKGROUND && y<height)
+ {
+ length++;
+ *dataptr++ = *byteptr++;
+ y++;
+ }
+ ((scaleseg far *)saveptr)->start = start;
+ ((scaleseg far *)saveptr)->length = length;
+ ((scaleseg far *)saveptr)->next = 0;
+ // get ready for next segment
+ segptr = (unsigned far *)&((scaleseg far *)saveptr)->next;
+ saveptr = dataptr; // next free byte to be used
+
+ } while (y<height);
+
+ }
+
+//
+// allocate exact space needed and copy shape to it, then free buffers
+//
+
+ MMGetPtr (shapeseg,FP_OFF(saveptr));
+ _fmemcpy (*shapeseg,tempseg,FP_OFF(saveptr));
+ MMFreePtr (&byteseg);
+ MMFreePtr (&(memptr)tempseg);
+}
+
+
+//==========================================================================
+
+
+/*
+====================
+=
+= SC_ScaleShape
+=
+= Scales the shape centered on x,y to size scale (256=1:1, 512=2:1, etc)
+=
+= Clips to scalexl/scalexh, scaleyl/scaleyh
+= Returns true if something was drawn
+=
+= Must be called in write mode 2!
+=
+====================
+*/
+int SC_ScaleShape (int x,int y,unsigned scale, memptr shape)
+{
+ int scalechop;
+ unsigned fullwidth,fullheight,scalewidth,scaleheight;
+ int xl,xh,yl,yh,sx,sy,sxl,sxh,syl,syh;
+ unsigned screencorner,screen,yoffset,shapeofs,xbyte,mask;
+ int shapex,i,blockx,blocky;
+ scaleseg far *shapeptr;
+ unsigned char far *basetoscreenptr, far *screentobaseptr;
+ unsigned char far *masterptr;
+
+ scalechop = scale/SCALESTEP - 1;
+
+ if (scalechop<0)
+ return 0; // can't scale this size
+
+ if (scalechop>=DISCREETSCALES)
+ scalechop = DISCREETSCALES-1;
+
+ basetoscreenptr = (unsigned char _seg *)basetableseg + basetables[scalechop];
+ screentobaseptr = (unsigned char _seg *)screentableseg + screentables[scalechop];
+
+
+//
+// figure bounding rectangle for scaled image
+//
+ fullwidth = ((scaleshape _seg *)shape)->width;
+ fullheight = ((scaleshape _seg *)shape)->height;
+
+ scalewidth = fullwidth*((scalechop+1)*SCALESTEP)/BASESCALE; //basetoscreenptr[fullwidth-1];
+ scaleheight = basetoscreenptr[fullheight-1];
+
+ xl=x-scalewidth/2;
+ xh=xl+scalewidth-1;
+ yl=y-scaleheight/2;
+ yh=yl+scaleheight-1;
+
+
+// off screen?
+
+ if (xl>scalexh || xh<scalexl || yl>scaleyh || yh<scaleyl)
+ return 0;
+
+//
+// clip to sides of screen
+//
+ if (xl<scalexl)
+ sxl=scalexl;
+ else
+ sxl=xl;
+ if (xh>scalexh)
+ sxh=scalexh;
+ else
+ sxh=xh;
+
+//
+// clip both sides to zbuffer
+//
+ sx=sxl;
+ while (zbuffer[sx]>scale && sx<=sxh)
+ sx++;
+ sxl=sx;
+
+ sx=sxh;
+ while (zbuffer[sx]>scale && sx>sxl)
+ sx--;
+ sxh=sx;
+
+ if (sxl>sxh)
+ return 0; // behind a wall
+
+//
+// save block info for background erasing
+//
+ screencorner = screenofs+yl*linewidth;
+
+ scaleblockdest = screencorner + sxl/8;
+ scaleblockwidth = sxh/8-sxl/8+1;
+ scaleblockheight = yh-yl+1;
+
+
+//
+// start drawing
+//
+
+
+ for (sx=sxl;sx<=sxh;sx++)
+ {
+ shapex=screentobaseptr[sx-xl];
+
+ if ( (shapeofs = ((scaleshape _seg *)shape)->first[shapex]) != 0)
+ {
+ xbyte = bytetable[sx];
+ mask = masktable[sx];
+ if (scale>BASESCALE)
+ {
+ //
+ // make a multiple pixel scale pass if possible
+ //
+ while ( ( (sx&7) != 7) && (screentobaseptr[sx+1-xl] == shapex) )
+ {
+ sx++;
+ mask |= masktable[sx];
+ }
+ }
+
+ //
+ // set bit mask
+ //
+asm mov ah,[BYTE PTR mask]
+asm mov al,GC_BITMASK
+asm mov dx,GC_INDEX
+asm out dx,ax
+
+ do
+ {
+ shapeptr=MK_FP(FP_SEG(shape),shapeofs);
+ yoffset=basetoscreenptr[shapeptr->start];// pixels on screen to be skipped
+ screen=screencorner+ylookup[yoffset]+xbyte;
+
+ ScaleLine
+ (basetoscreenptr[shapeptr->length],
+ screentobaseptr,
+ &shapeptr->data[0],
+ screen);
+
+ shapeofs = shapeptr->next;
+ } while (shapeofs);
+ }
+ }
+
+ return 1;
+}
+
+
+
diff --git a/HOVTEXT.C b/HOVTEXT.C
new file mode 100644
index 0000000..64768c5
--- /dev/null
+++ b/HOVTEXT.C
@@ -0,0 +1,196 @@
+/* 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.
+ */
+
+char *levnames[20] =
+{/*......................................*/
+ "Zone 1: Langston Research Facility",
+ "Zone 2: Gardens of Marvin M. Mitchell",
+ "Zone 3: Caves, Brazos de la Madre",
+ "Zone 4: Fort Smith",
+ "Zone 5: Coyote Canyon",
+ "Zone 6: Santa Maria Cathedral",
+ "Zone 7: Pax Humana Commune",
+ "Zone 8: Sewers below New Trenton",
+ "Zone 9: Old UFA Headquarters",
+ "Zone 10: Braker's Mountain",
+ "Zone 11: Wounded Village",
+ "Zone 12: Murder Hill",
+ "Zone 13: TerraChem Corp.",
+ "Zone 14: Gulf Tech University",
+ "Zone 15: Agromatic Inc. Farm",
+ "Zone 16: National Agency for Defense",
+ "Zone 17: Jackson International Airport",
+ "Zone 18: Museum of Modern Art",
+ "Zone 19: AUF Headquarters",
+ "Zone 20: UFA Headquarters",
+};
+
+
+char *levtext[20] =
+{/*......................................*/
+ "Your first assignment is to rescue a\n"
+ "bunch of scientists who have\n"
+ "barracaded themselves inside the\n"
+ "Langston Research Facility. They were\n"
+ "working on a new, clean fuel until\n"
+ "some big oil corporations decided to\n"
+ "buy Langston out. Now insiders say\n"
+ "the corporation is going to nuke them.\n"
+
+,/*......................................*/
+ "The Mitchell estate is home to many of\n"
+ "the world's most famous activists,\n"
+ "philanthropists, and do-gooders.\n"
+ "We've just found out that a group of\n"
+ "extremely rich industrialists have\n"
+ "funded a tactical strike on the estate\n"
+ "after some of the activists irritated\n"
+ "some of their interests.\n"
+
+,/*......................................*/
+ "A group of terrorists known as The Dark\n"
+ "Legion are holding a bunch of children\n"
+ "hostage until their demands are met.\n"
+ "The goverment has decided, with their\n"
+ "usual compassion, to nuke the Legion\n"
+ "along with their hostages. Get the\n"
+ "hostages out of there.\n"
+
+,/*......................................*/
+ "The last renegades of the local\n"
+ "resistance are imprisoned for holding\n"
+ "rallies and publishing their anti-\n"
+ "government pamphlets. A superpower is\n"
+ "is planning to nuke Fort Smith for its\n"
+ "strategic importance. We want those\n"
+ "renegades.\n"
+
+,/*......................................*/
+ "A brilliant scientist and his daughter\n"
+ "are living on a missile site in the\n"
+ "canyon. The site is a military target,\n"
+ "and we want you to get Professor\n"
+ "Phillips back safely to Headquarters.\n"
+
+,/*......................................*/
+ "A group of priests have been tending\n"
+ "the dying at the cathedral, even\n"
+ "though their area is likely to be\n"
+ "bombed again. The mutants swarming\n"
+ "the area are insane. Be careful!\n"
+
+,/*......................................*/
+ "This commune of peace demonstrators is\n"
+ "about to be toasted by the NMC -- the\n"
+ "National Munitions Corporation. Pax\n"
+ "Humana has been a thorn in their side\n"
+ "for many years. The thorn is about to\n"
+ "be removed...by nuclear means.\n"
+
+,/*......................................*/
+ "This city's sewers hold the survivors\n"
+ "of the last nuclear attack. Unlucky\n"
+ "for them, the last one wasn't the\n"
+ "last one....\n"
+
+,/*......................................*/
+ "Some operatives remain at the old\n"
+ "headquarters after the move, and\n"
+ "those looking for us have finally\n"
+ "located the old base. You'll have\n"
+ "to work fast.\n"
+
+,/*......................................*/
+ "A dangerous horde of mutants are\n"
+ "holding humans prisoner inside the\n"
+ "mountain. Rescue them before the\n"
+ "area is 'sanitized.'\n"
+
+,/*......................................*/
+ "Drones have gone rampant and are\n"
+ "killing the population of this\n"
+ "village. Before the situation is\n"
+ "'gotten under control,' you need to\n"
+ "get those people out of there.\n"
+
+,/*......................................*/
+ "A tank brigade is hunting down AWOL\n"
+ "soldiers. Little do they know that\n"
+ "the whole area is about be baked by\n"
+ "enemy missiles. Those soldiers have\n"
+ "some interesting information that we\n"
+ "would like to acquire.\n"
+
+,/*......................................*/
+ "There are engineers trapped in the\n"
+ "TerraChem building. Get them back so\n"
+ "they can testify against TerraChem.\n"
+ "But hurry, the whole building's gonna\n"
+ "blow!\n"
+
+,/*......................................*/
+ "Terrorists are about to bomb Gulf Tech\n"
+ "University off the face of the earth.\n"
+ "We haven't been able to reach the\n"
+ "scientists there. Get them out of there!\n"
+
+,/*......................................*/
+ "The Agromatic Inc. Corporate farm is\n"
+ "being nuked by their competitors at\n"
+ "at TerraTronic Inc. Get the innocent\n"
+ "farmers to safety.\n"
+
+,/*......................................*/
+ "Some of our UFA spies are trapped in\n"
+ "NAD headquarters. Rescue them before\n"
+ "the enemy missiles get there.\n"
+
+,/*......................................*/
+ "The airport is under siege by\n"
+ "terrorist forces. Get the civilians \n"
+ "out before the Company takes care of\n"
+ "the situation.\n"
+
+,/*......................................*/
+ "The Museum is going to be bombed by\n"
+ "by Dadaists. The bombing is their\n"
+ "form of anti-expression. They've\n"
+ "barred the exits and the missiles are\n"
+ "coming. Good luck.\n"
+
+,/*......................................*/
+ "Our competitors, the Alliance for a\n"
+ "Utopian Future, are getting a little\n"
+ "too good to ignore. We're nuking them.\n"
+ "However, we really don't want to kill\n"
+ "anyone, so get them out of there\n"
+ "before our missiles get there.\n"
+ "It's just a matter of business, you\n"
+ "understand..."
+
+,/*......................................*/
+ "The AUF apparently had a backup strike\n"
+ "force that we didn't know about. All\n"
+ "our people are alerted, but there are\n"
+ "a number of people on the lower levels\n"
+ "that won't be able to get out in time.\n"
+ "Get them quick! Meet you at Basepoint\n"
+ "Delta!\n"
+
+};
+
diff --git a/HOVTRACE.C b/HOVTRACE.C
new file mode 100644
index 0000000..076032c
--- /dev/null
+++ b/HOVTRACE.C
@@ -0,0 +1,822 @@
+/* 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"
+
+//==========================================================================
+
+int FinishWall (void);
+
+//==========================================================================
+
+fixed edgex,edgey;
+
+int wallon;
+int basecolor;
+
+walltype *oldwall;
+
+//
+// offsets from upper left corner of a tile to the left and right edges of
+// a given wall (NORTH-WEST)
+//
+fixed point1x[4] = {GLOBAL1,GLOBAL1,0 ,0 };
+fixed point1y[4] = {0 ,GLOBAL1,GLOBAL1,0 };
+
+fixed point2x[4] = {0 ,GLOBAL1,GLOBAL1,0 };
+fixed point2y[4] = {0 ,0 ,GLOBAL1 ,GLOBAL1};
+
+
+//
+// offset from tile.x,tile.y of the tile that shares wallon side
+// (side is not visable if it is shared)
+//
+int sharex[4] = { 0, 1, 0,-1};
+int sharey[4] = {-1, 0, 1, 0};
+
+//
+// amount to move tile.x,tile.y to follow wallon to another tile
+//
+int followx[4] = {-1, 0, 1, 0};
+int followy[4] = { 0,-1, 0, 1};
+
+//
+// cornerwall gives the wall on the same tile to start following when the
+// wall ends at an empty tile (go around an edge on same tile)
+// turnwall gives the wall on tile.x+sharex,tile.y+sharey to start following
+// when the wall hits another tile (right angle corner)
+//
+int cornerwall[4] = {WEST,NORTH,EAST,SOUTH};
+int turnwall[4] = {EAST,SOUTH,WEST,NORTH};
+
+//
+// wall visabilities in reletive locations
+// -,- 0,- +,-
+// -,0 0,0 +,0
+// -,+ 0,+ +,+
+//
+int visable[9][4] =
+{
+ {0,1,1,0}, {0,0,1,0}, {0,0,1,1},
+ {0,1,0,0}, {0,0,0,0}, {0,0,0,1},
+ {1,1,0,0}, {1,0,0,0}, {1,0,0,1}
+};
+
+int startwall[9] = {2,2,3, 1,0,3, 1,0,0};
+int backupwall[9] = {3,3,0, 2,0,0, 2,1,1};
+
+
+
+/*
+========================
+=
+= FollowTrace
+=
+========================
+*/
+
+int FollowTrace (fixed tracex, fixed tracey, long deltax, long deltay, int max)
+{
+ int tx,ty,otx,oty;
+ long absdx,absdy,xstep,ystep;
+
+ tx = tracex>>TILESHIFT;
+ ty = tracey>>TILESHIFT;
+
+ absdx=LABS(deltax);
+ absdy=LABS(deltay);
+
+ if (absdx>absdy)
+ {
+ ystep = (deltay<<8)/(absdx>>8);
+
+ if (!ystep)
+ ystep = deltay>0 ? 1 : -1;
+
+ oty = (tracey+ystep)>>TILESHIFT;
+ if (deltax>0)
+ {
+//###############
+//
+// step x by +1
+//
+//###############
+ do
+ {
+ tx++;
+ tracey+=ystep;
+ ty = tracey>>TILESHIFT;
+
+ if (ty!=oty)
+ {
+ if (tilemap[tx-1][ty])
+ {
+ tile.x = tx-1;
+ tile.y = ty;
+ return 1;
+ }
+ oty = ty;
+ }
+ if (tilemap[tx][ty])
+ {
+ tile.x = tx;
+ tile.y = ty;
+ return 1;
+ }
+ } while (--max);
+ return 0;
+ }
+ else
+ {
+//###############
+//
+// step x by -1
+//
+//###############
+ do
+ {
+ tx--;
+ tracey+=ystep;
+ ty = tracey>>TILESHIFT;
+
+ if (ty!=oty)
+ {
+ if (tilemap[tx][oty])
+ {
+ tile.x = tx;
+ tile.y = oty;
+ return 1;
+ }
+ oty = ty;
+ }
+ if (tilemap[tx][ty])
+ {
+ tile.x = tx;
+ tile.y = ty;
+ return 1;
+ }
+ } while (--max);
+ return 0;
+
+ }
+ }
+ else
+ {
+ xstep = (deltax<<8)/(absdy>>8);
+ if (!xstep)
+ xstep = deltax>0 ? 1 : -1;
+
+
+ otx = (tracex+xstep)>>TILESHIFT;
+ if (deltay>0)
+ {
+//###############
+//
+// step y by +1
+//
+//###############
+ do
+ {
+ ty++;
+ tracex+=xstep;
+ tx = tracex>>TILESHIFT;
+
+ if (tx!=otx)
+ {
+ if (tilemap[tx][ty-1])
+ {
+ tile.x = tx;
+ tile.y = ty-1;
+ return 1;
+ }
+ otx = tx;
+ }
+ if (tilemap[tx][ty])
+ {
+ tile.x = tx;
+ tile.y = ty;
+ return 1;
+ }
+ } while (--max);
+ return 0;
+ }
+ else
+ {
+//###############
+//
+// step y by -1
+//
+//###############
+ do
+ {
+ ty--;
+ tracex+=xstep;
+ tx = tracex>>TILESHIFT;
+
+ if (tx!=otx)
+ {
+ if (tilemap[otx][ty])
+ {
+ tile.x = otx;
+ tile.y = ty;
+ return 1;
+ }
+ otx = tx;
+ }
+ if (tilemap[tx][ty])
+ {
+ tile.x = tx;
+ tile.y = ty;
+ return 1;
+ }
+ } while (--max);
+ return 0;
+ }
+
+ }
+
+}
+
+
+//===========================================================================
+
+
+/*
+=================
+=
+= BackTrace
+=
+= Traces backwards from edgex,edgey to viewx,viewy to see if a closer
+= tile obscures the given point. If it does, it finishes the wall and
+= starts a new one.
+= Returns true if a tile is hit.
+= Call with a 1 to have it automatically finish the current wall
+=
+=================
+*/
+
+int BackTrace (int finish)
+{
+ fixed tracex,tracey;
+ long deltax,deltay,absdx,absdy;
+ int steps,otx,oty,testx,testheight,offset,wall;
+
+ deltax = viewx-edgex;
+ deltay = viewy-edgey;
+
+ absdx = LABS(deltax);
+ absdy = LABS(deltay);
+
+ if (absdx>absdy)
+ steps = ABS(focal.x-(edgex>>TILESHIFT))-1;
+ else
+ steps = ABS(focal.y-(edgey>>TILESHIFT))-1;
+
+ if (steps<=0)
+ return 0;
+
+ otx = tile.x;
+ oty = tile.y;
+ if (!FollowTrace(edgex,edgey,deltax,deltay,steps))
+ return 0;
+
+//
+// if the start wall is behind the focal point, the trace went too far back
+//
+ if (ABS(tile.x-focal.x)<2 && ABS(tile.y-focal.y)<2) // too close
+ {
+ if (tile.x == focal.x && tile.y == focal.y)
+ {
+ tile.x = otx;
+ tile.y = oty;
+ return 0;
+ }
+
+ if (tile.x<focal.x)
+ {
+ if (tile.y<focal.y)
+ wall = SOUTH;
+ else
+ wall = EAST;
+ }
+ else if (tile.x==focal.x)
+ {
+ if (tile.y<focal.y)
+ wall = SOUTH;
+ else
+ wall = NORTH;
+ }
+ else
+ {
+ if (tile.y<=focal.y)
+ wall = WEST;
+ else
+ wall = NORTH;
+ }
+
+ //
+ // rotate the X value to see if it is behind the view plane
+ //
+ if (TransformX (((long)tile.x<<16)+point1x[wall],
+ ((long)tile.y<<16)+point1y[wall]) < FOCALLENGTH)
+ {
+ tile.x = otx;
+ tile.y = oty;
+ return 0;
+ }
+ }
+
+//
+// if the old wall is still behind a closer wall, ignore the back trace
+// and continue on (dealing with limited precision...)
+//
+ if (finish && !FinishWall ()) // the wall is still behind a forward wall
+ {
+ tile.x = otx;
+ tile.y = oty;
+ rightwall->x1 = oldwall->x2; // common edge with last wall
+ rightwall->height1 = oldwall->height2;
+ return 0;
+ }
+
+
+//
+// back up along the intersecting face to find the rightmost wall
+//
+
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ wallon = backupwall[offset];
+
+ while (tilemap[tile.x][tile.y])
+ {
+ tile.x += followx[wallon];
+ tile.y += followy[wallon];
+ };
+
+ tile.x -= followx[wallon];
+ tile.y -= followy[wallon];
+
+ wallon = cornerwall[wallon]; // turn to first visable face
+
+ edgex = ((long)tile.x<<16);
+ edgey = ((long)tile.y<<16);
+
+ TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
+ &rightwall->x1,&rightwall->height1);
+
+ basecolor = tilemap[tile.x][tile.y];
+
+ return 1;
+}
+
+//===========================================================================
+
+
+/*
+=================
+=
+= ForwardTrace
+=
+= Traces forwards from edgex,edgey along the line from viewx,viewy until
+= a solid tile is hit. Sets tile.x,tile.y
+=
+=================
+*/
+
+void ForwardTrace (void)
+{
+ int offset;
+ fixed tracex,tracey;
+ long deltax,deltay;
+
+ deltax = edgex-viewx;
+ deltay = edgey-viewy;
+
+ FollowTrace(edgex,edgey,deltax,deltay,0);
+
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ wallon = startwall[offset];
+
+//
+// start the new wall
+//
+ edgex = ((long)tile.x<<16);
+ edgey = ((long)tile.y<<16);
+
+//
+// if entire first wall is invisable, corner
+//
+ TransformPoint (edgex+point2x[wallon],edgey+point2y[wallon],
+ &rightwall->x2,&rightwall->height2);
+
+ if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]]
+ || rightwall->x2 < (rightwall-1)->x2 )
+ wallon = cornerwall [wallon];
+
+//
+// transform first point
+//
+
+ TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
+ &rightwall->x1,&rightwall->height1);
+
+ basecolor = tilemap[tile.x][tile.y];
+}
+
+
+//===========================================================================
+
+
+/*
+=================
+=
+= FinishWall
+=
+= Transforms edgex,edgey as the next point of the current wall
+= and sticks it in the wall list
+=
+=================
+*/
+
+int FinishWall (void)
+{
+ char num[20];
+
+ oldwall = rightwall;
+
+ if (wallon&1)
+ rightwall->color = basecolor+8; // high intensity walls
+ else
+ rightwall->color = basecolor;
+
+ TransformPoint (edgex,edgey,&rightwall->x2,&rightwall->height2);
+
+ if (rightwall->x2 <= (rightwall-1)->x2+2
+ && rightwall->height2 < (rightwall-1)->height2 )
+ return 0;
+
+ rightwall++;
+
+ return 1;
+}
+
+//===========================================================================
+
+
+/*
+=================
+=
+= InsideCorner
+=
+=================
+*/
+
+void InsideCorner (void)
+{
+ int offset;
+
+ //
+ // the wall turned -90 degrees, so draw what we have, move to the new tile,
+ // change wallon, change color, and continue following.
+ //
+ FinishWall ();
+
+ tile.x += sharex[wallon];
+ tile.y += sharey[wallon];
+
+ wallon = turnwall[wallon];
+
+ //
+ // if the new wall is visable, continue following it. Otherwise
+ // follow it backwards until it turns
+ //
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ if (visable[offset][wallon])
+ {
+ //
+ // just turn to the next wall and continue
+ //
+ rightwall->x1 = oldwall->x2; // common edge with last wall
+ rightwall->height1 = oldwall->height2;
+ basecolor = tilemap[tile.x][tile.y];
+ return; // continue from here
+ }
+
+ //
+ // back follow the invisable wall until it turns, then follow that
+ //
+ do
+ {
+ tile.x += followx[wallon];
+ tile.y += followy[wallon];
+ } while (tilemap[tile.x][tile.y]);
+
+ tile.x -= followx[wallon];
+ tile.y -= followy[wallon];
+
+ wallon = cornerwall[wallon]; // turn to first visable face
+
+ edgex = ((long)tile.x<<16)+point1x[wallon];
+ edgey = ((long)tile.y<<16)+point1y[wallon];
+
+ if (!BackTrace(0)) // backtrace without finishing a wall
+ {
+ TransformPoint (edgex,edgey,&rightwall->x1,&rightwall->height1);
+ basecolor = tilemap[tile.x][tile.y];
+ }
+}
+
+//===========================================================================
+
+
+/*
+=================
+=
+= OutsideCorner
+=
+=================
+*/
+
+void OutsideCorner (void)
+{
+ int offset;
+
+ //
+ // edge is the outside edge of a corner, so draw the current wall and
+ // turn the corner (+90 degrees)
+ //
+ FinishWall ();
+
+ tile.x -= followx[wallon]; // backup to the real tile
+ tile.y -= followy[wallon];
+ wallon = cornerwall[wallon];
+
+ //
+ // if the new wall is visable, continue following it. Otherwise
+ // trace a ray from the corner to find a wall in the distance to
+ // follow
+ //
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ if (visable[offset][wallon])
+ {
+ //
+ // the new wall is visable, so just continue on
+ //
+ rightwall->x1 = oldwall->x2; // common edge with last wall
+ rightwall->height1 = oldwall->height2;
+ return; // still on same tile, so color is ok
+ }
+
+//
+// start from a new tile further away
+//
+ ForwardTrace(); // find the next wall further back
+
+}
+
+
+//===========================================================================
+
+
+/*
+=================
+=
+= FollowWalls
+=
+= Starts a wall edge at the leftmost edge of tile.x,tile.y and follows it
+= until something else is seen or the entire view area is covered
+=
+=================
+*/
+
+void FollowWalls (void)
+{
+ int height,newcolor,offset,wall;
+
+//####################
+//
+// figure leftmost wall of new tile
+//
+//####################
+
+restart:
+
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ wallon = startwall[offset];
+
+//
+// if the start wall is inside a block, skip it by cornering to the second wall
+//
+ if ( tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])
+ wallon = cornerwall [wallon];
+
+//
+// transform first edge to screen coordinates
+//
+ edgex = ((long)tile.x<<16);
+ edgey = ((long)tile.y<<16);
+
+ TransformPoint (edgex+point1x[wallon],edgey+point1y[wallon],
+ &rightwall->x1,&rightwall->height1);
+
+ basecolor = tilemap[tile.x][tile.y];
+
+//##################
+//
+// follow the wall as long as possible
+//
+//##################
+
+advance:
+
+ do // while ( tile.x != right.x || tile.y != right.y)
+ {
+//
+// check for conditions that shouldn't happed...
+//
+ if (rightwall->x1 > VIEWXH) // somehow missed right tile...
+ return;
+
+ if (rightwall == &walls[DANGERHIGH])
+ {
+ //
+ // somethiing got messed up! Correct by thrusting ahead...
+ //
+ ColorBorder(15);
+ bordertime = 60;
+ Thrust();
+ if (++obon.angle==ANGLES)
+ obon.angle = 0;
+ objlist[0] = obon;
+ StartView ();
+ goto restart;
+
+ #if 0
+ strcpy (str,"Wall list overflow at LE:");
+ itoa(level,num,10);
+ strcat (str,num);
+ strcat (str," X:");
+ ltoa(objlist[0].x,num,10);
+ strcat (str,num);
+ strcat (str," Y:");
+ ltoa(objlist[0].y,num,10);
+ strcat (str,num);
+ strcat (str," AN:");
+ itoa(objlist[0].angle,num,10);
+ strcat (str,num);
+
+ Quit (str);
+ #endif
+ }
+
+//
+// proceed along wall
+//
+
+ edgex = ((long)tile.x<<16)+point2x[wallon];
+ edgey = ((long)tile.y<<16)+point2y[wallon];
+
+ if (BackTrace(1)) // went behind a closer wall
+ continue;
+
+ //
+ // advance to next tile along wall
+ //
+ tile.x += followx[wallon];
+ tile.y += followy[wallon];
+
+ if (tilemap [tile.x+sharex[wallon]] [tile.y+sharey[wallon]])
+ {
+ InsideCorner (); // turn at a corner
+ continue;
+ }
+
+ newcolor = tilemap[tile.x][tile.y];
+
+ if (!newcolor) // turn around an edge
+ {
+ OutsideCorner ();
+ continue;
+ }
+
+ if (newcolor != basecolor)
+ {
+ //
+ // wall changed color, so draw what we have and continue following
+ //
+ FinishWall ();
+ rightwall->x1 = oldwall->x2; // new wall shares this edge
+ rightwall->height1 = oldwall->height2;
+ basecolor = newcolor;
+
+ continue;
+ }
+
+
+ } while (tile.x != right.x || tile.y != right.y);
+
+
+
+//######################
+//
+// draw the last tile
+//
+//######################
+
+ edgex = ((long)tile.x<<16)+point2x[wallon];
+ edgey = ((long)tile.y<<16)+point2y[wallon];
+ FinishWall();
+
+ wallon = cornerwall[wallon];
+
+ //
+ // if the corner wall is visable, draw it
+ //
+ if (tile.y<focal.y)
+ offset = 0;
+ else if (tile.y==focal.y)
+ offset = 3;
+ else
+ offset = 6;
+ if (tile.x==focal.x)
+ offset ++;
+ else if (tile.x>focal.x)
+ offset += 2;
+
+ if (visable[offset][wallon])
+ {
+ rightwall->x1 = oldwall->x2; // common edge with last wall
+ rightwall->height1 = oldwall->height2;
+ edgex = ((long)tile.x<<16)+point2x[wallon];
+ edgey = ((long)tile.y<<16)+point2y[wallon];
+ FinishWall();
+ }
+
+}
+
+//===========================================================================
diff --git a/IDASM.ASM b/IDASM.ASM
new file mode 100644
index 0000000..b72f872
--- /dev/null
+++ b/IDASM.ASM
@@ -0,0 +1,1378 @@
+; 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.
+
+IDEAL
+MODEL SMALL,C
+
+;============================================================================
+;
+; Gamer's Edge Library, ASM section
+;
+;============================================================================
+
+
+
+;=======================================================================
+;
+; KEYBOARD ROUTINES
+;
+;=======================================================================
+
+
+DATASEG
+EVEN
+
+oldint9 dd 0
+keydown db 128 dup (0)
+NBKscan dw 0
+NBKascii dw 0
+
+scanascii db 0,27,49,50,51,52,53,54,55,56,57,48,45,61,8,9,113 ;'q'
+ db 119,101,114,116,121,117,105,111,112,91,93,13,0,97,115 ;'s'
+ db 100,102,103,104,106,107,108,59,39,96,0,92,122,120,99 ;'c'
+ db 118,98,110,109,44,46,47,0,42,0,32,0,1,1,1,1,1,1,1,1,1,1 ;f10
+ db 0,0,1,1,1,45,1,1,1,43,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0 ;shift-f10
+ db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 ;ctl-home
+ db 0,0,0,0,0,0,0,0,0,0,0,0,0
+
+PUBLIC keydown,NBKscan,NBKascii
+
+CODESEG
+
+;========
+;
+; StartupKbd
+;
+; Sets up the new INT 8 ISR and various internal pointers.
+; Assumes that the calling program has pointer soundseg to something
+; meaningful...
+;
+;========
+
+PROC StartupKbd
+PUBLIC StartupKbd
+
+ mov ax,3509h ;call bios to get int 9
+ int 21h
+ mov [WORD oldint9],bx
+ mov ax,es
+ mov [WORD oldint9+2],ax
+
+ push ds
+
+ push cs
+ pop ds
+ lea dx,[Int9Isr]
+ mov ax,2509h ;call bios to set int 9
+ int 21h
+
+ pop ds
+
+ ret
+
+ENDP
+
+
+
+;========
+;
+; ShutdownKbd
+;
+;========
+
+PROC ShutdownKbd
+PUBLIC ShutdownKbd
+
+ push ds
+
+ mov dx,[WORD Oldint9]
+ mov ds,[WORD Oldint9+2]
+ mov ax,2509h ;call bios to set int 8
+ int 21h
+
+ mov ax,40h ;clear ctrl/alt/shift flags
+ mov ds,ax
+ mov ax,[17h]
+ and ax,1111110011110000b
+ mov [17h],ax
+
+ pop ds
+ ret
+
+ENDP
+
+
+;========
+;
+; NoBiosKey
+;
+;========
+
+PROC NoBiosKey parm:WORD
+PUBLIC NoBiosKey
+
+ xor bh,bh
+ mov ax,[parm]
+ or ax,ax
+ jnz @@bioskey1
+@@waitforkey:
+ mov bl,[BYTE NBKscan]
+ or bl,bl
+ jns @@waitforkey
+ mov al,[BYTE NBKascii]
+ or al,al
+ jz @@waitforkey
+ mov ah,[BYTE NBKscan]
+ and [BYTE NBKscan],7fh
+ ret
+@@bioskey1:
+ mov al,[BYTE NBKascii]
+ mov ah,[BYTE NBKscan]
+ and ah,7fh
+ or al,al
+ jnz @@ok
+ xor ah,ah ; just a modifier key
+@@ok:
+ ret
+
+ENDP
+
+
+
+;========
+;
+; Int9ISR
+; only called by interrupt $9!
+;
+;=========
+
+PROC Int9ISR FAR
+PUBLIC Int9ISR
+
+ push ax
+ push bx
+ push ds
+
+ xor ah,ah
+ in al,60h ;get the key pressed
+ push ax
+
+ in al,61h
+ mov ah,al
+ or al,80h
+ out 61h,al
+ mov al,ah
+ out 61h,al
+
+ mov bx,_DATA
+ mov ds,bx ;ds to this data segment
+
+ pop ax
+ or al,al
+
+ jns @@keydown
+;
+; key released
+;
+ and al,7fh
+ mov bx,ax
+ mov [keydown+BX],ah ;keydown[key] = false
+ jmp @@done
+
+@@keydown:
+ mov [BYTE NBKscan],al
+ or [BYTE NBKscan],80h ;high bit set after press, cleared
+ mov bx,ax ;after NoBiosKey gets it
+ mov al,1
+ mov [keydown+BX],al ;keydown[key] = true
+ mov al,[scanascii+bx]
+ mov [BYTE NBKascii],al ;set the ascii code of key
+@@done:
+ mov al,20h
+ out 20h,al ;we got the interrupt here
+
+ pop ds
+ pop bx
+ pop ax
+
+ iret
+
+
+ENDP
+
+
+;============================================================================
+;
+; SOUND ROUTINES
+;
+;============================================================================
+
+ DATASEG
+
+;
+;offsets into .SPK file at segment SPKRfile, offset 0
+;
+;sound records each take up 16 bytes, and start at $10, and continue to $3F0
+
+snd_start equ 0
+snd_priority equ 2
+snd_samples equ 3
+snd_name equ 4
+
+timerspeed dw 0 ;clock speed for tic counting
+
+LABEL inttime WORD
+timecount dd 0,0 ;fast timer tics since startup
+
+SPKactive dw 0 ;set non zero when started
+
+soundmode dw 1 ;0=nosound, 1=SPKR, 2= adlib...
+OldInt8 dd ? ;StartupSPK saves here, Shutdown restores
+Intcount db ? ;counter for extraints, call OldInt8 at 0
+
+SndPtr dw ? ;Pointer to frequency of current sound
+SndPriority db ? ;current sound's priority
+
+pausesndptr dw ?
+pausepriority db ?
+pauseintcount db ?
+
+dontplay dw 0 ;set to 1 to avoid all interrupt and timer stuff
+
+int8hook dw 0 ;gets called every tic if not null
+
+soundseg dw ?
+
+PUBLIC soundmode,dontplay,timecount,inttime,timerspeed,int8hook,soundseg,sndptr
+PUBLIC SndPriority
+
+EXTRN soundblaster:WORD
+
+ CODESEG
+
+
+;========
+;
+; StartupSound
+;
+; Sets up the new INT 8 ISR and various internal pointers.
+; Assumes that the calling program has pointer soundseg to something
+; meaningful...
+;
+;========
+
+PROC StartupSound
+ PUBLIC StartupSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ test [SPKactive],0FFFFh ;see if library is active
+ jne @@started ;library was allready started
+
+@@start:
+ call NEAR PTR StopSound ;make sure nothing is playing
+
+ mov ax,3508h ;call bios to get int 8
+ int 21h
+ mov [WORD oldint8],bx
+ mov ax,es
+ mov [WORD oldint8+2],ax
+
+ push ds
+
+ push cs
+ pop ds
+ lea dx,[UpdateSPKR]
+ mov ax,2508h ;call bios to set int 8
+ int 21h
+
+ pop ds
+
+ mov bx,[timerspeed]
+ cli
+ mov al,36h ;tell the timer chip we are going to
+ out 43h,al ;change the speed of timer 0
+ mov al,0
+ mov al,bl
+ out 40h,al ;low
+ mov al,bh
+ out 40h,al ;high
+ sti
+
+ inc [SPKactive] ;sound routines are now active
+
+@@started:
+ mov ax,1
+ mov [soundmode],ax ;set soundmode to SPKR
+ ret
+
+ENDP
+
+
+;========
+;
+; CallTimer
+;
+; Call the bios int8 to turn off drive motors
+;
+;========
+
+PROC CallTimer
+PUBLIC CallTimer
+
+ test [WORD OldInt8+2],0ffffh
+ jz @@done
+
+ pushf
+ call [OldInt8]
+@@done:
+ ret
+ENDP
+
+
+;========
+;
+; ShutdownSound
+;
+;========
+
+PROC ShutdownSound
+ PUBLIC ShutdownSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ cli
+ mov al,36h ;tell the timer chip we are going to
+ out 43h,al ;change the speed of timer 0
+ mov al,0 ;system expects 0000 for rate
+ out 40h,al ;low
+ out 40h,al ;high
+ sti
+
+ mov ax,[SPKactive]
+ cmp ax,0
+ je @@done ;sound library wasn't started...
+
+ push ds
+
+ mov dx,[WORD Oldint8]
+ mov ax,[WORD Oldint8+2]
+ mov ds,ax
+ mov ax,2508h ;call bios to set int 8
+ int 21h
+
+ pop ds
+
+ mov [SPKactive],0 ;sound routines are now inactive
+
+ cli
+ in al,61h ;get peripheral (speaker) port value
+ and al,11111101b ;turn speaker off
+ out 61h,al
+ sti
+@@done:
+ ret
+
+ENDP
+
+
+
+;===========
+;
+; PlaySoundSPK (soundnum)
+;
+; If the sound's priority is >= the current priority, SoundPtr, SndPriority,
+; and the timer speed are changed
+;
+; Hacked for sound blaster support!
+;
+;===========
+
+EXTRN jmPlaySample:PROC
+
+PROC PlaySound playnum:WORD
+ USES SI
+ PUBLIC PlaySound
+
+ test [dontplay],-1 ;for profiler
+ jne @@playdone
+ test [soundmode],-1 ;f2 to turn off sound blaster also
+ je @@playdone
+
+ mov ax,[playnum] ;index into the sound headers
+
+ mov si,ax
+ shl si,1
+ shl si,1
+ shl si,1
+ shl si,1
+
+ mov es,[soundseg] ;point es: to the spkr file
+
+ mov al,[es:si+snd_Priority] ;priority table (one byte each)
+ cmp al,[SndPriority]
+ jb @@playdone ;current sound has higher priority
+ mov [SndPriority],al
+
+ test [soundblaster],-1
+ jz @@pc
+
+ push [playnum]
+ call jmPlaySample
+ pop ax
+ ret
+
+@@pc:
+ mov ax,[es:si+snd_Start] ;offset in .SPK file
+ mov [SndPtr],ax ;store it in the sound playing table
+
+
+@@playdone:
+ ret
+
+ENDP
+
+
+;======================================================================
+
+;===========
+;
+; StopSound
+;
+;===========
+
+PROC StopSound
+ PUBLIC StopSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ xor ax,ax ;set to 0
+ mov [SndPtr],ax
+ mov [SndPriority],al
+
+ cli
+
+ in al,61h ;get peripheral (speaker) port value
+ and al,11111101b ;turn speaker off
+ out 61h,al
+
+ sti
+
+ ret
+ENDP
+
+;======================================================================
+
+;===========
+;
+; PauseSound
+;
+;===========
+
+PROC PauseSound
+ PUBLIC PauseSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ mov ax,[SndPtr] ;save off the current values
+ mov [pausesndptr],ax
+ mov al,[SndPriority]
+ mov [pausepriority],al
+ mov al,[intcount]
+ mov [pauseintcount],al
+ call StopSound
+ ret
+ENDP
+
+;======================================================================
+
+;===========
+;
+; ContinueSound
+;
+;===========
+
+PROC ContinueSound
+ PUBLIC ContinueSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ mov ax,[pausesndptr]
+ mov [SndPtr],ax ;restore the old values
+ mov al,[pausepriority]
+ mov [SndPriority],al
+ mov al,[pauseintcount]
+ mov [intcount],al
+
+ ret
+ENDP
+
+;======================================================================
+
+;========
+;
+; WaitendSound
+; Just waits around until the current sound stops playing
+;
+;========
+
+PROC WaitEndSound
+ PUBLIC WaitEndSound
+
+ test [dontplay],0ffffh
+ je @@dowork
+ ret
+@@dowork:
+ pushf
+ call FAR PTR UpdateSPKR ;in case a sound was just started and hasn't
+ ;been hit by an INT yet
+@@wait:
+ mov ax,[sndptr]
+ cmp ax,0 ;when the ptr is 0, nothing is on
+ jne @@wait
+
+ ret
+
+ENDP
+
+;=========================================================================
+
+;========
+;
+; UpdateSPKR
+; only called by interrupt $8!
+;
+;=========
+
+DATASEG
+
+EVEN
+
+oldss dw ?
+oldsp dw ?
+
+fakestack dw 64 dup (?)
+
+PUBLIC fakestack
+
+CODESEG
+
+PROC UpdateSPKR FAR
+PUBLIC UpdateSPKR
+
+ push ax
+ push bx
+ push cx
+ push si
+ push ds
+ push es
+
+ mov al,20h
+ out 20h,al ;we got the interrupt here
+
+ mov ax,@Data
+ mov ds,ax ;ds to this data segment
+
+ add [WORD timecount],1 ;inced once every VBL time
+ adc [WORD timecount+2],0
+
+;
+; call a user routine if needed
+;
+ mov ax,[int8hook]
+ or ax,ax
+ jz @@userdone
+ push ax
+ push bx
+ push cx
+ push dx
+ push si
+ push di
+ push bp
+ push es
+ push ds
+ pushf
+
+ mov [oldss],ss ;because we might not be in our stack!
+ mov [oldsp],sp
+ mov bx,ds
+ mov ss,bx ;make SURE the stack is = ds
+ mov sp,OFFSET fakestack+60
+ call ax ;user routine that gets called every tic
+ mov ss,[oldss]
+ mov sp,[oldsp]
+
+ popf
+ pop ds
+ pop es
+ pop bp
+ pop di
+ pop si
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+
+@@userdone:
+ mov es,[soundseg] ;es to sound file
+;
+; play the speaker
+;
+ mov si,[SndPtr]
+ cmp si,0
+ je @@nosound ;nothing playing
+
+ mov bx,[es:si]
+ inc [SndPtr]
+ inc [SndPtr]
+
+ cmp bx,0
+ je @@nosound ;a zero frequency is no sound, but don't stop
+
+ cmp bx,-1 ;a -1 frequency is end of sound
+ jne @@playfreq
+
+ call StopSound
+ jmp @@doneplay
+
+@@nosound:
+ in al,61h ;get peripheral (speaker) port value
+ and al,11111100b ;turn speaker off
+ out 61h,al
+ jmp @@doneplay
+
+@@playfreq:
+ test [soundmode],0FFh ;if soundon=0, don't play anything
+ je @@nosound
+
+ mov al,10110110b ;write to channel 2 (speaker) timer
+ out 43h,al
+ mov al,bl
+ out 42h,al ;low byte
+ mov al,bh
+ out 42h,al ;high byte
+
+ in al,61h ;get peripheral (speaker) port value
+ or al,00000011b ;turn speaker on to timer
+ out 61h,al
+
+@@doneplay:
+
+ pop es
+ pop ds
+ pop si
+ pop cx
+ pop bx
+ pop ax
+
+ iret
+
+
+ENDP
+
+
+;============================================================================
+;
+; RANDOM ROUTINES
+;
+;============================================================================
+
+ DATASEG
+
+rndindex dw ?
+
+rndtable db 0, 8, 109, 220, 222, 241, 149, 107, 75, 248, 254, 140, 16, 66
+ db 74, 21, 211, 47, 80, 242, 154, 27, 205, 128, 161, 89, 77, 36
+ db 95, 110, 85, 48, 212, 140, 211, 249, 22, 79, 200, 50, 28, 188
+ db 52, 140, 202, 120, 68, 145, 62, 70, 184, 190, 91, 197, 152, 224
+ db 149, 104, 25, 178, 252, 182, 202, 182, 141, 197, 4, 81, 181, 242
+ db 145, 42, 39, 227, 156, 198, 225, 193, 219, 93, 122, 175, 249, 0
+ db 175, 143, 70, 239, 46, 246, 163, 53, 163, 109, 168, 135, 2, 235
+ db 25, 92, 20, 145, 138, 77, 69, 166, 78, 176, 173, 212, 166, 113
+ db 94, 161, 41, 50, 239, 49, 111, 164, 70, 60, 2, 37, 171, 75
+ db 136, 156, 11, 56, 42, 146, 138, 229, 73, 146, 77, 61, 98, 196
+ db 135, 106, 63, 197, 195, 86, 96, 203, 113, 101, 170, 247, 181, 113
+ db 80, 250, 108, 7, 255, 237, 129, 226, 79, 107, 112, 166, 103, 241
+ db 24, 223, 239, 120, 198, 58, 60, 82, 128, 3, 184, 66, 143, 224
+ db 145, 224, 81, 206, 163, 45, 63, 90, 168, 114, 59, 33, 159, 95
+ db 28, 139, 123, 98, 125, 196, 15, 70, 194, 253, 54, 14, 109, 226
+ db 71, 17, 161, 93, 186, 87, 244, 138, 20, 52, 123, 251, 26, 36
+ db 17, 46, 52, 231, 232, 76, 31, 221, 84, 37, 216, 165, 212, 106
+ db 197, 242, 98, 43, 39, 175, 254, 145, 190, 84, 118, 222, 187, 136
+ db 120, 163, 236, 249
+
+
+;
+; Random # Generator vars
+;
+indexi dw ? ;Rnd#Generator
+indexj dw ?
+LastRnd dw ?
+RndArray dw 17 dup (?)
+
+baseRndArray dw 1,1,2,3,5,8,13,21,54,75,129,204
+ dw 323,527,850,1377,2227
+
+ CODESEG
+
+;=================================================
+;
+; InitRnd (boolean randomize)
+; if randomize is false, the counter is set to 0
+;
+;=================================================
+
+PROC InitRnd randomize:word
+ USES SI,DI
+ public InitRnd
+
+ mov ax,ds
+ mov es,ax
+ mov di,offset RndArray
+ mov si,offset baseRndArray
+ mov cx,17
+ cld
+ rep movsw ;set up the table (which is constantly changed)
+
+ mov [LastRnd],0
+ mov [indexi],17*2
+ mov [indexj],5*2
+
+ mov ax,[randomize]
+ cmp ax,0
+ je @@setit ;if randomize is true, really random
+
+ mov ah,2ch
+ int 21h ;GetSystemTime
+
+ mov [RndArray+34-2],dx
+ xor dx,cx ;init w/seconds values
+ mov [RndArray+10-2],dx
+
+@@setit:
+ mov ax,0ffffh
+ push ax
+ call Rnd ;warm up generator!
+ pop ax
+
+ ret
+
+ENDP
+
+;=================================================
+;
+; unsigned Random (unsigned maxval)
+; Return a random # between 0-?
+;
+;=================================================
+
+PROC Rnd maxval:WORD
+ USES SI
+ public Rnd
+
+ mov ax,[maxval]
+
+ push ax ;save max value
+;
+; create a mask to cut down on the # of SUBTRACTS!
+;
+ mov dx,0ffffh ;full-mask
+@@0:
+ shl ax,1
+ jc @@0a
+ shr dx,1
+ jmp @@0
+@@0a:
+ mov bx,[indexi] ;this routine was converted from
+ mov si,[indexj] ;the Random macro on Merlin GS
+ mov ax,[RndArray-2+bx]
+ adc ax,[RndArray-2+si]
+ mov [RndArray-2+bx],ax
+ add ax,[LastRnd]
+ mov [LastRnd],ax
+ dec bx
+ dec bx
+ jne @@1
+ mov bx,17*2
+@@1:
+ dec si
+ dec si
+ jne @@2
+ mov si,17*2
+@@2:
+ mov [indexi],bx
+ mov [indexj],si
+ pop cx ;loop -- returns value in range
+ and ax,dx ;AND our mask!
+@@3:
+ cmp ax,cx ;SUBTRACT to be within range
+ jbe @@4
+ shr ax,1
+@@4:
+ ret
+
+ENDP
+
+
+
+;=================================================
+;
+; InitRndT (boolean randomize)
+; Init table based RND generator
+; if randomize is false, the counter is set to 0
+;
+;=================================================
+
+PROC InitRndT randomize:word
+ uses si,di
+ public initrndt
+
+ mov ax,[randomize]
+ or ax,ax
+ jne @@timeit ;if randomize is true, really random
+
+ mov dx,0 ;set to a definate value
+ jmp @@setit
+
+@@timeit:
+ mov ah,2ch
+ int 21h ;GetSystemTime
+ and dx,0ffh
+
+@@setit:
+ mov [rndindex],dx
+
+ ret
+
+ENDP
+
+;=================================================
+;
+; int RandomT (void)
+; Return a random # between 0-255
+; Exit : AX = value
+;
+;=================================================
+PROC RndT
+ public RndT
+
+ mov bx,[rndindex]
+ inc bx
+ and bx,0ffh
+ mov [rndindex],bx
+ mov al,[rndtable+BX]
+ xor ah,ah
+
+ ret
+
+ENDP
+
+;============================================================================
+;
+; MISC VIDEO ROUTINES
+;
+;============================================================================
+
+;========
+;
+; WaitVBL (int number)
+;
+;========
+STATUS_REGISTER_1 = 03dah
+
+PROC WaitVBL number:WORD
+ PUBLIC WaitVBL
+
+ mov dx,STATUS_REGISTER_1
+
+ mov cx,[number]
+
+waitvbl1:
+ in al,dx
+ test al,00001000b ;look for vbl
+ jnz waitvbl1
+
+waitvbl2:
+ in al,dx
+ test al,00001000b ;look for vbl
+ jz waitvbl2
+
+ loop waitvbl1
+
+ ret
+
+ENDP
+
+
+;===========================================================================
+
+
+ MASM
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+;
+; Name: VideoID
+;
+; Function: Detects the presence of various video subsystems
+;
+; int VideoID;
+;
+; Subsystem ID values:
+; 0 = (none)
+; 1 = MDA
+; 2 = CGA
+; 3 = EGA
+; 4 = MCGA
+; 5 = VGA
+; 80h = HGC
+; 81h = HGC+
+; 82h = Hercules InColor
+;
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+;
+; Equates
+;
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+VIDstruct STRUC ; corresponds to C data structure
+
+Video0Type DB ? ; first subsystem type
+Display0Type DB ? ; display attached to first subsystem
+
+Video1Type DB ? ; second subsystem type
+Display1Type DB ? ; display attached to second subsystem
+
+VIDstruct ENDS
+
+
+Device0 EQU word ptr Video0Type[di]
+Device1 EQU word ptr Video1Type[di]
+
+
+MDA EQU 1 ; subsystem types
+CGA EQU 2
+EGA EQU 3
+MCGA EQU 4
+VGA EQU 5
+HGC EQU 80h
+HGCPlus EQU 81h
+InColor EQU 82h
+
+MDADisplay EQU 1 ; display types
+CGADisplay EQU 2
+EGAColorDisplay EQU 3
+PS2MonoDisplay EQU 4
+PS2ColorDisplay EQU 5
+
+TRUE EQU 1
+FALSE EQU 0
+
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+;
+; Program
+;
+;様様様様様様様様様様様様様様様様様様様様様様様様様様様様
+
+Results VIDstruct <> ;results go here!
+
+EGADisplays DB CGADisplay ; 0000b, 0001b (EGA switch values)
+ DB EGAColorDisplay ; 0010b, 0011b
+ DB MDADisplay ; 0100b, 0101b
+ DB CGADisplay ; 0110b, 0111b
+ DB EGAColorDisplay ; 1000b, 1001b
+ DB MDADisplay ; 1010b, 1011b
+
+DCCtable DB 0,0 ; translate table for INT 10h func 1Ah
+ DB MDA,MDADisplay
+ DB CGA,CGADisplay
+ DB 0,0
+ DB EGA,EGAColorDisplay
+ DB EGA,MDADisplay
+ DB 0,0
+ DB VGA,PS2MonoDisplay
+ DB VGA,PS2ColorDisplay
+ DB 0,0
+ DB MCGA,EGAColorDisplay
+ DB MCGA,PS2MonoDisplay
+ DB MCGA,PS2ColorDisplay
+
+TestSequence DB TRUE ; this list of flags and addresses
+ DW FindPS2 ; determines the order in which this
+ ; program looks for the various
+EGAflag DB ? ; subsystems
+ DW FindEGA
+
+CGAflag DB ?
+ DW FindCGA
+
+Monoflag DB ?
+ DW FindMono
+
+NumberOfTests EQU ($-TestSequence)/3
+
+
+ PUBLIC VideoID
+VideoID PROC near
+
+ push bp ; preserve caller registers
+ mov bp,sp
+ push ds
+ push si
+ push di
+
+ push cs
+ pop ds
+ ASSUME DS:@Code
+
+; initialize the data structure that will contain the results
+
+ lea di,Results ; DS:DI -> start of data structure
+
+ mov Device0,0 ; zero these variables
+ mov Device1,0
+
+; look for the various subsystems using the subroutines whose addresses are
+; tabulated in TestSequence; each subroutine sets flags in TestSequence
+; to indicate whether subsequent subroutines need to be called
+
+ mov byte ptr CGAflag,TRUE
+ mov byte ptr EGAflag,TRUE
+ mov byte ptr Monoflag,TRUE
+
+ mov cx,NumberOfTests
+ mov si,offset TestSequence
+
+@@L01: lodsb ; AL := flag
+ test al,al
+ lodsw ; AX := subroutine address
+ jz @@L02 ; skip subroutine if flag is false
+
+ push si
+ push cx
+ call ax ; call subroutine to detect subsystem
+ pop cx
+ pop si
+
+@@L02: loop @@L01
+
+; determine which subsystem is active
+
+ call FindActive
+
+ mov al,Results.Video0Type
+ mov ah,0 ; was: Results.Display0Type
+
+ pop di ; restore caller registers and return
+ pop si
+ pop ds
+ mov sp,bp
+ pop bp
+ ret
+
+VideoID ENDP
+
+
+;
+; FindPS2
+;
+; This subroutine uses INT 10H function 1Ah to determine the video BIOS
+; Display Combination Code (DCC) for each video subsystem present.
+;
+
+FindPS2 PROC near
+
+ mov ax,1A00h
+ int 10h ; call video BIOS for info
+
+ cmp al,1Ah
+ jne @@L13 ; exit if function not supported (i.e.,
+ ; no MCGA or VGA in system)
+
+; convert BIOS DCCs into specific subsystems & displays
+
+ mov cx,bx
+ xor bh,bh ; BX := DCC for active subsystem
+
+ or ch,ch
+ jz @@L11 ; jump if only one subsystem present
+
+ mov bl,ch ; BX := inactive DCC
+ add bx,bx
+ mov ax,[bx+offset DCCtable]
+
+ mov Device1,ax
+
+ mov bl,cl
+ xor bh,bh ; BX := active DCC
+
+@@L11: add bx,bx
+ mov ax,[bx+offset DCCtable]
+
+ mov Device0,ax
+
+; reset flags for subsystems that have been ruled out
+
+ mov byte ptr CGAflag,FALSE
+ mov byte ptr EGAflag,FALSE
+ mov byte ptr Monoflag,FALSE
+
+ lea bx,Video0Type[di] ; if the BIOS reported an MDA ...
+ cmp byte ptr [bx],MDA
+ je @@L12
+
+ lea bx,Video1Type[di]
+ cmp byte ptr [bx],MDA
+ jne @@L13
+
+@@L12: mov word ptr [bx],0 ; ... Hercules can't be ruled out
+ mov byte ptr Monoflag,TRUE
+
+@@L13: ret
+
+FindPS2 ENDP
+
+
+;
+; FindEGA
+;
+; Look for an EGA. This is done by making a call to an EGA BIOS function
+; which doesn't exist in the default (MDA, CGA) BIOS.
+
+FindEGA PROC near ; Caller: AH = flags
+ ; Returns: AH = flags
+ ; Video0Type and
+ ; Display0Type updated
+
+ mov bl,10h ; BL := 10h (return EGA info)
+ mov ah,12h ; AH := INT 10H function number
+ int 10h ; call EGA BIOS for info
+ ; if EGA BIOS is present,
+ ; BL <> 10H
+ ; CL = switch setting
+ cmp bl,10h
+ je @@L22 ; jump if EGA BIOS not present
+
+ mov al,cl
+ shr al,1 ; AL := switches/2
+ mov bx,offset EGADisplays
+ xlat ; determine display type from switches
+ mov ah,al ; AH := display type
+ mov al,EGA ; AL := subystem type
+ call FoundDevice
+
+ cmp ah,MDADisplay
+ je @@L21 ; jump if EGA has a monochrome display
+
+ mov CGAflag,FALSE ; no CGA if EGA has color display
+ jmp short @@L22
+
+@@L21: mov Monoflag,FALSE ; EGA has a mono display, so MDA and
+ ; Hercules are ruled out
+@@L22: ret
+
+FindEGA ENDP
+
+;
+; FindCGA
+;
+; This is done by looking for the CGA's 6845 CRTC at I/O port 3D4H.
+;
+FindCGA PROC near ; Returns: VIDstruct updated
+
+ mov dx,3D4h ; DX := CRTC address port
+ call Find6845
+ jc @@L31 ; jump if not present
+
+ mov al,CGA
+ mov ah,CGADisplay
+ call FoundDevice
+
+@@L31: ret
+
+FindCGA ENDP
+
+;
+; FindMono
+;
+; This is done by looking for the MDA's 6845 CRTC at I/O port 3B4H. If
+; a 6845 is found, the subroutine distinguishes between an MDA
+; and a Hercules adapter by monitoring bit 7 of the CRT Status byte.
+; This bit changes on Hercules adapters but does not change on an MDA.
+;
+; The various Hercules adapters are identified by bits 4 through 6 of
+; the CRT Status value:
+;
+; 000b = HGC
+; 001b = HGC+
+; 101b = InColor card
+;
+
+FindMono PROC near ; Returns: VIDstruct updated
+
+ mov dx,3B4h ; DX := CRTC address port
+ call Find6845
+ jc @@L44 ; jump if not present
+
+ mov dl,0BAh ; DX := 3BAh (status port)
+ in al,dx
+ and al,80h
+ mov ah,al ; AH := bit 7 (vertical sync on HGC)
+
+ mov cx,8000h ; do this 32768 times
+@@L41: in al,dx
+ and al,80h ; isolate bit 7
+ cmp ah,al
+ loope @@L41 ; wait for bit 7 to change
+ jne @@L42 ; if bit 7 changed, it's a Hercules
+
+ mov al,MDA ; if bit 7 didn't change, it's an MDA
+ mov ah,MDADisplay
+ call FoundDevice
+ jmp short @@L44
+
+@@L42: in al,dx
+ mov dl,al ; DL := value from status port
+ and dl,01110000b ; mask bits 4 thru 6
+
+ mov ah,MDADisplay ; assume it's a monochrome display
+
+ mov al,HGCPlus ; look for an HGC+
+ cmp dl,00010000b
+ je @@L43 ; jump if it's an HGC+
+
+ mov al,HGC ; look for an InColor card or HGC
+ cmp dl,01010000b
+ jne @@L43 ; jump if it's not an InColor card
+
+ mov al,InColor ; it's an InColor card
+ mov ah,EGAColorDisplay
+
+@@L43: call FoundDevice
+
+@@L44: ret
+
+FindMono ENDP
+
+;
+; Find6845
+;
+; This routine detects the presence of the CRTC on a MDA, CGA or HGC.
+; The technique is to write and read register 0Fh of the chip (cursor
+; low). If the same value is read as written, assume the chip is
+; present at the specified port addr.
+;
+
+Find6845 PROC near ; Caller: DX = port addr
+ ; Returns: cf set if not present
+ mov al,0Fh
+ out dx,al ; select 6845 reg 0Fh (Cursor Low)
+ inc dx
+ in al,dx ; AL := current Cursor Low value
+ mov ah,al ; preserve in AH
+ mov al,66h ; AL := arbitrary value
+ out dx,al ; try to write to 6845
+
+ mov cx,100h
+@@L51: loop @@L51 ; wait for 6845 to respond
+
+ in al,dx
+ xchg ah,al ; AH := returned value
+ ; AL := original value
+ out dx,al ; restore original value
+
+ cmp ah,66h ; test whether 6845 responded
+ je @@L52 ; jump if it did (cf is reset)
+
+ stc ; set carry flag if no 6845 present
+
+@@L52: ret
+
+Find6845 ENDP
+
+
+;
+; FindActive
+;
+; This subroutine stores the currently active device as Device0. The
+; current video mode determines which subsystem is active.
+;
+
+FindActive PROC near
+
+ cmp word ptr Device1,0
+ je @@L63 ; exit if only one subsystem
+
+ cmp Video0Type[di],4 ; exit if MCGA or VGA present
+ jge @@L63 ; (INT 10H function 1AH
+ cmp Video1Type[di],4 ; already did the work)
+ jge @@L63
+
+ mov ah,0Fh
+ int 10h ; AL := current BIOS video mode
+
+ and al,7
+ cmp al,7 ; jump if monochrome
+ je @@L61 ; (mode 7 or 0Fh)
+
+ cmp Display0Type[di],MDADisplay
+ jne @@L63 ; exit if Display0 is color
+ jmp short @@L62
+
+@@L61: cmp Display0Type[di],MDADisplay
+ je @@L63 ; exit if Display0 is monochrome
+
+@@L62: mov ax,Device0 ; make Device0 currently active
+ xchg ax,Device1
+ mov Device0,ax
+
+@@L63: ret
+
+FindActive ENDP
+
+
+;
+; FoundDevice
+;
+; This routine updates the list of subsystems.
+;
+
+FoundDevice PROC near ; Caller: AH = display #
+ ; AL = subsystem #
+ ; Destroys: BX
+ lea bx,Video0Type[di]
+ cmp byte ptr [bx],0
+ je @@L71 ; jump if 1st subsystem
+
+ lea bx,Video1Type[di] ; must be 2nd subsystem
+
+@@L71: mov [bx],ax ; update list entry
+ ret
+
+FoundDevice ENDP
+
+
+END
diff --git a/IDASME.ASM b/IDASME.ASM
new file mode 100644
index 0000000..587148b
--- /dev/null
+++ b/IDASME.ASM
@@ -0,0 +1,1653 @@
+; 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.
+
+IDEAL
+MODEL SMALL,C
+
+include "GRAPHHOV.EQU"
+
+;============================================================================
+;
+; EGA Graphic routines
+;
+;============================================================================
+
+SC_INDEX = 03C4h
+SC_RESET = 0
+SC_CLOCK = 1
+SC_MAPMASK = 2
+SC_CHARMAP = 3
+SC_MEMMODE = 4
+
+CRTC_INDEX = 03D4h
+CRTC_H_TOTAL = 0
+CRTC_H_DISPEND = 1
+CRTC_H_BLANK = 2
+CRTC_H_ENDBLANK = 3
+CRTC_H_RETRACE = 4
+CRTC_H_ENDRETRACE = 5
+CRTC_V_TOTAL = 6
+CRTC_OVERFLOW = 7
+CRTC_ROWSCAN = 8
+CRTC_MAXSCANLINE = 9
+CRTC_CURSORSTART = 10
+CRTC_CURSOREND = 11
+CRTC_STARTHIGH = 12
+CRTC_STARTLOW = 13
+CRTC_CURSORHIGH = 14
+CRTC_CURSORLOW = 15
+CRTC_V_RETRACE = 16
+CRTC_V_ENDRETRACE = 17
+CRTC_V_DISPEND = 18
+CRTC_OFFSET = 19
+CRTC_UNDERLINE = 20
+CRTC_V_BLANK = 21
+CRTC_V_ENDBLANK = 22
+CRTC_MODE = 23
+CRTC_LINECOMPARE = 24
+
+
+GC_INDEX = 03CEh
+GC_SETRESET = 0
+GC_ENABLESETRESET = 1
+GC_COLORCOMPARE = 2
+GC_DATAROTATE = 3
+GC_READMAP = 4
+GC_MODE = 5
+GC_MISCELLANEOUS = 6
+GC_COLORDONTCARE = 7
+GC_BITMASK = 8
+
+ATR_INDEX = 03c0h
+ATR_MODE = 16
+ATR_OVERSCAN = 17
+ATR_COLORPLANEENABLE = 18
+ATR_PELPAN = 19
+ATR_COLORSELECT = 20
+
+
+SCREENWIDTH equ 40
+
+;
+; offsets into sprite/pictable
+;
+PICWIDTHOFS equ 0
+PICHEIGHTOFS equ 2
+
+
+DATASEG
+
+screenseg dw 0a000h
+otherseg dw 0
+screenofs dw 0
+screenorigin dw 0
+planemask dw 0
+planecount dw 0
+linewidth dw 0
+
+PUBLIC screenseg,screenofs,screenorigin,otherseg,linewidth
+
+EXTRN pictable:WORD
+EXTRN spritetable:WORD
+EXTRN grsegs:WORD ; master location table for all graphics
+
+ylookup dw 256 dup (?)
+PUBLIC ylookup
+
+;============================================================================
+CODESEG
+;============================================================================
+
+MACRO WORDOUT
+ out dx,al
+ inc dx
+ xchg al,ah
+ out dx,al
+ dec dx
+ xchg al,ah
+ENDM
+
+
+;====================
+;
+; EGAplane
+; Sets read/write mode 0 and selects the given plane (0-3)
+; for reading and writing
+;
+;====================
+
+PROC EGAplane plane:WORD
+ PUBLIC EGAplane
+
+ cli
+
+ mov dx,GC_INDEX
+ mov ax,GC_MODE
+ WORDOUT ;set read / write mode 0
+
+ mov dx,GC_INDEX
+ mov al,4 ;read map select
+ mov ah,[BYTE plane] ;read from this plane number
+ out dx,ax
+ mov dx,SC_INDEX
+ mov al,SC_MAPMASK
+ mov ah,1
+ mov cl,[BYTE plane] ;write to this plane only
+ shl ah,cl
+ WORDOUT
+
+ sti
+ ret
+
+ENDP
+
+
+;==============
+;
+; SetScreen
+;
+;==============
+
+;
+; EGA registers
+;
+HPELPAN equ 20h or 13h
+
+PROC SetScreen crtc:WORD, pel:WORD
+PUBLIC SetScreen
+
+;
+; set the CRTC start registers for the screen just drawn
+;
+
+; wait for no display enable and no vertical sync, so the raster is in a
+; horizontal sync, not on the last line!
+
+ cli
+
+ mov dx,CRTC_INDEX+6
+@@waitnovbl:
+ in al,dx
+ test al,00001000b
+ jnz @@waitnovbl ;vertical syncing now
+ or al,1
+ jz @@waitnovbl ;in the middle of a scan line
+
+
+ mov cx,[crtc]
+ mov dx,3d4h ;CRTC address register
+ mov al,0ch ;start address high register
+ out dx,al
+ inc dx
+ mov al,ch
+ out dx,al ;set the high byte
+ dec dx
+ mov al,0dh ;start address low register
+ out dx,al
+ inc dx
+ mov al,cl
+ out dx,al ;set the low byte
+
+ sti
+
+ mov dx,CRTC_INDEX+6
+@@waitvbl:
+ in al,dx
+ test al,00001000b ;look for vertical retrace
+ jz @@waitvbl
+
+;
+; set horizontal panning
+;
+ cli
+
+ mov bx,[pel]
+ mov dx,CRTC_INDEX+6
+ in al,dx
+ mov dx,ATR_INDEX
+ mov al,HPELPAN
+ out dx,al
+ mov ax,bx ;pel pan value
+ out dx,al
+
+ sti
+
+ ret
+
+ENDP
+
+
+
+;=============
+;
+; XorBar
+;
+; xcoord in bytes, ycoord in pixels
+;
+;=============
+
+PROC XorBar xl:WORD, yl:WORD, wide:WORD, height:WORD
+USES SI,DI
+PUBLIC XorBar
+
+; set write mode 0
+ mov dx,GC_INDEX
+ mov ax,GC_MODE
+ WORDOUT
+
+; set xor mode
+ mov ax,GC_DATAROTATE + 11000b * 256
+ WORDOUT
+
+ mov dx,[wide] ;bytes / line
+ mov ch,[BYTE height] ;lines
+
+ mov bx,[yl]
+ shl bx,1
+ mov di,[ylookup+bx]
+ add di,[screenofs]
+ add di,[xl]
+
+ mov es,[screenseg]
+
+ mov ah,0ffh
+
+; ch = vertical loops
+; cl = horizontal loops
+
+@@vertloop:
+ mov cl,dl
+ xor bx,bx
+@@horizloop:
+ mov al,[es:di+bx] ;load latches
+ mov [es:di+bx],ah ;xor in $ff
+ inc bx
+
+ dec cl
+ jnz @@horizloop
+ add di,SCREENWIDTH
+ dec ch
+ jnz @@vertloop
+
+; set copy mode
+ mov dx,GC_INDEX
+ mov ax,GC_DATAROTATE
+ WORDOUT
+
+; set mapmask to all
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK + 15*256
+ WORDOUT
+
+ ret
+ENDP
+
+
+;=============
+;
+; XPlot
+;
+; Xdraws one point
+;
+;=============
+
+PROC XPlot x:WORD, y:WORD, color:WORD
+USES SI,DI
+PUBLIC XPlot
+
+; set write mode 0
+ mov dx,GC_INDEX
+ mov ax,GC_MODE
+ WORDOUT
+
+; set xor mode
+ mov ax,GC_DATAROTATE + 11000b * 256
+ WORDOUT
+
+; set mapmask to color
+ mov dx,SC_INDEX
+ mov al,SC_MAPMASK
+ mov ah,[BYTE color]
+ WORDOUT
+
+; calculate screen location
+ mov bx,[y]
+ shl bx,1
+ mov di,[ylookup+bx]
+ add di,[screenofs]
+ mov ax,[x]
+ mov bx,ax
+ shr bx,1
+ shr bx,1
+ shr bx,1
+ add di,bx ; byte value of x
+ and ax,7
+ mov cx,7
+ sub cx,ax ; bit position
+ mov ax,100h
+ shl ax,cl ; high byte holds mask
+
+; set bitmask to pixel
+ mov dx,GC_INDEX
+ mov al,GC_BITMASK
+ WORDOUT
+
+ mov es,[screenseg]
+ mov al,[es:di] ; load latches
+ mov [BYTE es:di],0ffh ; xor out 1s to active planes/bits
+
+; set copy mode
+ mov dx,GC_INDEX
+ mov ax,GC_DATAROTATE
+ WORDOUT
+
+; set mapmask to all
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK + 15*256
+ WORDOUT
+
+; set bitmask to pixel
+ mov dx,GC_INDEX
+ mov ax,GC_BITMASK + 255*256
+ WORDOUT
+ ret
+ENDP
+
+
+;=============
+;
+; DrawChar (int xcoord, int ycoord, int charnum)
+;
+; xcoord in bytes, ycoord in pixels
+;
+; Source is grsegs[STARTTILE8+charnum]
+;
+;=============
+
+PROC DrawChar xcoord:WORD, ycoord:WORD, charnum:WORD
+USES SI,DI
+PUBLIC DrawChar
+
+ mov es,[screenseg]
+
+ mov di,[screenofs]
+ add di,[xcoord]
+ mov bx,[ycoord]
+ shl bx,1
+ add di,[ylookup+bx] ;screen destination
+
+ cld
+
+ mov bx,[linewidth]
+ dec bx
+
+ mov si,[charnum]
+ shl si,1
+ shl si,1
+ shl si,1
+ shl si,1
+ shl si,1
+
+ mov ds,[grsegs+STARTTILE8*2] ; segment for all tile8s
+
+
+;
+; start drawing
+;
+
+ cli
+ mov dx,GC_INDEX ;set write mode 0
+ mov ax,GC_MODE
+ WORDOUT
+ sti
+
+ mov cx,4 ;planes to draw
+ mov [ss:planemask],0001b ;map mask
+
+ mov bx,6
+
+@@planeloop:
+ cli
+ mov dx,SC_INDEX
+ mov al,SC_MAPMASK
+ mov ah,[BYTE ss:planemask]
+ shl [ss:planemask],1
+ WORDOUT
+ sti
+ mov dx,[ss:linewidth]
+ dec dx
+ dec bx
+ dec bx
+
+
+ push di
+
+REPT 7
+ movsb
+ add di,dx
+ENDM
+ movsb
+
+ pop di
+
+ loop @@planeloop
+
+ cli
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK+15*256 ;write to all planes
+ WORDOUT
+ sti
+
+ mov ax,ss
+ mov ds,ax ;restore turbo's data segment
+
+ ret
+
+ENDP
+
+;=======================================================================
+
+;============
+;
+; DrawPic (int xcoord, int ycoord, int picnum)
+;
+; xcoord in bytes, ycoord in pixels
+;
+;============
+
+DATASEG
+
+picwidth dw ?
+picxcoord dw ?
+picheight dw ?
+
+picoffset dw ? ;offset into data planes
+
+PUBLIC picoffset
+
+CODESEG
+
+PROC DrawPic xcoord:WORD, ycoord:WORD, picnum:WORD
+USES SI,DI
+PUBLIC DrawPic
+
+
+ mov si,[picnum]
+ shl si,1
+ shl si,1
+
+ mov ax,[pictable+si+PICWIDTHOFS]
+ mov [picwidth],ax
+ mov ax,[pictable+si+PICHEIGHTOFS]
+ mov [picheight],ax
+
+ mov es,[screenseg]
+
+ mov di,[screenofs]
+ add di,[xcoord]
+ mov bx,[ycoord]
+ shl bx,1
+ add di,[ylookup+bx] ;screen destination
+
+ cld
+
+;
+; start drawing
+;
+
+ cli
+ mov dx,GC_INDEX ;set write mode 0
+ mov ax,GC_MODE
+ WORDOUT
+ sti
+
+ mov [planecount],3
+ mov [planemask],0001b ;map mask
+
+ mov si,[picnum]
+ shl si,1
+ mov ds,[grsegs+STARTPICS*2+si] ; segment of pictures (PARA'd)
+ xor si,si ; segment aligned
+
+ mov bx,6
+
+@@planeloop:
+ cli
+ mov dx,SC_INDEX
+ mov al,SC_MAPMASK
+ mov ah,[BYTE ss:planemask]
+ shl [ss:planemask],1
+ WORDOUT
+ sti
+ mov dx,[ss:linewidth]
+ sub dx,[ss:picwidth]
+ mov bx,[ss:planecount]
+ shl bx,1
+
+ push di
+
+ mov bx,[ss:picheight]
+@@lineloop:
+ mov cx,[ss:picwidth]
+ rep movsb
+ add di,dx
+
+ dec bx
+ jnz @@lineloop
+
+ pop di
+
+ dec [ss:planecount]
+ jns @@planeloop
+
+ cli
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK+15*256 ;write to all planes
+ WORDOUT
+ sti
+
+ mov ax,ss
+ mov ds,ax ;restore turbo's data segment
+
+ ret
+
+
+ ret
+
+ENDP
+
+
+
+;============
+;
+; Bar (int xl,yl,width,height)
+;
+; xcoord in bytes, ycoord in pixels
+;
+;============
+
+PROC Bar xl:WORD, yl:WORD, wide:WORD, height:WORD, fill:WORD
+USES SI,DI
+PUBLIC Bar
+
+ mov di,[screenofs]
+ mov bx,[yl]
+ shl bx,1
+ add di,[ylookup+bx]
+ add di,[xl]
+
+ mov es,[screenseg]
+
+ cld
+ cli ;no interrupts during EGA stuff!
+
+ mov dx,GC_INDEX
+ mov ax,GC_MODE ;write mode 0
+ WORDOUT
+
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK+15*256
+ WORDOUT
+
+ sti
+
+ mov bx,[ss:linewidth]
+ sub bx,[wide]
+ mov al,[BYTE fill]
+@@drawrow:
+ mov cx,[wide]
+ rep stosb
+ add di,bx
+ dec [height]
+ jnz @@drawrow
+
+ mov ax,ss
+ mov ds,ax ;restore turbo's data segment
+
+ ret
+
+ENDP
+
+
+
+;============
+;
+; CopyEGA
+;
+; Must be in latch mode
+;
+;============
+
+PROC CopyEGA wide:WORD, height:WORD, source:word, dest:word
+PUBLIC CopyEGA
+USES SI,DI
+
+ mov ax,0a000h
+ mov ds,ax
+ mov es,ax
+@@zapasprite:
+;
+; erase a sprite by copying a block from the master screen
+;
+ mov ah,[BYTE wide] ;width of block
+ mov bx,[WORD height] ;height of block
+ mov di,[dest] ;destination to erase
+ mov si,[source]
+
+ mov dx,[ss:linewidth]
+ sub dl,ah
+ xor ch,ch
+EVEN
+@@clearloop:
+ mov cl,ah
+ rep movsb
+ add si,dx
+ add di,dx
+ dec bx
+ jnz @@clearloop
+
+ mov ax,ss
+ mov ds,ax ;restore ds
+
+ ret
+ENDP
+
+
+
+if NUMFONT+NUMFONTM
+
+;===========================================================================
+;
+; SHIFT TABLES
+;
+;===========================================================================
+
+DATASEG
+
+
+LABEL shiftdata0 WORD
+ dw 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
+ dw 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27
+ dw 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41
+ dw 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55
+ dw 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69
+ dw 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83
+ dw 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
+ dw 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111
+ dw 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125
+ dw 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139
+ dw 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153
+ dw 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, 167
+ dw 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181
+ dw 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195
+ dw 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209
+ dw 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223
+ dw 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237
+ dw 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251
+ dw 252, 253, 254, 255
+
+LABEL shiftdata1 WORD
+ dw 0,32768, 1,32769, 2,32770, 3,32771, 4,32772, 5,32773, 6,32774
+ dw 7,32775, 8,32776, 9,32777, 10,32778, 11,32779, 12,32780, 13,32781
+ dw 14,32782, 15,32783, 16,32784, 17,32785, 18,32786, 19,32787, 20,32788
+ dw 21,32789, 22,32790, 23,32791, 24,32792, 25,32793, 26,32794, 27,32795
+ dw 28,32796, 29,32797, 30,32798, 31,32799, 32,32800, 33,32801, 34,32802
+ dw 35,32803, 36,32804, 37,32805, 38,32806, 39,32807, 40,32808, 41,32809
+ dw 42,32810, 43,32811, 44,32812, 45,32813, 46,32814, 47,32815, 48,32816
+ dw 49,32817, 50,32818, 51,32819, 52,32820, 53,32821, 54,32822, 55,32823
+ dw 56,32824, 57,32825, 58,32826, 59,32827, 60,32828, 61,32829, 62,32830
+ dw 63,32831, 64,32832, 65,32833, 66,32834, 67,32835, 68,32836, 69,32837
+ dw 70,32838, 71,32839, 72,32840, 73,32841, 74,32842, 75,32843, 76,32844
+ dw 77,32845, 78,32846, 79,32847, 80,32848, 81,32849, 82,32850, 83,32851
+ dw 84,32852, 85,32853, 86,32854, 87,32855, 88,32856, 89,32857, 90,32858
+ dw 91,32859, 92,32860, 93,32861, 94,32862, 95,32863, 96,32864, 97,32865
+ dw 98,32866, 99,32867, 100,32868, 101,32869, 102,32870, 103,32871, 104,32872
+ dw 105,32873, 106,32874, 107,32875, 108,32876, 109,32877, 110,32878, 111,32879
+ dw 112,32880, 113,32881, 114,32882, 115,32883, 116,32884, 117,32885, 118,32886
+ dw 119,32887, 120,32888, 121,32889, 122,32890, 123,32891, 124,32892, 125,32893
+ dw 126,32894, 127,32895
+
+LABEL shiftdata2 WORD
+ dw 0,16384,32768,49152, 1,16385,32769,49153, 2,16386,32770,49154, 3,16387
+ dw 32771,49155, 4,16388,32772,49156, 5,16389,32773,49157, 6,16390,32774,49158
+ dw 7,16391,32775,49159, 8,16392,32776,49160, 9,16393,32777,49161, 10,16394
+ dw 32778,49162, 11,16395,32779,49163, 12,16396,32780,49164, 13,16397,32781,49165
+ dw 14,16398,32782,49166, 15,16399,32783,49167, 16,16400,32784,49168, 17,16401
+ dw 32785,49169, 18,16402,32786,49170, 19,16403,32787,49171, 20,16404,32788,49172
+ dw 21,16405,32789,49173, 22,16406,32790,49174, 23,16407,32791,49175, 24,16408
+ dw 32792,49176, 25,16409,32793,49177, 26,16410,32794,49178, 27,16411,32795,49179
+ dw 28,16412,32796,49180, 29,16413,32797,49181, 30,16414,32798,49182, 31,16415
+ dw 32799,49183, 32,16416,32800,49184, 33,16417,32801,49185, 34,16418,32802,49186
+ dw 35,16419,32803,49187, 36,16420,32804,49188, 37,16421,32805,49189, 38,16422
+ dw 32806,49190, 39,16423,32807,49191, 40,16424,32808,49192, 41,16425,32809,49193
+ dw 42,16426,32810,49194, 43,16427,32811,49195, 44,16428,32812,49196, 45,16429
+ dw 32813,49197, 46,16430,32814,49198, 47,16431,32815,49199, 48,16432,32816,49200
+ dw 49,16433,32817,49201, 50,16434,32818,49202, 51,16435,32819,49203, 52,16436
+ dw 32820,49204, 53,16437,32821,49205, 54,16438,32822,49206, 55,16439,32823,49207
+ dw 56,16440,32824,49208, 57,16441,32825,49209, 58,16442,32826,49210, 59,16443
+ dw 32827,49211, 60,16444,32828,49212, 61,16445,32829,49213, 62,16446,32830,49214
+ dw 63,16447,32831,49215
+
+LABEL shiftdata3 WORD
+ dw 0, 8192,16384,24576,32768,40960,49152,57344, 1, 8193,16385,24577,32769,40961
+ dw 49153,57345, 2, 8194,16386,24578,32770,40962,49154,57346, 3, 8195,16387,24579
+ dw 32771,40963,49155,57347, 4, 8196,16388,24580,32772,40964,49156,57348, 5, 8197
+ dw 16389,24581,32773,40965,49157,57349, 6, 8198,16390,24582,32774,40966,49158,57350
+ dw 7, 8199,16391,24583,32775,40967,49159,57351, 8, 8200,16392,24584,32776,40968
+ dw 49160,57352, 9, 8201,16393,24585,32777,40969,49161,57353, 10, 8202,16394,24586
+ dw 32778,40970,49162,57354, 11, 8203,16395,24587,32779,40971,49163,57355, 12, 8204
+ dw 16396,24588,32780,40972,49164,57356, 13, 8205,16397,24589,32781,40973,49165,57357
+ dw 14, 8206,16398,24590,32782,40974,49166,57358, 15, 8207,16399,24591,32783,40975
+ dw 49167,57359, 16, 8208,16400,24592,32784,40976,49168,57360, 17, 8209,16401,24593
+ dw 32785,40977,49169,57361, 18, 8210,16402,24594,32786,40978,49170,57362, 19, 8211
+ dw 16403,24595,32787,40979,49171,57363, 20, 8212,16404,24596,32788,40980,49172,57364
+ dw 21, 8213,16405,24597,32789,40981,49173,57365, 22, 8214,16406,24598,32790,40982
+ dw 49174,57366, 23, 8215,16407,24599,32791,40983,49175,57367, 24, 8216,16408,24600
+ dw 32792,40984,49176,57368, 25, 8217,16409,24601,32793,40985,49177,57369, 26, 8218
+ dw 16410,24602,32794,40986,49178,57370, 27, 8219,16411,24603,32795,40987,49179,57371
+ dw 28, 8220,16412,24604,32796,40988,49180,57372, 29, 8221,16413,24605,32797,40989
+ dw 49181,57373, 30, 8222,16414,24606,32798,40990,49182,57374, 31, 8223,16415,24607
+ dw 32799,40991,49183,57375
+
+LABEL shiftdata4 WORD
+ dw 0, 4096, 8192,12288,16384,20480,24576,28672,32768,36864,40960,45056,49152,53248
+ dw 57344,61440, 1, 4097, 8193,12289,16385,20481,24577,28673,32769,36865,40961,45057
+ dw 49153,53249,57345,61441, 2, 4098, 8194,12290,16386,20482,24578,28674,32770,36866
+ dw 40962,45058,49154,53250,57346,61442, 3, 4099, 8195,12291,16387,20483,24579,28675
+ dw 32771,36867,40963,45059,49155,53251,57347,61443, 4, 4100, 8196,12292,16388,20484
+ dw 24580,28676,32772,36868,40964,45060,49156,53252,57348,61444, 5, 4101, 8197,12293
+ dw 16389,20485,24581,28677,32773,36869,40965,45061,49157,53253,57349,61445, 6, 4102
+ dw 8198,12294,16390,20486,24582,28678,32774,36870,40966,45062,49158,53254,57350,61446
+ dw 7, 4103, 8199,12295,16391,20487,24583,28679,32775,36871,40967,45063,49159,53255
+ dw 57351,61447, 8, 4104, 8200,12296,16392,20488,24584,28680,32776,36872,40968,45064
+ dw 49160,53256,57352,61448, 9, 4105, 8201,12297,16393,20489,24585,28681,32777,36873
+ dw 40969,45065,49161,53257,57353,61449, 10, 4106, 8202,12298,16394,20490,24586,28682
+ dw 32778,36874,40970,45066,49162,53258,57354,61450, 11, 4107, 8203,12299,16395,20491
+ dw 24587,28683,32779,36875,40971,45067,49163,53259,57355,61451, 12, 4108, 8204,12300
+ dw 16396,20492,24588,28684,32780,36876,40972,45068,49164,53260,57356,61452, 13, 4109
+ dw 8205,12301,16397,20493,24589,28685,32781,36877,40973,45069,49165,53261,57357,61453
+ dw 14, 4110, 8206,12302,16398,20494,24590,28686,32782,36878,40974,45070,49166,53262
+ dw 57358,61454, 15, 4111, 8207,12303,16399,20495,24591,28687,32783,36879,40975,45071
+ dw 49167,53263,57359,61455
+
+LABEL shiftdata5 WORD
+ dw 0, 2048, 4096, 6144, 8192,10240,12288,14336,16384,18432,20480,22528,24576,26624
+ dw 28672,30720,32768,34816,36864,38912,40960,43008,45056,47104,49152,51200,53248,55296
+ dw 57344,59392,61440,63488, 1, 2049, 4097, 6145, 8193,10241,12289,14337,16385,18433
+ dw 20481,22529,24577,26625,28673,30721,32769,34817,36865,38913,40961,43009,45057,47105
+ dw 49153,51201,53249,55297,57345,59393,61441,63489, 2, 2050, 4098, 6146, 8194,10242
+ dw 12290,14338,16386,18434,20482,22530,24578,26626,28674,30722,32770,34818,36866,38914
+ dw 40962,43010,45058,47106,49154,51202,53250,55298,57346,59394,61442,63490, 3, 2051
+ dw 4099, 6147, 8195,10243,12291,14339,16387,18435,20483,22531,24579,26627,28675,30723
+ dw 32771,34819,36867,38915,40963,43011,45059,47107,49155,51203,53251,55299,57347,59395
+ dw 61443,63491, 4, 2052, 4100, 6148, 8196,10244,12292,14340,16388,18436,20484,22532
+ dw 24580,26628,28676,30724,32772,34820,36868,38916,40964,43012,45060,47108,49156,51204
+ dw 53252,55300,57348,59396,61444,63492, 5, 2053, 4101, 6149, 8197,10245,12293,14341
+ dw 16389,18437,20485,22533,24581,26629,28677,30725,32773,34821,36869,38917,40965,43013
+ dw 45061,47109,49157,51205,53253,55301,57349,59397,61445,63493, 6, 2054, 4102, 6150
+ dw 8198,10246,12294,14342,16390,18438,20486,22534,24582,26630,28678,30726,32774,34822
+ dw 36870,38918,40966,43014,45062,47110,49158,51206,53254,55302,57350,59398,61446,63494
+ dw 7, 2055, 4103, 6151, 8199,10247,12295,14343,16391,18439,20487,22535,24583,26631
+ dw 28679,30727,32775,34823,36871,38919,40967,43015,45063,47111,49159,51207,53255,55303
+ dw 57351,59399,61447,63495
+
+LABEL shiftdata6 WORD
+ dw 0, 1024, 2048, 3072, 4096, 5120, 6144, 7168, 8192, 9216,10240,11264,12288,13312
+ dw 14336,15360,16384,17408,18432,19456,20480,21504,22528,23552,24576,25600,26624,27648
+ dw 28672,29696,30720,31744,32768,33792,34816,35840,36864,37888,38912,39936,40960,41984
+ dw 43008,44032,45056,46080,47104,48128,49152,50176,51200,52224,53248,54272,55296,56320
+ dw 57344,58368,59392,60416,61440,62464,63488,64512, 1, 1025, 2049, 3073, 4097, 5121
+ dw 6145, 7169, 8193, 9217,10241,11265,12289,13313,14337,15361,16385,17409,18433,19457
+ dw 20481,21505,22529,23553,24577,25601,26625,27649,28673,29697,30721,31745,32769,33793
+ dw 34817,35841,36865,37889,38913,39937,40961,41985,43009,44033,45057,46081,47105,48129
+ dw 49153,50177,51201,52225,53249,54273,55297,56321,57345,58369,59393,60417,61441,62465
+ dw 63489,64513, 2, 1026, 2050, 3074, 4098, 5122, 6146, 7170, 8194, 9218,10242,11266
+ dw 12290,13314,14338,15362,16386,17410,18434,19458,20482,21506,22530,23554,24578,25602
+ dw 26626,27650,28674,29698,30722,31746,32770,33794,34818,35842,36866,37890,38914,39938
+ dw 40962,41986,43010,44034,45058,46082,47106,48130,49154,50178,51202,52226,53250,54274
+ dw 55298,56322,57346,58370,59394,60418,61442,62466,63490,64514, 3, 1027, 2051, 3075
+ dw 4099, 5123, 6147, 7171, 8195, 9219,10243,11267,12291,13315,14339,15363,16387,17411
+ dw 18435,19459,20483,21507,22531,23555,24579,25603,26627,27651,28675,29699,30723,31747
+ dw 32771,33795,34819,35843,36867,37891,38915,39939,40963,41987,43011,44035,45059,46083
+ dw 47107,48131,49155,50179,51203,52227,53251,54275,55299,56323,57347,58371,59395,60419
+ dw 61443,62467,63491,64515
+
+LABEL shiftdata7 WORD
+ dw 0, 512, 1024, 1536, 2048, 2560, 3072, 3584, 4096, 4608, 5120, 5632, 6144, 6656
+ dw 7168, 7680, 8192, 8704, 9216, 9728,10240,10752,11264,11776,12288,12800,13312,13824
+ dw 14336,14848,15360,15872,16384,16896,17408,17920,18432,18944,19456,19968,20480,20992
+ dw 21504,22016,22528,23040,23552,24064,24576,25088,25600,26112,26624,27136,27648,28160
+ dw 28672,29184,29696,30208,30720,31232,31744,32256,32768,33280,33792,34304,34816,35328
+ dw 35840,36352,36864,37376,37888,38400,38912,39424,39936,40448,40960,41472,41984,42496
+ dw 43008,43520,44032,44544,45056,45568,46080,46592,47104,47616,48128,48640,49152,49664
+ dw 50176,50688,51200,51712,52224,52736,53248,53760,54272,54784,55296,55808,56320,56832
+ dw 57344,57856,58368,58880,59392,59904,60416,60928,61440,61952,62464,62976,63488,64000
+ dw 64512,65024, 1, 513, 1025, 1537, 2049, 2561, 3073, 3585, 4097, 4609, 5121, 5633
+ dw 6145, 6657, 7169, 7681, 8193, 8705, 9217, 9729,10241,10753,11265,11777,12289,12801
+ dw 13313,13825,14337,14849,15361,15873,16385,16897,17409,17921,18433,18945,19457,19969
+ dw 20481,20993,21505,22017,22529,23041,23553,24065,24577,25089,25601,26113,26625,27137
+ dw 27649,28161,28673,29185,29697,30209,30721,31233,31745,32257,32769,33281,33793,34305
+ dw 34817,35329,35841,36353,36865,37377,37889,38401,38913,39425,39937,40449,40961,41473
+ dw 41985,42497,43009,43521,44033,44545,45057,45569,46081,46593,47105,47617,48129,48641
+ dw 49153,49665,50177,50689,51201,51713,52225,52737,53249,53761,54273,54785,55297,55809
+ dw 56321,56833,57345,57857,58369,58881,59393,59905,60417,60929,61441,61953,62465,62977
+ dw 63489,64001,64513,65025
+
+
+shifttabletable dw shiftdata0,shiftdata1,shiftdata2,shiftdata3
+ dw shiftdata4,shiftdata5,shiftdata6,shiftdata7
+
+shiftdrawtable dw egafont1,egafont1,egafont2,egafont3
+
+fontcolor dw 15 ;0-16 mapmask value
+px dw 0
+py dw 0
+pdrawmode dw 11000b
+fontseg dw ?
+
+PUBLIC fontcolor,px,py,pdrawmode,fontseg
+
+pcharheight equ 0 ;lines high
+charloc equ 2 ;address of every character
+charwidth equ 514 ;width in pixels
+
+
+; temporary variables, to be optimised out later
+
+sourceptr dw 0
+destptr dw 0
+shiftptr dw 0
+drawptr dw 0
+
+egaxor dw 0
+
+CODESEG
+
+
+;==================
+;
+; DrawPchar
+; Draws a proportional character at px,py, and increments px
+;
+;==================
+
+PROC DrawPchar charnum:WORD
+PUBLIC DrawPchar
+USES si,di
+
+; set write mode 0
+ mov dx,GC_INDEX
+ mov ax,GC_MODE
+ WORDOUT
+
+; set xor mode
+ mov al,GC_DATAROTATE
+ mov ah,[BYTE pdrawmode]
+ WORDOUT
+
+; set mapmask to color
+ mov dx,SC_INDEX
+ mov al,SC_MAPMASK
+ mov ah,[BYTE fontcolor]
+ WORDOUT
+
+ mov es,[fontseg] ;font segment
+
+;
+; calculate destination on screen
+;
+ mov bx,[py]
+ shl bx,1
+ mov di,[ylookup+bx]
+ add di,[screenofs]
+
+ mov bx,[px]
+ mov ax,bx
+ shr ax,1
+ shr ax,1
+ shr ax,1 ;x location in bytes
+ add di,ax
+ mov [destptr],di ; DI holds destination <<<<<========
+
+;
+; look up which shift table to use, based on x coordinate
+;
+ and bx,7 ;low bits of x location
+ shl bx,1
+ mov ax,[shifttabletable+bx]
+ mov [shiftptr],ax ;<<<<<<=========
+
+;
+; find character location, width, and height
+;
+ mov bx,[charnum] ;move source for pic into bx
+ mov si,[es:charwidth+bx]
+ and si,0ffh
+ shl bx,1
+ mov ax,[es:charloc+bx]
+ mov [sourceptr],ax ;<<<<<<=========
+
+ add [px],si ;move the location for the next drawing
+ add si,7
+ shr si,1
+ shr si,1
+ shr si,1
+
+; advance past mask for or only
+ mov ax,si
+ mov dx,[es:pcharheight]
+ mul dl
+ add [sourceptr],ax
+;
+
+ shl si,1 ;bytes wide
+ mov ax,[shiftdrawtable+si] ;procedure to draw this width
+ mov [drawptr],ax ;<<<<<<=========
+
+; xor in data
+ mov bx,[sourceptr]
+ mov bp,[shiftptr]
+ mov cx,[es:pcharheight]
+ mov es,[screenseg]
+ mov ds,[fontseg]
+ call [ss:drawptr]
+
+; set copy mode
+ mov dx,GC_INDEX
+ mov ax,GC_DATAROTATE
+ WORDOUT
+
+; set mapmask to all
+ mov dx,SC_INDEX
+ mov ax,SC_MAPMASK + 15*256
+ WORDOUT
+
+ mov ax,ss
+ mov ds,ax
+ ret
+
+ENDP
+
+; ax scratch
+; bx source location
+; cx height counter
+; dx xor value
+; si byte value*2, to look up in scale table
+; di screen location
+; bp scale table to use
+;
+; ds source segment
+; es screenseg
+; ss table segment
+
+
+MACRO SHIFTXOR
+ mov al,[bx] ;source data
+ xor ah,ah
+ shl ax,1
+ mov si,ax
+
+ mov al,[es:di] ;load latches
+ mov ax,[bp+si] ;shift into two bytes
+ xor ax,dx
+ stosb ;write latches
+ mov al,[es:di] ;load latches
+ mov [es:di],ah ;write latches
+ inc bx
+ENDM
+
+MACRO SHIFTNOXOR
+ mov al,[bx] ;source data
+ xor ah,ah
+ shl ax,1
+ mov si,ax
+
+ mov al,[es:di] ;load latches
+ mov ax,[bp+si] ;shift into two bytes
+ stosb ;write latches
+ mov al,[es:di] ;load latches
+ mov [es:di],ah ;write latches
+ inc bx
+ENDM
+
+
+EVEN
+egafont1: ; draw a font that is 1 byte wide
+ mov dx,[ss:linewidth]
+ dec dx
+EVEN
+@@loop1:
+ SHIFTNOXOR
+ add di,dx
+ loop @@loop1
+ ret
+
+
+EVEN
+egafont2: ; draw a font that is 2 byte wide
+ mov dx,[ss:linewidth]
+ dec dx
+ dec dx
+EVEN
+@@loop2:
+ SHIFTNOXOR
+ SHIFTNOXOR
+
+ add di,dx
+ loop @@loop2
+ ret
+
+
+EVEN
+egafont3: ; draw a font that is 3 byte wide
+ mov dx,[ss:linewidth]
+ dec dx
+ dec dx
+EVEN
+@@loop3:
+ SHIFTNOXOR
+ SHIFTNOXOR
+ SHIFTNOXOR
+
+ add di,dx
+ loop egafont3
+ ret
+
+
+endif ; if fonts
+
+;===========================================================================
+;
+; SCALING GRAPHICS
+;
+;===========================================================================
+
+
+
+MACRO MAKELAB NUM
+
+lab&NUM:
+
+ENDM
+
+MACRO MAKEREF NUM
+
+dw OFFSET lab&NUM
+
+ENDM
+
+
+;=========================================================================
+
+MAXSCALES equ 256
+
+ DATASEG
+
+LABEL endtable WORD
+labcount = 0
+REPT MAXSCALES
+MAKEREF %labcount
+labcount = labcount + 1
+ENDM
+
+
+ CODESEG
+
+;==================================================
+;
+; void scaleline (int scale, unsigned picseg, unsigned maskseg,
+; unsigned screen, unsigned width)
+;
+;==================================================
+
+PROC ScaleLine pixels:word, scaleptr:dword, picptr:dword, screen:word
+USES si,di
+PUBLIC ScaleLine
+
+;
+; modify doline procedure for proper width
+;
+ mov bx,[pixels]
+ cmp bx,MAXSCALES
+ jbe @@scaleok
+ mov bx,MAXSCALES
+@@scaleok:
+ shl bx,1
+ mov bx,[endtable+bx]
+ push [cs:bx] ;save the code that will be modified over
+ mov [WORD cs:bx],0d18eh ;mov ss,cx
+ push [cs:bx+2] ;save the code that will be modified over
+ mov [WORD cs:bx+2],90c3h ;ret / nop
+ push bx
+
+ mov dx,[linewidth]
+
+ mov di,[WORD screen]
+ mov es,[screenseg]
+
+ mov si,[WORD scaleptr]
+ mov ds,[WORD scaleptr+2]
+
+ mov bx,[WORD picptr]
+ mov ax,[WORD picptr+2] ;will be moved into ss after call
+
+ mov bp,bx
+
+ cli
+ call doline
+ sti
+;
+; restore doline to regular state
+;
+ pop bx ;address of modified code
+ pop [cs:bx+2]
+ pop [cs:bx]
+
+ mov ax,ss
+ mov ds,ax
+ ret
+
+;================
+;
+; doline
+;
+; Big unwound scaling routine
+;
+; ds:si = scale table
+; ss:bx = pic data
+; es:di = screen location
+;
+;================
+
+doline:
+
+ mov cx,ss
+ mov ss,ax ;can't call a routine with ss used...
+
+labcount = 0
+
+REPT MAXSCALES
+
+MAKELAB %labcount
+labcount = labcount + 1
+
+ lodsb ; get scaled pixel number
+ xlat [ss:bx] ; look it up in the picture
+ xchg [es:di],al ; load latches and write pixel to screen
+ add di,dx ; down to next line
+
+ENDM
+
+ mov ss,cx
+ ret
+
+ENDP
+
+;===========================================================================
+;
+; SPRITE routines
+;
+;===========================================================================
+
+if NUMSPRITES
+
+;============
+;
+; DrawSprite
+;
+; Source is a (void _seg *) to the sprite
+;
+; Must be in write mode 0
+;
+;============
+
+DATASEG
+
+EGAdraws dw BadSize,EGAone,EGAtwo,EGAthree,EGAfour,EGAfive,EGAsix
+ dw EGAseven,EGAeight,EGAnine,EGAten
+ dw 10 dup (BadSize)
+EGAdrawsOdd dw BadSize,EGAone,EGAtwoOdd,EGAthreeOdd,EGAfourOdd
+ dw EGAfiveOdd,EGAsixOdd,EGAsevenOdd,EGAeightOdd
+ dw EGAnineOdd,EGAtenOdd
+ dw 10 dup (BadSize)
+
+spriteroutine dw ?
+
+blocksize dw ?
+blockheight dw ?
+blockdest dw ?
+
+CODESEG
+
+PROC DrawSpriteT wide:WORD, height:WORD, source:WORD, dest:WORD, plsize:WORD
+USES SI,DI
+PUBLIC DrawSpriteT
+
+ mov ax,[dest]
+ mov [blockdest],ax
+ mov ax,[height]
+ mov [blockheight],ax
+ mov ax,[plsize]
+ mov [blocksize],ax
+ mov bx,ax
+ shl bx,1
+ shl bx,1 ;mask is four planes from first byte
+
+ mov si,[wide]
+ mov dx,[linewidth]
+ sub dx,si ;dx is delta to next line (move to bp)
+
+ shl si,1
+ mov di,[dest]
+ test di,1
+ jz @@evens
+ mov ax,[EGAdrawsOdd+si]
+ jmp @@gotit
+@@evens:
+ mov ax,[EGAdraws+si]
+@@gotit:
+ mov [spriteroutine],ax
+
+ mov es,[screenseg]
+ mov ds,[source]
+ mov bp,dx
+ xor si,si
+
+;=================
+;
+; AX: scratch
+; BX: offset to mask
+; CX: height
+; DX: scratch
+; SI: source in sprite
+; DI: screen
+; BP: delta to next line
+; DS: sprite
+; ES: screen
+; SS: stack
+;
+;=================
+
+;
+; draw plane 0
+;
+ mov dx,SC_INDEX
+ mov ax,1*256+SC_MAPMASK
+ WORDOUT
+ add dx,GC_INDEX-SC_INDEX
+ mov ax,0*256+GC_READMAP
+ WORDOUT
+ mov cx,[ss:blockheight]
+ mov di,[ss:blockdest]
+ call [ss: spriteroutine] ;draw the plane's data
+
+;
+; draw plane 1
+;
+ mov dx,SC_INDEX
+ mov ax,2*256+SC_MAPMASK
+ WORDOUT
+ add dx,GC_INDEX-SC_INDEX
+ mov ax,1*256+GC_READMAP
+ WORDOUT
+ sub bx,[ss:blocksize]
+ mov cx,[ss:blockheight]
+ mov di,[ss:blockdest]
+ call [ss:spriteroutine] ;draw the plane's data
+
+;
+; draw plane 2
+;
+ mov dx,SC_INDEX
+ mov ax,4*256+SC_MAPMASK
+ WORDOUT
+ add dx,GC_INDEX-SC_INDEX
+ mov ax,2*256+GC_READMAP
+ WORDOUT
+ sub bx,[ss:blocksize]
+ mov cx,[ss:blockheight]
+ mov di,[ss:blockdest]
+ call [ss:spriteroutine] ;draw the plane's data
+
+;
+; draw plane 3
+;
+ mov dx,SC_INDEX
+ mov ax,8*256+SC_MAPMASK
+ WORDOUT
+ add dx,GC_INDEX-SC_INDEX
+ mov ax,3*256+GC_READMAP
+ WORDOUT
+ sub bx,[ss:blocksize]
+ mov cx,[ss:blockheight]
+ mov di,[ss:blockdest]
+ call [ss:spriteroutine] ;draw the plane's data
+
+ mov ax,ss
+ mov ds,ax
+
+ ret
+
+ENDP
+
+;=================
+PROC BadSize
+
+ mov ax,@Data
+ mov ds,ax
+ mov ss,ax
+ ret
+ENDP
+
+;===========================================================================
+;
+; sprite macros
+;
+;===========================================================================
+
+MACRO MASKBYTE
+ mov dl,[es:di] ;background
+ and dl,[si+bx] ;mask
+ lodsb ;data
+ or al,dl
+ stosb ;screen
+ENDM
+
+MACRO MASKWORD
+ mov dx,[es:di] ;background
+ and dx,[si+bx] ;mask
+ lodsw ;data
+ or ax,dx
+ stosw ;screen
+ENDM
+
+;=================
+;
+; AX: scratch
+; BX: offset to mask
+; CX: height
+; DX: scratch
+; SI: source in sprite
+; DI: screen
+; BP: delta to next line
+; DS: sprite
+; ES: screen
+; SS: stack
+;
+;=================
+
+
+;===========================================================================
+;
+; even shifts
+;
+;===========================================================================
+
+
+EVEN
+PROC EGAone
+ MASKBYTE
+ add di,bp
+ loop EGAone
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAtwo
+ MASKWORD
+ add di,bp
+ loop EGAtwo
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAthree
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAthree
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAfour
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAfour
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAfive
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAfive
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAsix
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAsix
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAseven
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAseven
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAeight
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAeight
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAnine
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAnine
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAten
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAten
+ ret
+ENDP
+
+
+;===========================================================================
+;
+; odd shifts
+;
+;===========================================================================
+
+
+EVEN
+PROC EGAoneOdd
+ MASKBYTE
+ add di,bp
+ loop EGAoneOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAtwoOdd
+ MASKBYTE
+ MASKBYTE
+ add di,bp
+ loop EGAtwoOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAthreeOdd
+ MASKBYTE
+ MASKWORD
+ add di,bp
+ loop EGAthreeOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAfourOdd
+ MASKBYTE
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAfourOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAfiveOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAfiveOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAsixOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAsixOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAsevenOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAsevenOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAeightOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAeightOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAnineOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ add di,bp
+ loop EGAnineOdd
+ ret
+ENDP
+
+;=================
+
+EVEN
+PROC EGAtenOdd
+ MASKBYTE
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKWORD
+ MASKBYTE
+ add di,bp
+ loop EGAtenOdd
+ ret
+ENDP
+
+
+endif ; if numsprites
+
+END \ No newline at end of file
diff --git a/IDLIB.H b/IDLIB.H
new file mode 100644
index 0000000..09f48db
--- /dev/null
+++ b/IDLIB.H
@@ -0,0 +1,494 @@
+/* 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.
+ */
+
+#define EXTENSION "HOV"
+
+#include "GRAPHHOV.H"
+#include "SNDSHOV.H"
+
+#include <stdarg.h>
+#include <dos.h>
+#include <mem.h>
+#include <sys\stat.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <alloc.h>
+#include <io.h>
+
+#ifndef __jm__
+typedef enum {false,true} boolean;
+typedef unsigned char byte;
+#endif
+
+#define TRUE 1
+#define FALSE 0
+
+
+char extern ch,str[80]; // scratch variables
+
+#define SIGN(x) ((x)>0?1:-1)
+#define ABS(x) ((int)(x)>0?(x):-(x))
+#define LABS(x) ((long)(x)>0?(x):-(x))
+
+/*
+============================================================================
+
+ MEMORY MANAGER
+
+============================================================================
+*/
+
+
+typedef void _seg * memptr;
+
+#define MEMPTR(x) ((memptr)((unsigned)x))
+
+extern unsigned totalmem; // total paragraphs available
+extern int EMSpresent,XMSpresent;
+
+
+//==========================================================================
+
+//
+// public prototypes
+//
+
+void MMStartup (void);
+void MMShutdown (void);
+void MMMapEMS (void);
+void MMGetPtr (memptr *baseptr,long size);
+void MMFreePtr (memptr *baseptr);
+void MMSetPurge (memptr *baseptr, int purge);
+void MMSortMem (void);
+void MMBlockDump (void);
+unsigned MMUnusedMemory (void);
+unsigned MMTotalFree (void);
+
+void PatchPointers (void); // must be present in the main program
+
+/*
+============================================================================
+
+** Sound routines
+** Ties into INT 8, with a timer tic at 8 * normal rate (144/sec)
+
+============================================================================
+*/
+
+typedef enum {off,spkr,adlib} soundtype;
+
+typedef struct {unsigned start;
+ byte priority;
+ byte samplerate;
+ char name[12];} spksndtype;
+
+typedef struct {char id[4];
+ unsigned filelength;
+ unsigned filler[5];
+ spksndtype sounds[63];
+ unsigned freqdata[];} SPKRtable;
+
+
+soundtype extern soundmode;
+
+extern unsigned timerspeed;
+extern int dontplay;
+extern unsigned inttime;
+extern long timecount;
+
+extern unsigned int8hook; // address of function to call every tic
+
+extern memptr soundseg;
+extern unsigned sndptr;
+
+void StartupSound (void);
+void CallTimer (void);
+void ShutdownSound (void);
+void PlaySound (int sound);
+void PauseSound (void);
+void ContinueSound (void);
+void StopSound (void);
+void WaitEndSound (void);
+
+
+/*
+============================================================================
+
+** Control routines
+** Ties into INT 9 to intercept all key presses, but passes on to BIOS
+** The control panel handles all this stuff!
+
+============================================================================
+*/
+
+typedef enum {north,northeast,east,southeast,south,southwest,west,
+ northwest,nodir} dirtype;
+
+typedef struct {dirtype dir;
+ boolean button1,button2;} ControlStruct;
+
+typedef enum {keyboard,mouse,joystick1,joystick2,demo} inputtype;
+
+enum demoenum {notdemo,demoplay,recording};
+enum demoenum extern indemo;
+
+inputtype extern playermode[3];
+char extern keydown[128];
+int extern JoyXlow[3],
+ JoyXhigh[3],
+ JoyYlow [3],
+ JoyYhigh [3]; // 1&2 are used, 0 is just space
+
+int extern MouseSensitivity;
+char extern key[8], keyB1, keyB2; // scan codes for key control
+
+
+void StartupKbd (void); /* ASM */
+void ShutdownKbd (void); /* ASM */
+
+void ReadJoystick (int joynum,int *xcount,int *ycount);
+
+int JoyButton (void);
+void CalibrateJoy (int joynum);
+void Printscan (int sc);
+void calibratekeys (void);
+
+ControlStruct ControlKBD (void);
+ControlStruct ControlMouse (void);
+ControlStruct ControlJoystick (int joynum);
+ControlStruct ControlPlayer (int player);
+
+int NoBiosKey(int parm);
+extern int NBKscan,NBKascii,lastkey;
+
+/*
+===========================================================================
+
+** Miscellaneous library routines
+
+===========================================================================
+*/
+
+typedef struct
+{
+ unsigned bit0,bit1; // 0-255 is a character, > is a pointer to a node
+} huffnode;
+
+extern int useegamem;
+
+long unsigned int LoadFile(char *filename,char huge *buffer);
+void SaveFile(char *filename,char huge *buffer, long size);
+long Verify(char *filename);
+void StopDrive (void);
+
+void BloadinMM (char *filename,memptr *spot);
+void BloadinRLEMM (char *filename,memptr *spot);
+void BloadinHUFFMM (char *filename,memptr *spot);
+
+void HuffExpandFile (unsigned char huge *infile,
+ unsigned char huge *outfile);
+
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+ long length,huffnode *hufftable);
+
+void RLEBExpand (unsigned char far *source, unsigned char far *dest);
+
+void RLEExpand (char far *surce,char far *dest,long length);
+unsigned RLECompress (char far *source, unsigned Length, char far *dest);
+
+void InitRnd (boolean randomize); /* ASM */
+int Rnd (int max); /* ASM */
+void InitRndT (boolean randomize); /* ASM */
+int RndT (void); /* ASM */
+
+void ClearKeys (void);
+
+
+/*
+============================================================================
+
+** Graphic routines
+** Edge graphic file not needed
+**
+** Many of these #defines are duplicates as EQUs in EDGEASM, and must be ==
+
+============================================================================
+*/
+
+#define SC_INDEX 0x3C4
+#define SC_RESET 0
+#define SC_CLOCK 1
+#define SC_MAPMASK 2
+#define SC_CHARMAP 3
+#define SC_MEMMODE 4
+
+#define CRTC_INDEX 0x3D4
+#define CRTC_H_TOTAL 0
+#define CRTC_H_DISPEND 1
+#define CRTC_H_BLANK 2
+#define CRTC_H_ENDBLANK 3
+#define CRTC_H_RETRACE 4
+#define CRTC_H_ENDRETRACE 5
+#define CRTC_V_TOTAL 6
+#define CRTC_OVERFLOW 7
+#define CRTC_ROWSCAN 8
+#define CRTC_MAXSCANLINE 9
+#define CRTC_CURSORSTART 10
+#define CRTC_CURSOREND 11
+#define CRTC_STARTHIGH 12
+#define CRTC_STARTLOW 13
+#define CRTC_CURSORHIGH 14
+#define CRTC_CURSORLOW 15
+#define CRTC_V_RETRACE 16
+#define CRTC_V_ENDRETRACE 17
+#define CRTC_V_DISPEND 18
+#define CRTC_OFFSET 19
+#define CRTC_UNDERLINE 20
+#define CRTC_V_BLANK 21
+#define CRTC_V_ENDBLANK 22
+#define CRTC_MODE 23
+#define CRTC_LINECOMPARE 24
+
+
+#define GC_INDEX 0x3CE
+#define GC_SETRESET 0
+#define GC_ENABLESETRESET 1
+#define GC_COLORCOMPARE 2
+#define GC_DATAROTATE 3
+#define GC_READMAP 4
+#define GC_MODE 5
+#define GC_MISCELLANEOUS 6
+#define GC_COLORDONTCARE 7
+#define GC_BITMASK 8
+
+#define ATR_INDEX 0x3c0
+#define ATR_MODE 16
+#define ATR_OVERSCAN 17
+#define ATR_COLORPLANEENABLE 18
+#define ATR_PELPAN 19
+#define ATR_COLORSELECT 20
+
+#define SCREENWIDTH 40
+
+#define EGAWRITEMODE(x) asm{cli;mov dx,GC_INDEX;mov ax,GC_MODE+256*x;out dx,ax;sti;}
+#define EGABITMASK(x) asm{mov dx,GC_INDEX;mov ax,GC_BITMASK+256*x;out dx,ax;sti;}
+#define EGAMAPMASK(x) asm{cli;mov dx,SC_INDEX;mov ax,SC_MAPMASK+x*256;out dx,ax;sti;}
+
+typedef enum {text,CGAgr,EGAgr,VGAgr} grtype;
+typedef enum {NOcard,MDAcard,CGAcard,EGAcard,MCGAcard,VGAcard,
+ HGCcard=0x80,HGCPcard,HICcard} cardtype;
+
+grtype extern grmode;
+cardtype extern videocard;
+unsigned extern ylookup[256];
+int extern bordercolor;
+
+
+void SetScreenMode (grtype mode); // sets graphic mode
+void WaitVBL (int num); // waits for no sync, then sync
+
+void LoadPage(char *filename,unsigned dest);
+
+void EGAPlane (int plane); // read / write from plane 0-4
+void EGASplitScreen (int linenum); // splits a 200 line screen
+void CRTCstart (unsigned start); // set crtc high/low registers
+void EGAVirtualScreen (int width); // sets screen width
+void ColorBorder (int color); // sets overscan color
+
+cardtype VideoID (void); // returns the display adapter installed
+
+void SetDefaultColors(void); // full bright palete
+void FadeOut (void); // EGA 16 color palette fade
+void FadeIn (void);
+
+void XorBar(int xl,int yl,int width,int height);
+void Bar (int xl,int yl,int width,int height,int fill);
+
+/*
+============================================================================
+
+ IGRAB Graphic file routines
+
+ Based on number reported in GRAPHEXT.H header file!
+
+============================================================================
+*/
+
+typedef struct
+{
+ int width,
+ height,
+ orgx,orgy,
+ xl,yl,xh,yh,
+ shifts;
+} spritetype;
+
+
+typedef struct
+{
+ int width,height;
+} pictype;
+
+
+typedef struct
+{
+ int height;
+ int location[256];
+ char width[256];
+} fontstruct;
+
+
+extern unsigned screenseg; // normally 0xa000
+extern unsigned screenofs; // adjustment for panning and buffers
+ // from screenseg for UL corner
+extern unsigned screenorigin; // first byte viable on screen
+
+unsigned extern linewidth;
+
+
+//
+// cachable locations
+//
+
+extern memptr grsegs[NUMCHUNKS];
+extern char needgr[NUMCHUNKS]; // for caching
+
+#if NUMPICS>0
+extern pictype pictable[NUMPICS];
+#endif
+
+#if NUMPICM>0
+extern pictype picmtable[NUMPICS];
+extern unsigned picmsize[NUMPICS]; // plane size for drawing
+#endif
+
+#if NUMSPRITES>0
+extern spritetype image, spritetable[NUMSPRITES];
+extern unsigned spritesize[NUMSPRITES]; // plane size for drawing
+#endif
+
+
+//
+// proportional font stuff
+//
+#if NUMFONT+NUMFONTM>0
+extern unsigned fontcolor,pdrawmode;
+extern unsigned px,py;
+extern unsigned pxl,pxh,pyl,pyh;
+extern fontstruct _seg * fontseg;
+
+void DrawPchar (int picnum);
+void DrawMPchar (int picnum);
+#endif
+
+//
+// base drawing routines, x in bytes, y in lines
+//
+
+void DrawChar (int x, int y, int picnum);
+void MaskChar (int x, int y, int picnum);
+void CopyChar (int x, int y);
+void DrawPic (int x, int y, int picnum);
+void DrawSprite (int xcoord, int ycoord, int spritenum);
+void DrawSpriteT (unsigned wide,unsigned height,unsigned source,
+ unsigned dest, unsigned plsize);
+
+
+/*
+============================================================================
+
+** Mid level graphic routines
+
+============================================================================
+*/
+
+int extern sx,sy,leftedge, screencenterx ,screencentery, segoffset;
+
+int Get (void);
+int Input(char *string,int max);
+unsigned InputInt(void);
+void Print (const char *str);
+void Printxy(int x,int y,char *string);
+void PrintC(char *string);
+void PrintHexB(unsigned char value);
+void PrintHex(unsigned value);
+void PrintBin(unsigned value);
+void PrintInt (int val);
+void PrintLong (long val);
+
+void PPrint (const char *str);
+void CPPrint (const char *str);
+void PPrintInt (int val);
+void PPrintUnsigned (unsigned val);
+
+void DrawWindow (int xl, int yl, int xh, int yh);
+void EraseWindow (void);
+void CharBar (int xl,int yl, int xh, int yh, int ch);
+void CenterWindow (int width, int height);
+void ExpWin (int width, int height);
+void ExpWinH (int width, int height);
+void ExpWinV (int width, int height);
+void DrawFrame(int x1,int y1,int x2,int y2,int type);
+
+
+/*
+============================================================================
+
+** Game level routines
+
+============================================================================
+*/
+
+long extern score,highscore;
+int extern level;
+
+typedef struct { int width;
+ int height;
+ int planes;
+ int screenx;
+ int screeny;
+ int screenw;
+ int screenh;
+ unsigned planesize;
+ } LevelDef;
+
+LevelDef extern far *levelheader;
+unsigned extern far *mapplane[4]; // points into map
+int extern mapbwide,mapwwide,mapwidthextra,mapheight;
+
+
+//
+// get / set a tile value in the map
+//
+#define SETTILE(x,y,plane,value) *(mapplane[plane]+((y)*(unsigned)mapwwide+(x)))=value
+#define GETTILE(x,y,plane) (*(mapplane[plane]+((y)*(unsigned)mapwwide+(x)) ))
+
+
+void LoadCtrls (void);
+void SaveCtrls (void);
+
+/*
+============================================================================
+
+** Needed non library routines
+
+============================================================================
+*/
+
+void Quit (char *);
+void PatchPointers (void); // called after the memory manager sorts blocks
diff --git a/IDLIBC.ASM b/IDLIBC.ASM
new file mode 100644
index 0000000..6cf77c8
--- /dev/null
+++ b/IDLIBC.ASM
@@ -0,0 +1,8172 @@
+; 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.
+
+ ifndef ??version
+?debug macro
+ endm
+publicdll macro name
+ public name
+ endm
+$comm macro name,dist,size,count
+ comm dist name:BYTE:count*size
+ endm
+ else
+$comm macro name,dist,size,count
+ comm dist name[size]:BYTE:count
+ endm
+ endif
+ ?debug S "idlibc.c"
+ ?debug C E92C869D160869646C6962632E63
+ ?debug C E9D03A9E160749444C49422E48
+ ?debug C E9AE10A3160A4752415048484F562E48
+ ?debug C E92592951609534E4453484F562E48
+ ?debug C E900104D1616433A5C42435C494E434C5544455C7374646172672E+
+ ?debug C 68
+ ?debug C E900104D1613433A5C42435C494E434C5544455C646F732E68
+ ?debug C E900104D1613433A5C42435C494E434C5544455C6D656D2E68
+ ?debug C E900104D1618433A5C42435C494E434C5544455C7379735C737461+
+ ?debug C 742E68
+ ?debug C E900104D1615433A5C42435C494E434C5544455C66636E746C2E68
+ ?debug C E900104D1616433A5C42435C494E434C5544455C7374646C69622E+
+ ?debug C 68
+ ?debug C E900104D1615433A5C42435C494E434C5544455C616C6C6F632E68
+ ?debug C E900104D1612433A5C42435C494E434C5544455C696F2E68
+_TEXT segment byte public 'CODE'
+_TEXT ends
+DGROUP group _DATA,_BSS
+ assume cs:_TEXT,ds:DGROUP
+_DATA segment word public 'DATA'
+d@ label byte
+d@w label word
+_DATA ends
+_BSS segment word public 'BSS'
+b@ label byte
+b@w label word
+_BSS ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void CalibrateJoy (int joynum)
+ ;
+ assume cs:_TEXT
+_CalibrateJoy proc near
+ push bp
+ mov bp,sp
+ sub sp,42
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; int stage,dx,dy,xl,yl,xh,yh;
+ ; ControlStruct ctr;
+ ;
+ ; ExpWin (34,11);
+ ;
+ mov ax,11
+ push ax
+ mov ax,34
+ push ax
+ call near ptr _ExpWin
+ pop cx
+ pop cx
+ ;
+ ;
+ ;
+ ; fontcolor=13;
+ ;
+ mov word ptr DGROUP:_fontcolor,13
+ ;
+ ; CPPrint("Joystick Configuration\n");
+ ;
+ mov ax,offset DGROUP:s@
+ push ax
+ call near ptr _CPPrint
+ pop cx
+ ;
+ ; py+=6;
+ ;
+ add word ptr DGROUP:_py,6
+ ;
+ ; fontcolor=15;
+ ;
+ mov word ptr DGROUP:_fontcolor,15
+ ;
+ ; PPrint("Hold the joystick in the UPPER LEFT\n");
+ ;
+ mov ax,offset DGROUP:s@+24
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint("corner and press a button:");
+ ;
+ mov ax,offset DGROUP:s@+61
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; stage=15;
+ ;
+ mov di,15
+ ;
+ ; sx=(px+7)/8;
+ ;
+ mov ax,word ptr DGROUP:_px
+ add ax,7
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ mov word ptr DGROUP:_sx,ax
+@1@50:
+ ;
+ ; do // wait for a button press
+ ; {
+ ; DrawChar (sx,py,stage);
+ ;
+ push di
+ push word ptr DGROUP:_py
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; WaitVBL (3);
+ ;
+ mov ax,3
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; if (++stage==23)
+ ;
+ inc di
+ mov ax,di
+ cmp ax,23
+ jne short @1@98
+ ;
+ ; stage=15;
+ ;
+ mov di,15
+@1@98:
+ ;
+ ; ReadJoystick (joynum,&xl,&yl);
+ ;
+ lea ax,word ptr [bp-8]
+ push ax
+ lea ax,word ptr [bp-6]
+ push ax
+ push si
+ call near ptr _ReadJoystick
+ add sp,6
+ ;
+ ; ctr = ControlJoystick(joynum);
+ ;
+ lea ax,word ptr [bp-18]
+ push ss
+ push ax
+ push si
+ push ss
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-24]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ ;
+ ; if (keydown[1])
+ ;
+ cmp byte ptr DGROUP:_keydown+1,0
+ je short @1@146
+ ;
+ ; return;
+ ;
+ jmp @1@674
+@1@146:
+ ;
+ ; } while (ctr.button1!= 1 && ctr.button2!=1);
+ ;
+ cmp word ptr [bp-16],1
+ je short @1@194
+ cmp word ptr [bp-14],1
+ jne short @1@50
+@1@194:
+ ;
+ ; DrawChar(sx,py,BLANKCHAR);
+ ;
+ mov ax,9
+ push ax
+ push word ptr DGROUP:_py
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+@1@218:
+ ;
+ ; do // wait for the button release
+ ; {
+ ; ctr = ControlJoystick(joynum);
+ ;
+ lea ax,word ptr [bp-18]
+ push ss
+ push ax
+ push si
+ push ss
+ lea ax,word ptr [bp-30]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-30]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ ;
+ ; } while (ctr.button1);
+ ;
+ cmp word ptr [bp-16],0
+ jne short @1@218
+ ;
+ ; WaitVBL (4); // so the button can't bounce
+ ;
+ mov ax,4
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ;
+ ; py+=6;
+ ;
+ add word ptr DGROUP:_py,6
+ ;
+ ; PPrint("\nHold the joystick in the LOWER RIGHT\n");
+ ;
+ mov ax,offset DGROUP:s@+88
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint("corner and press a button:");
+ ;
+ mov ax,offset DGROUP:s@+127
+ push ax
+ call near ptr _PPrint
+ pop cx
+@1@290:
+ ;
+ ; do // wait for a button press
+ ; {
+ ; DrawChar (sx,py,stage);
+ ;
+ push di
+ push word ptr DGROUP:_py
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; WaitVBL (3);
+ ;
+ mov ax,3
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; if (++stage==23)
+ ;
+ inc di
+ mov ax,di
+ cmp ax,23
+ jne short @1@338
+ ;
+ ; stage=15;
+ ;
+ mov di,15
+@1@338:
+ ;
+ ; ReadJoystick (joynum,&xh,&yh);
+ ;
+ lea ax,word ptr [bp-12]
+ push ax
+ lea ax,word ptr [bp-10]
+ push ax
+ push si
+ call near ptr _ReadJoystick
+ add sp,6
+ ;
+ ; ctr = ControlJoystick(joynum);
+ ;
+ lea ax,word ptr [bp-18]
+ push ss
+ push ax
+ push si
+ push ss
+ lea ax,word ptr [bp-36]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-36]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ ;
+ ; if (keydown[1])
+ ;
+ cmp byte ptr DGROUP:_keydown+1,0
+ je short @1@386
+ ;
+ ; return;
+ ;
+ jmp @1@674
+@1@386:
+ ;
+ ; } while (ctr.button1!= 1 && ctr.button2!=1);
+ ;
+ cmp word ptr [bp-16],1
+ je short @1@434
+ cmp word ptr [bp-14],1
+ jne short @1@290
+@1@434:
+ ;
+ ; DrawChar (sx,py,BLANKCHAR);
+ ;
+ mov ax,9
+ push ax
+ push word ptr DGROUP:_py
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+@1@458:
+ ;
+ ; do // wait for the button release
+ ; {
+ ; ctr = ControlJoystick(joynum);
+ ;
+ lea ax,word ptr [bp-18]
+ push ss
+ push ax
+ push si
+ push ss
+ lea ax,word ptr [bp-42]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-42]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ ;
+ ; } while (ctr.button1);
+ ;
+ cmp word ptr [bp-16],0
+ jne short @1@458
+ ;
+ ;
+ ; //
+ ; // figure out good boundaries
+ ; //
+ ;
+ ; dx=(xh-xl) / 6;
+ ;
+ mov ax,word ptr [bp-10]
+ sub ax,word ptr [bp-6]
+ mov bx,6
+ cwd
+ idiv bx
+ mov word ptr [bp-2],ax
+ ;
+ ; dy=(yh-yl) / 6;
+ ;
+ mov ax,word ptr [bp-12]
+ sub ax,word ptr [bp-8]
+ mov bx,6
+ cwd
+ idiv bx
+ mov word ptr [bp-4],ax
+ ;
+ ; JoyXlow[joynum]=xl+dx;
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr [bp-6]
+ add ax,word ptr [bp-2]
+ mov word ptr DGROUP:_JoyXlow[bx],ax
+ ;
+ ; JoyXhigh[joynum]=xh-dx;
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr [bp-10]
+ sub ax,word ptr [bp-2]
+ mov word ptr DGROUP:_JoyXhigh[bx],ax
+ ;
+ ; JoyYlow[joynum]=yl+dy;
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr [bp-8]
+ add ax,word ptr [bp-4]
+ mov word ptr DGROUP:_JoyYlow[bx],ax
+ ;
+ ; JoyYhigh[joynum]=yh-dy;
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr [bp-12]
+ sub ax,word ptr [bp-4]
+ mov word ptr DGROUP:_JoyYhigh[bx],ax
+ ;
+ ; if (joynum==1)
+ ;
+ cmp si,1
+ jne short @1@554
+ ;
+ ; playermode[1]=joystick1;
+ ;
+ mov word ptr DGROUP:_playermode+2,2
+ jmp short @1@578
+@1@554:
+ ;
+ ; else
+ ; playermode[1]=joystick2;
+ ;
+ mov word ptr DGROUP:_playermode+2,3
+@1@578:
+ ;
+ ;
+ ; py+=6;
+ ;
+ add word ptr DGROUP:_py,6
+ ;
+ ; PPrint ("\n(F)ire or (A)fterburn with B1 ?");
+ ;
+ mov ax,offset DGROUP:s@+154
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; ch = PGet();
+ ;
+ call near ptr _PGet
+ mov byte ptr DGROUP:_ch,al
+ ;
+ ; if ( ch == 'A' || ch == 'a')
+ ;
+ cmp byte ptr DGROUP:_ch,65
+ je short @1@626
+ cmp byte ptr DGROUP:_ch,97
+ jne short @1@650
+@1@626:
+ ;
+ ; buttonflip = 1;
+ ;
+ mov word ptr DGROUP:_buttonflip,1
+ jmp short @1@674
+@1@650:
+ ;
+ ; else
+ ; buttonflip = 0;
+ ;
+ mov word ptr DGROUP:_buttonflip,0
+@1@674:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_CalibrateJoy endp
+_TEXT ends
+_DATA segment word public 'DATA'
+ db 63
+ db 63
+ db 49
+ db 50
+ db 51
+ db 52
+ db 53
+ db 54
+ db 55
+ db 56
+ db 57
+ db 48
+ db 45
+ db 43
+ db 63
+ db 63
+ db 81
+ db 87
+ db 69
+ db 82
+ db 84
+ db 89
+ db 85
+ db 73
+ db 79
+ db 80
+ db 91
+ db 93
+ db 124
+ db 63
+ db 65
+ db 83
+ db 68
+ db 70
+ db 71
+ db 72
+ db 74
+ db 75
+ db 76
+ db 59
+ db 34
+ db 63
+ db 63
+ db 63
+ db 90
+ db 88
+ db 67
+ db 86
+ db 66
+ db 78
+ db 77
+ db 44
+ db 46
+ db 47
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 15
+ db 63
+ db 45
+ db 21
+ db 53
+ db 17
+ db 43
+ db 63
+ db 19
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+ db 63
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void printscan (int sc)
+ ;
+ assume cs:_TEXT
+_printscan proc near
+ push bp
+ mov bp,sp
+ sub sp,4
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; char static chartable[128] =
+ ; {'?','?','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
+ ; 'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
+ ; 'D','F','G','H','J','K','L',';','"','?','?','?','Z','X','C','V',
+ ; 'B','N','M',',','.','/','?','?','?','?','?','?','?','?','?','?',
+ ; '?','?','?','?','?','?','?','?', 15,'?','-', 21,'5', 17,'+','?',
+ ; 19,'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+ ; '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+ ; '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'};
+ ;
+ ; sc = sc & 0x7f;
+ ;
+ mov ax,si
+ and ax,127
+ mov si,ax
+ ;
+ ;
+ ; if (sc==1)
+ ;
+ cmp si,1
+ jne short @2@74
+ ;
+ ; PPrint ("ESC");
+ ;
+ mov ax,offset DGROUP:s@+187
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@74:
+ ;
+ ; else if (sc==0xe)
+ ;
+ cmp si,14
+ jne short @2@122
+ ;
+ ; PPrint ("BKSP");
+ ;
+ mov ax,offset DGROUP:s@+191
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@122:
+ ;
+ ; else if (sc==0xf)
+ ;
+ cmp si,15
+ jne short @2@170
+ ;
+ ; PPrint ("TAB");
+ ;
+ mov ax,offset DGROUP:s@+196
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@170:
+ ;
+ ; else if (sc==0x1d)
+ ;
+ cmp si,29
+ jne short @2@218
+ ;
+ ; PPrint ("CTRL");
+ ;
+ mov ax,offset DGROUP:s@+200
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@218:
+ ;
+ ; else if (sc==0x2A)
+ ;
+ cmp si,42
+ jne short @2@266
+ ;
+ ; PPrint ("LSHIFT");
+ ;
+ mov ax,offset DGROUP:s@+205
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@266:
+ ;
+ ; else if (sc==0x39)
+ ;
+ cmp si,57
+ jne short @2@314
+ ;
+ ; PPrint ("SPACE");
+ ;
+ mov ax,offset DGROUP:s@+212
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@314:
+ ;
+ ; else if (sc==0x3A)
+ ;
+ cmp si,58
+ jne short @2@362
+ ;
+ ; PPrint ("CAPSLK");
+ ;
+ mov ax,offset DGROUP:s@+218
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@362:
+ ;
+ ; else if (sc>=0x3b && sc<=0x44)
+ ;
+ cmp si,59
+ jl short @2@458
+ cmp si,68
+ jg short @2@458
+ ;
+ ; {
+ ; char str[3];
+ ; PPrint ("F");
+ ;
+ mov ax,offset DGROUP:s@+225
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; itoa (sc-0x3a,str,10);
+ ;
+ mov ax,10
+ push ax
+ lea ax,word ptr [bp-4]
+ push ax
+ mov ax,si
+ add ax,65478
+ push ax
+ call near ptr _itoa
+ add sp,6
+ ;
+ ; PPrint (str);
+ ;
+ lea ax,word ptr [bp-4]
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; }
+ ;
+ jmp @2@1346
+@2@458:
+ ;
+ ; else if (sc==0x57)
+ ;
+ cmp si,87
+ jne short @2@506
+ ;
+ ; PPrint ("F11");
+ ;
+ mov ax,offset DGROUP:s@+227
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@506:
+ ;
+ ; else if (sc==0x59)
+ ;
+ cmp si,89
+ jne short @2@554
+ ;
+ ; PPrint ("F12");
+ ;
+ mov ax,offset DGROUP:s@+231
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@554:
+ ;
+ ; else if (sc==0x46)
+ ;
+ cmp si,70
+ jne short @2@602
+ ;
+ ; PPrint ("SCRLLK");
+ ;
+ mov ax,offset DGROUP:s@+235
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@602:
+ ;
+ ; else if (sc==0x1c)
+ ;
+ cmp si,28
+ jne short @2@650
+ ;
+ ; PPrint ("ENTER");
+ ;
+ mov ax,offset DGROUP:s@+242
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@650:
+ ;
+ ; else if (sc==0x36)
+ ;
+ cmp si,54
+ jne short @2@698
+ ;
+ ; PPrint ("RSHIFT");
+ ;
+ mov ax,offset DGROUP:s@+248
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@698:
+ ;
+ ; else if (sc==0x37)
+ ;
+ cmp si,55
+ jne short @2@746
+ ;
+ ; PPrint ("PRTSC");
+ ;
+ mov ax,offset DGROUP:s@+255
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@746:
+ ;
+ ; else if (sc==0x38)
+ ;
+ cmp si,56
+ jne short @2@794
+ ;
+ ; PPrint ("ALT");
+ ;
+ mov ax,offset DGROUP:s@+261
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@794:
+ ;
+ ; else if (sc==0x47)
+ ;
+ cmp si,71
+ jne short @2@842
+ ;
+ ; PPrint ("HOME");
+ ;
+ mov ax,offset DGROUP:s@+265
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@842:
+ ;
+ ; else if (sc==0x49)
+ ;
+ cmp si,73
+ jne short @2@890
+ ;
+ ; PPrint ("PGUP");
+ ;
+ mov ax,offset DGROUP:s@+270
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@890:
+ ;
+ ; else if (sc==0x4f)
+ ;
+ cmp si,79
+ jne short @2@938
+ ;
+ ; PPrint ("END");
+ ;
+ mov ax,offset DGROUP:s@+275
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@938:
+ ;
+ ; else if (sc==0x51)
+ ;
+ cmp si,81
+ jne short @2@986
+ ;
+ ; PPrint ("PGDN");
+ ;
+ mov ax,offset DGROUP:s@+279
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp @2@1346
+@2@986:
+ ;
+ ; else if (sc==0x52)
+ ;
+ cmp si,82
+ jne short @2@1034
+ ;
+ ; PPrint ("INS");
+ ;
+ mov ax,offset DGROUP:s@+284
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1034:
+ ;
+ ; else if (sc==0x53)
+ ;
+ cmp si,83
+ jne short @2@1082
+ ;
+ ; PPrint ("DEL");
+ ;
+ mov ax,offset DGROUP:s@+288
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1082:
+ ;
+ ; else if (sc==0x45)
+ ;
+ cmp si,69
+ jne short @2@1130
+ ;
+ ; PPrint ("NUMLK");
+ ;
+ mov ax,offset DGROUP:s@+292
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1130:
+ ;
+ ; else if (sc==0x48)
+ ;
+ cmp si,72
+ jne short @2@1178
+ ;
+ ; PPrint ("UP");
+ ;
+ mov ax,offset DGROUP:s@+298
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1178:
+ ;
+ ; else if (sc==0x50)
+ ;
+ cmp si,80
+ jne short @2@1226
+ ;
+ ; PPrint ("DOWN");
+ ;
+ mov ax,offset DGROUP:s@+301
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1226:
+ ;
+ ; else if (sc==0x4b)
+ ;
+ cmp si,75
+ jne short @2@1274
+ ;
+ ; PPrint ("LEFT");
+ ;
+ mov ax,offset DGROUP:s@+306
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1274:
+ ;
+ ; else if (sc==0x4d)
+ ;
+ cmp si,77
+ jne short @2@1322
+ ;
+ ; PPrint ("RIGHT");
+ ;
+ mov ax,offset DGROUP:s@+311
+ push ax
+ call near ptr _PPrint
+ pop cx
+ jmp short @2@1346
+@2@1322:
+ ;
+ ; else
+ ; {
+ ; str[0]=chartable[sc];
+ ;
+ mov al,byte ptr DGROUP:d@+0[si]
+ mov byte ptr DGROUP:_str,al
+ ;
+ ; str[1]=0;
+ ;
+ mov byte ptr DGROUP:_str+1,0
+ ;
+ ; PPrint (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _PPrint
+ pop cx
+@2@1346:
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_printscan endp
+ ;
+ ; void calibratekeys (void)
+ ;
+ assume cs:_TEXT
+_calibratekeys proc near
+ push bp
+ mov bp,sp
+ sub sp,8
+ push si
+ push di
+ ;
+ ; {
+ ; char ch;
+ ; int hx,hy,i,select,new;
+ ;
+ ; ExpWin (22,12);
+ ;
+ mov ax,12
+ push ax
+ mov ax,22
+ push ax
+ call near ptr _ExpWin
+ pop cx
+ pop cx
+ ;
+ ; fontcolor=13;
+ ;
+ mov word ptr DGROUP:_fontcolor,13
+ ;
+ ; CPPrint ("Keyboard Configuration");
+ ;
+ mov ax,offset DGROUP:s@+317
+ push ax
+ call near ptr _CPPrint
+ pop cx
+ ;
+ ; fontcolor=15;
+ ;
+ mov word ptr DGROUP:_fontcolor,15
+ ;
+ ; PPrint ("\n1 north");
+ ;
+ mov ax,offset DGROUP:s@+340
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\n2 east");
+ ;
+ mov ax,offset DGROUP:s@+349
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\n3 south");
+ ;
+ mov ax,offset DGROUP:s@+357
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\n4 west");
+ ;
+ mov ax,offset DGROUP:s@+366
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\n5 button1");
+ ;
+ mov ax,offset DGROUP:s@+374
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\n6 button2");
+ ;
+ mov ax,offset DGROUP:s@+385
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrint ("\nModify which action:");
+ ;
+ mov ax,offset DGROUP:s@+396
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; hx=(px+7)/8;
+ ;
+ mov ax,word ptr DGROUP:_px
+ add ax,7
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ mov word ptr [bp-4],ax
+ ;
+ ; hy=py;
+ ;
+ mov ax,word ptr DGROUP:_py
+ mov word ptr [bp-6],ax
+ ;
+ ; for (i=0;i<4;i++)
+ ;
+ xor si,si
+ jmp short @3@98
+@3@50:
+ ;
+ ; {
+ ; px=pxl+8*12;
+ ;
+ mov ax,word ptr DGROUP:_pxl
+ add ax,96
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=pyl+10*(1+i);
+ ;
+ mov ax,si
+ inc ax
+ mov dx,10
+ imul dx
+ mov dx,word ptr DGROUP:_pyl
+ add dx,ax
+ mov word ptr DGROUP:_py,dx
+ ;
+ ; PPrint(":");
+ ;
+ mov ax,offset DGROUP:s@+418
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; printscan (key[i*2]);
+ ;
+ mov bx,si
+ shl bx,1
+ mov al,byte ptr DGROUP:_key[bx]
+ cbw
+ push ax
+ call near ptr _printscan
+ pop cx
+ inc si
+@3@98:
+ cmp si,4
+ jl short @3@50
+ ;
+ ; }
+ ; px=pxl+8*12;
+ ;
+ mov ax,word ptr DGROUP:_pxl
+ add ax,96
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=pyl+10*5;
+ ;
+ mov ax,word ptr DGROUP:_pyl
+ add ax,50
+ mov word ptr DGROUP:_py,ax
+ ;
+ ; PPrint(":");
+ ;
+ mov ax,offset DGROUP:s@+420
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; printscan (keyB1);
+ ;
+ mov al,byte ptr DGROUP:_keyB1
+ cbw
+ push ax
+ call near ptr _printscan
+ pop cx
+ ;
+ ; px=pxl+8*12;
+ ;
+ mov ax,word ptr DGROUP:_pxl
+ add ax,96
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=pyl+10*6;
+ ;
+ mov ax,word ptr DGROUP:_pyl
+ add ax,60
+ mov word ptr DGROUP:_py,ax
+ ;
+ ; PPrint(":");
+ ;
+ mov ax,offset DGROUP:s@+422
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; printscan (keyB2);
+ ;
+ mov al,byte ptr DGROUP:_keyB2
+ cbw
+ push ax
+ call near ptr _printscan
+ pop cx
+@3@146:
+ ;
+ ;
+ ; do
+ ; {
+ ; px=hx*8;
+ ;
+ mov ax,word ptr [bp-4]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=hy;
+ ;
+ mov ax,word ptr [bp-6]
+ mov word ptr DGROUP:_py,ax
+ ;
+ ; DrawChar (hx,hy,BLANKCHAR);
+ ;
+ mov ax,9
+ push ax
+ push word ptr [bp-6]
+ push word ptr [bp-4]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; ch=PGet() % 256;
+ ;
+ call near ptr _PGet
+ mov bx,256
+ cwd
+ idiv bx
+ mov byte ptr [bp-1],dl
+ ;
+ ; if (ch<'1' || ch>'6')
+ ;
+ cmp byte ptr [bp-1],49
+ jl short @3@194
+ cmp byte ptr [bp-1],54
+ jle short @3@218
+@3@194:
+ ;
+ ; continue;
+ ;
+ jmp @3@530
+@3@218:
+ ;
+ ; select = ch - '1';
+ ;
+ mov al,byte ptr [bp-1]
+ cbw
+ add ax,65487
+ mov di,ax
+ ;
+ ; DrawPchar (ch);
+ ;
+ mov al,byte ptr [bp-1]
+ cbw
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; PPrint ("\nPress the new key:");
+ ;
+ mov ax,offset DGROUP:s@+424
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; ClearKeys ();
+ ;
+ call near ptr _ClearKeys
+ ;
+ ; new=-1;
+ ;
+ mov word ptr [bp-8],65535
+ jmp short @3@338
+@3@242:
+ ;
+ ; while (!keydown[++new])
+ ; if (new==0x79)
+ ;
+ cmp word ptr [bp-8],121
+ jne short @3@290
+ ;
+ ; new=-1;
+ ;
+ mov word ptr [bp-8],65535
+ jmp short @3@338
+@3@290:
+ ;
+ ; else if (new==0x29)
+ ;
+ cmp word ptr [bp-8],41
+ jne short @3@338
+ ;
+ ; new++; // skip STUPID left shifts!
+ ;
+ inc word ptr [bp-8]
+@3@338:
+ inc word ptr [bp-8]
+ mov bx,word ptr [bp-8]
+ mov al,byte ptr DGROUP:_keydown[bx]
+ cbw
+ or ax,ax
+ je short @3@242
+ ;
+ ; Bar(leftedge,py,22,10,0xff);
+ ;
+ mov ax,255
+ push ax
+ mov ax,10
+ push ax
+ mov ax,22
+ push ax
+ push word ptr DGROUP:_py
+ push word ptr DGROUP:_leftedge
+ call near ptr _Bar
+ add sp,10
+ ;
+ ; if (select<4)
+ ;
+ cmp di,4
+ jge short @3@410
+ ;
+ ; key[select*2]=new;
+ ;
+ mov bx,di
+ shl bx,1
+ mov al,byte ptr [bp-8]
+ mov byte ptr DGROUP:_key[bx],al
+@3@410:
+ ;
+ ; if (select==4)
+ ;
+ cmp di,4
+ jne short @3@458
+ ;
+ ; keyB1=new;
+ ;
+ mov al,byte ptr [bp-8]
+ mov byte ptr DGROUP:_keyB1,al
+@3@458:
+ ;
+ ; if (select==5)
+ ;
+ cmp di,5
+ jne short @3@506
+ ;
+ ; keyB2=new;
+ ;
+ mov al,byte ptr [bp-8]
+ mov byte ptr DGROUP:_keyB2,al
+@3@506:
+ ;
+ ; px=pxl+8*12;
+ ;
+ mov ax,word ptr DGROUP:_pxl
+ add ax,96
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=pyl+(select+2)*10;
+ ;
+ mov ax,di
+ inc ax
+ inc ax
+ mov dx,10
+ imul dx
+ mov dx,word ptr DGROUP:_pyl
+ add dx,ax
+ mov word ptr DGROUP:_py,dx
+ ;
+ ; Bar(px/8,py,9,10,0xff);
+ ;
+ mov ax,255
+ push ax
+ mov ax,10
+ push ax
+ mov ax,9
+ push ax
+ push word ptr DGROUP:_py
+ mov ax,word ptr DGROUP:_px
+ shr ax,1
+ shr ax,1
+ shr ax,1
+ push ax
+ call near ptr _Bar
+ add sp,10
+ ;
+ ; PPrint (":");
+ ;
+ mov ax,offset DGROUP:s@+444
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; printscan (new);
+ ;
+ push word ptr [bp-8]
+ call near ptr _printscan
+ pop cx
+ ;
+ ; ClearKeys ();
+ ;
+ call near ptr _ClearKeys
+ ;
+ ; ch='0'; // so the loop continues
+ ;
+ mov byte ptr [bp-1],48
+@3@530:
+ ;
+ ; } while (ch>='0' && ch<='9');
+ ;
+ cmp byte ptr [bp-1],48
+ jl short @3@578
+ cmp byte ptr [bp-1],57
+ jg @@82
+ jmp @3@146
+@@82:
+@3@578:
+ ;
+ ; playermode[1]=keyboard;
+ ;
+ mov word ptr DGROUP:_playermode+2,0
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_calibratekeys endp
+ ;
+ ; ControlStruct ControlKBD ()
+ ;
+ assume cs:_TEXT
+_ControlKBD proc near
+ push bp
+ mov bp,sp
+ sub sp,6
+ push si
+ push di
+ ;
+ ; {
+ ; int xmove=0,
+ ;
+ xor si,si
+ ;
+ ; ymove=0;
+ ;
+ xor di,di
+ ;
+ ; ControlStruct action;
+ ;
+ ; if (keydown [key[north]])
+ ;
+ mov al,byte ptr DGROUP:_key
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@74
+ ;
+ ; ymove=-1;
+ ;
+ mov di,65535
+@4@74:
+ ;
+ ; if (keydown [key[east]])
+ ;
+ mov al,byte ptr DGROUP:_key+2
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@122
+ ;
+ ; xmove=1;
+ ;
+ mov si,1
+@4@122:
+ ;
+ ; if (keydown [key[south]])
+ ;
+ mov al,byte ptr DGROUP:_key+4
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@170
+ ;
+ ; ymove=1;
+ ;
+ mov di,1
+@4@170:
+ ;
+ ; if (keydown [key[west]])
+ ;
+ mov al,byte ptr DGROUP:_key+6
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@218
+ ;
+ ; xmove=-1;
+ ;
+ mov si,65535
+@4@218:
+ ;
+ ;
+ ; if (keydown [key[northeast]])
+ ;
+ mov al,byte ptr DGROUP:_key+1
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@266
+ ;
+ ; {
+ ; ymove=-1;
+ ;
+ mov di,65535
+ ;
+ ; xmove=1;
+ ;
+ mov si,1
+@4@266:
+ ;
+ ; }
+ ; if (keydown [key[northwest]])
+ ;
+ mov al,byte ptr DGROUP:_key+7
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@314
+ ;
+ ; {
+ ; ymove=-1;
+ ;
+ mov di,65535
+ ;
+ ; xmove=-1;
+ ;
+ mov si,65535
+@4@314:
+ ;
+ ; }
+ ; if (keydown [key[southeast]])
+ ;
+ mov al,byte ptr DGROUP:_key+3
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@362
+ ;
+ ; {
+ ; ymove=1;
+ ;
+ mov di,1
+ ;
+ ; xmove=1;
+ ;
+ mov si,1
+@4@362:
+ ;
+ ; }
+ ; if (keydown [key[southwest]])
+ ;
+ mov al,byte ptr DGROUP:_key+5
+ cbw
+ mov bx,ax
+ cmp byte ptr DGROUP:_keydown[bx],0
+ je short @4@410
+ ;
+ ; {
+ ; ymove=1;
+ ;
+ mov di,1
+ ;
+ ; xmove=-1;
+ ;
+ mov si,65535
+@4@410:
+ ;
+ ; }
+ ;
+ ; switch (ymove*3+xmove)
+ ;
+ mov ax,di
+ mov dx,3
+ imul dx
+ add ax,si
+ sub ax,65532
+ mov bx,ax
+ cmp bx,8
+ ja short @4@698
+ shl bx,1
+ jmp word ptr cs:@4@C2394[bx]
+@4@482:
+ ;
+ ; {
+ ; case -4: action.dir = northwest; break;
+ ;
+ mov word ptr [bp-6],7
+ jmp short @4@698
+@4@506:
+ ;
+ ; case -3: action.dir = north; break;
+ ;
+ mov word ptr [bp-6],0
+ jmp short @4@698
+@4@530:
+ ;
+ ; case -2: action.dir = northeast; break;
+ ;
+ mov word ptr [bp-6],1
+ jmp short @4@698
+@4@554:
+ ;
+ ; case -1: action.dir = west; break;
+ ;
+ mov word ptr [bp-6],6
+ jmp short @4@698
+@4@578:
+ ;
+ ; case 0: action.dir = nodir; break;
+ ;
+ mov word ptr [bp-6],8
+ jmp short @4@698
+@4@602:
+ ;
+ ; case 1: action.dir = east; break;
+ ;
+ mov word ptr [bp-6],2
+ jmp short @4@698
+@4@626:
+ ;
+ ; case 2: action.dir = southwest; break;
+ ;
+ mov word ptr [bp-6],5
+ jmp short @4@698
+@4@650:
+ ;
+ ; case 3: action.dir = south; break;
+ ;
+ mov word ptr [bp-6],4
+ jmp short @4@698
+@4@674:
+ ;
+ ; case 4: action.dir = southeast; break;
+ ;
+ mov word ptr [bp-6],3
+ jmp short @4@698
+@4@698:
+ ;
+ ; }
+ ;
+ ; action.button1 = keydown [keyB1];
+ ;
+ mov al,byte ptr DGROUP:_keyB1
+ cbw
+ mov bx,ax
+ mov al,byte ptr DGROUP:_keydown[bx]
+ cbw
+ mov word ptr [bp-4],ax
+ ;
+ ; action.button2 = keydown [keyB2];
+ ;
+ mov al,byte ptr DGROUP:_keyB2
+ cbw
+ mov bx,ax
+ mov al,byte ptr DGROUP:_keydown[bx]
+ cbw
+ mov word ptr [bp-2],ax
+ ;
+ ;
+ ; return (action);
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ lea ax,word ptr [bp-6]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @4@722
+@4@722:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_ControlKBD endp
+@4@C2394 label word
+ dw @4@482
+ dw @4@506
+ dw @4@530
+ dw @4@554
+ dw @4@578
+ dw @4@602
+ dw @4@626
+ dw @4@650
+ dw @4@674
+ ;
+ ; void ReadJoystick (int joynum,int *xcount,int *ycount)
+ ;
+ assume cs:_TEXT
+_ReadJoystick proc near
+ push bp
+ mov bp,sp
+ sub sp,6
+ push si
+ push di
+ mov si,word ptr [bp+6]
+ mov di,word ptr [bp+8]
+ ;
+ ; {
+ ; int portval,a1,a2,xbit,ybit;
+ ;
+ ; if (joynum==1)
+ ;
+ cmp word ptr [bp+4],1
+ jne short @5@74
+ ;
+ ; {
+ ; xbit=1;
+ ;
+ mov word ptr [bp-4],1
+ ;
+ ; ybit=2;
+ ;
+ mov word ptr [bp-6],2
+ ;
+ ; }
+ ;
+ jmp short @5@98
+@5@74:
+ ;
+ ; else
+ ; {
+ ; xbit=4;
+ ;
+ mov word ptr [bp-4],4
+ ;
+ ; ybit=8;
+ ;
+ mov word ptr [bp-6],8
+@5@98:
+ ;
+ ; }
+ ;
+ ; *xcount = 0;
+ ;
+ mov word ptr [si],0
+ ;
+ ; *ycount = 0;
+ ;
+ mov word ptr [di],0
+ ;
+ ;
+ ; outportb (0x201,inportb (0x201)); /* start the signal pulse */
+ ;
+ mov dx,513
+ in al,dx
+ mov dx,513
+ out dx,al
+ ;
+ ;
+ ; asm cli;
+ ;
+ cli
+@5@146:
+ ;
+ ;
+ ; do
+ ; {
+ ; portval = inportb (0x201);
+ ;
+ mov dx,513
+ in al,dx
+ mov ah,0
+ mov bx,ax
+ ;
+ ; a1 = (portval & xbit) != 0;
+ ;
+ mov ax,word ptr [bp-4]
+ test bx,ax
+ je short @5@194
+ mov ax,1
+ jmp short @5@218
+@5@194:
+ xor ax,ax
+@5@218:
+ mov cx,ax
+ ;
+ ; a2 = (portval & ybit) != 0;
+ ;
+ mov ax,word ptr [bp-6]
+ test bx,ax
+ je short @5@266
+ mov ax,1
+ jmp short @5@290
+@5@266:
+ xor ax,ax
+@5@290:
+ mov word ptr [bp-2],ax
+ ;
+ ; *xcount+=a1;
+ ;
+ mov ax,cx
+ add word ptr [si],ax
+ ;
+ ; *ycount+=a2;
+ ;
+ mov ax,word ptr [bp-2]
+ add word ptr [di],ax
+ ;
+ ; } while ((a1+a2!=0) && (*xcount<500) && (*ycount<500));
+ ;
+ mov ax,cx
+ add ax,word ptr [bp-2]
+ je short @5@386
+ cmp word ptr [si],500
+ jge short @5@386
+ cmp word ptr [di],500
+ jl short @5@146
+@5@386:
+ ;
+ ;
+ ; asm sti;
+ ;
+ sti
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_ReadJoystick endp
+ ;
+ ; int JoyButton (void)
+ ;
+ assume cs:_TEXT
+_JoyButton proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int buttons = inportb (0x201); /* Get all four button status */
+ ;
+ mov dx,513
+ in al,dx
+ mov ah,0
+ mov si,ax
+ ;
+ ; if ((buttons & 0x10) == 0)
+ ;
+ test si,16
+ jne short @6@74
+ ;
+ ; return 1;
+ ;
+ mov ax,1
+ jmp short @6@146
+@6@74:
+ ;
+ ; if ((buttons & 0x20) == 0)
+ ;
+ test si,32
+ jne short @6@122
+ ;
+ ; return 2;
+ ;
+ mov ax,2
+ jmp short @6@146
+@6@122:
+ ;
+ ;
+ ; return 0;
+ ;
+ xor ax,ax
+ jmp short @6@146
+@6@146:
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_JoyButton endp
+ ;
+ ; ControlStruct ControlJoystick (int joynum)
+ ;
+ assume cs:_TEXT
+_ControlJoystick proc near
+ push bp
+ mov bp,sp
+ sub sp,14
+ push si
+ push di
+ mov si,word ptr [bp+8]
+ ;
+ ; {
+ ; int joyx = 0,joyy = 0, /* resistance in joystick */
+ ;
+ mov word ptr [bp-2],0
+ mov word ptr [bp-4],0
+ ;
+ ; xmove = 0,
+ ;
+ mov word ptr [bp-6],0
+ ;
+ ; ymove = 0,
+ ;
+ mov word ptr [bp-8],0
+ ;
+ ; buttons;
+ ; ControlStruct action;
+ ;
+ ; ReadJoystick (joynum,&joyx,&joyy);
+ ;
+ lea ax,word ptr [bp-4]
+ push ax
+ lea ax,word ptr [bp-2]
+ push ax
+ push si
+ call near ptr _ReadJoystick
+ add sp,6
+ ;
+ ; if ( (joyx>500) | (joyy>500) )
+ ;
+ cmp word ptr [bp-2],500
+ jle short @7@74
+ mov ax,1
+ jmp short @7@98
+@7@74:
+ xor ax,ax
+@7@98:
+ push ax
+ cmp word ptr [bp-4],500
+ jle short @7@146
+ mov ax,1
+ jmp short @7@170
+@7@146:
+ xor ax,ax
+@7@170:
+ pop dx
+ or dx,ax
+ je short @7@218
+ ;
+ ; {
+ ; joyx=JoyXlow [joynum] + 1; /* no joystick connected, do nothing */
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyXlow[bx]
+ inc ax
+ mov word ptr [bp-2],ax
+ ;
+ ; joyy=JoyYlow [joynum] + 1;
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyYlow[bx]
+ inc ax
+ mov word ptr [bp-4],ax
+@7@218:
+ ;
+ ; }
+ ;
+ ; if (joyx > JoyXhigh [joynum])
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyXhigh[bx]
+ cmp ax,word ptr [bp-2]
+ jge short @7@266
+ ;
+ ; xmove = 1;
+ ;
+ mov word ptr [bp-6],1
+ jmp short @7@314
+@7@266:
+ ;
+ ; else if (joyx < JoyXlow [joynum])
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyXlow[bx]
+ cmp ax,word ptr [bp-2]
+ jle short @7@314
+ ;
+ ; xmove = -1;
+ ;
+ mov word ptr [bp-6],65535
+@7@314:
+ ;
+ ; if (joyy > JoyYhigh [joynum])
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyYhigh[bx]
+ cmp ax,word ptr [bp-4]
+ jge short @7@362
+ ;
+ ; ymove = 1;
+ ;
+ mov word ptr [bp-8],1
+ jmp short @7@410
+@7@362:
+ ;
+ ; else if (joyy < JoyYlow [joynum])
+ ;
+ mov bx,si
+ shl bx,1
+ mov ax,word ptr DGROUP:_JoyYlow[bx]
+ cmp ax,word ptr [bp-4]
+ jle short @7@410
+ ;
+ ; ymove = -1;
+ ;
+ mov word ptr [bp-8],65535
+@7@410:
+ ;
+ ;
+ ; switch (ymove*3+xmove)
+ ;
+ mov ax,word ptr [bp-8]
+ mov dx,3
+ imul dx
+ add ax,word ptr [bp-6]
+ sub ax,65532
+ mov bx,ax
+ cmp bx,8
+ ja short @7@698
+ shl bx,1
+ jmp word ptr cs:@7@C3820[bx]
+@7@482:
+ ;
+ ; {
+ ; case -4: action.dir = northwest; break;
+ ;
+ mov word ptr [bp-14],7
+ jmp short @7@698
+@7@506:
+ ;
+ ; case -3: action.dir = north; break;
+ ;
+ mov word ptr [bp-14],0
+ jmp short @7@698
+@7@530:
+ ;
+ ; case -2: action.dir = northeast; break;
+ ;
+ mov word ptr [bp-14],1
+ jmp short @7@698
+@7@554:
+ ;
+ ; case -1: action.dir = west; break;
+ ;
+ mov word ptr [bp-14],6
+ jmp short @7@698
+@7@578:
+ ;
+ ; case 0: action.dir = nodir; break;
+ ;
+ mov word ptr [bp-14],8
+ jmp short @7@698
+@7@602:
+ ;
+ ; case 1: action.dir = east; break;
+ ;
+ mov word ptr [bp-14],2
+ jmp short @7@698
+@7@626:
+ ;
+ ; case 2: action.dir = southwest; break;
+ ;
+ mov word ptr [bp-14],5
+ jmp short @7@698
+@7@650:
+ ;
+ ; case 3: action.dir = south; break;
+ ;
+ mov word ptr [bp-14],4
+ jmp short @7@698
+@7@674:
+ ;
+ ; case 4: action.dir = southeast; break;
+ ;
+ mov word ptr [bp-14],3
+ jmp short @7@698
+@7@698:
+ ;
+ ; }
+ ;
+ ; buttons = inportb (0x201); /* Get all four button status */
+ ;
+ mov dx,513
+ in al,dx
+ mov ah,0
+ mov di,ax
+ ;
+ ; if (joynum == 1)
+ ;
+ cmp si,1
+ jne short @7@890
+ ;
+ ; {
+ ; action.button1 = ((buttons & 0x10) == 0);
+ ;
+ test di,16
+ jne short @7@770
+ mov ax,1
+ jmp short @7@794
+@7@770:
+ xor ax,ax
+@7@794:
+ mov word ptr [bp-12],ax
+ ;
+ ; action.button2 = ((buttons & 0x20) == 0);
+ ;
+ test di,32
+ jne short @7@842
+ mov ax,1
+ jmp short @7@866
+@7@842:
+ xor ax,ax
+@7@866:
+ mov word ptr [bp-10],ax
+ ;
+ ; }
+ ;
+ jmp short @7@1058
+@7@890:
+ ;
+ ; else
+ ; {
+ ; action.button1 = ((buttons & 0x40) == 0);
+ ;
+ test di,64
+ jne short @7@938
+ mov ax,1
+ jmp short @7@962
+@7@938:
+ xor ax,ax
+@7@962:
+ mov word ptr [bp-12],ax
+ ;
+ ; action.button2 = ((buttons & 0x80) == 0);
+ ;
+ test di,128
+ jne short @7@1010
+ mov ax,1
+ jmp short @7@1034
+@7@1010:
+ xor ax,ax
+@7@1034:
+ mov word ptr [bp-10],ax
+@7@1058:
+ ;
+ ; }
+ ; if (buttonflip)
+ ;
+ cmp word ptr DGROUP:_buttonflip,0
+ je short @7@1106
+ ;
+ ; {
+ ; buttons = action.button1;
+ ;
+ mov di,word ptr [bp-12]
+ ;
+ ; action.button1 = action.button2;
+ ;
+ mov ax,word ptr [bp-10]
+ mov word ptr [bp-12],ax
+ ;
+ ; action.button2 = buttons;
+ ;
+ mov word ptr [bp-10],di
+@7@1106:
+ ;
+ ; }
+ ; return (action);
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ lea ax,word ptr [bp-14]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @7@1130
+@7@1130:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_ControlJoystick endp
+@7@C3820 label word
+ dw @7@482
+ dw @7@506
+ dw @7@530
+ dw @7@554
+ dw @7@578
+ dw @7@602
+ dw @7@626
+ dw @7@650
+ dw @7@674
+ ;
+ ; ControlStruct ControlPlayer (int player)
+ ;
+ assume cs:_TEXT
+_ControlPlayer proc near
+ push bp
+ mov bp,sp
+ sub sp,24
+ ;
+ ; {
+ ; ControlStruct ret;
+ ;
+ ; switch (playermode[player])
+ ;
+ mov bx,word ptr [bp+8]
+ shl bx,1
+ mov ax,word ptr DGROUP:_playermode[bx]
+ or ax,ax
+ je short @8@146
+ cmp ax,2
+ je short @8@170
+ cmp ax,3
+ je short @8@194
+ jmp short @8@218
+@8@146:
+ ;
+ ; {
+ ; case keyboard : return ControlKBD ();
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ push ss
+ lea ax,word ptr [bp-6]
+ push ax
+ call near ptr _ControlKBD
+ pop cx
+ pop cx
+ lea ax,word ptr [bp-6]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @8@242
+@8@170:
+ ;
+ ; case joystick1: return ControlJoystick(1);
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ mov ax,1
+ push ax
+ push ss
+ lea ax,word ptr [bp-12]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-12]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @8@242
+@8@194:
+ ;
+ ; case joystick2: return ControlJoystick(2);
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ mov ax,2
+ push ax
+ push ss
+ lea ax,word ptr [bp-18]
+ push ax
+ call near ptr _ControlJoystick
+ add sp,6
+ lea ax,word ptr [bp-18]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @8@242
+@8@218:
+ ;
+ ; }
+ ;
+ ; return ControlKBD();
+ ;
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ push ss
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _ControlKBD
+ pop cx
+ pop cx
+ lea ax,word ptr [bp-24]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ mov ax,word ptr [bp+4]
+ jmp short @8@242
+@8@242:
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_ControlPlayer endp
+ ;
+ ; void ClearKeys (void)
+ ;
+ assume cs:_TEXT
+_ClearKeys proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; int i;
+ ; NBKscan=NBKascii=0;
+ ;
+ xor ax,ax
+ mov word ptr DGROUP:_NBKascii,ax
+ mov word ptr DGROUP:_NBKscan,ax
+ ;
+ ; memset (keydown,0,sizeof(keydown));
+ ;
+ mov ax,128
+ push ax
+ xor ax,ax
+ push ax
+ mov ax,offset DGROUP:_keydown
+ push ax
+ call near ptr _memset
+ add sp,6
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_ClearKeys endp
+ ;
+ ; void Ack(void)
+ ;
+ assume cs:_TEXT
+_Ack proc near
+ push bp
+ mov bp,sp
+ sub sp,12
+ ;
+ ; {
+ ; ControlStruct c;
+ ;
+ ; ClearKeys();
+ ;
+ call near ptr _ClearKeys
+@10@50:
+ ;
+ ; while (1)
+ ; {
+ ; if (NBKscan>127)
+ ;
+ cmp word ptr DGROUP:_NBKscan,127
+ jle short @10@98
+ ;
+ ; {
+ ; NBKscan&=0x7f;
+ ;
+ and word ptr DGROUP:_NBKscan,127
+ ;
+ ; return;
+ ;
+ jmp short @10@194
+@10@98:
+ ;
+ ; }
+ ; c = ControlPlayer(1);
+ ;
+ lea ax,word ptr [bp-6]
+ push ss
+ push ax
+ mov ax,1
+ push ax
+ push ss
+ lea ax,word ptr [bp-12]
+ push ax
+ call near ptr _ControlPlayer
+ add sp,6
+ lea ax,word ptr [bp-12]
+ push ss
+ push ax
+ mov cx,6
+ call near ptr N_SCOPY@
+ ;
+ ; if (c.button1 || c.button2)
+ ;
+ cmp word ptr [bp-4],0
+ jne short @10@146
+ cmp word ptr [bp-2],0
+ je short @10@170
+@10@146:
+ ;
+ ; return;
+ ;
+ jmp short @10@194
+@10@170:
+ jmp short @10@50
+@10@194:
+ ;
+ ; }
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_Ack endp
+ ;
+ ; unsigned long LoadFile(char *filename,char huge *buffer)
+ ;
+ assume cs:_TEXT
+_LoadFile proc near
+ push bp
+ mov bp,sp
+ sub sp,18
+ ;
+ ; {
+ ; unsigned handle,flength1=0,flength2=0,buf1,buf2,foff1,foff2,
+ ;
+ mov word ptr [bp-4],0
+ mov word ptr [bp-6],0
+ ;
+ ; len1,len2;
+ ;
+ ; buf1=FP_OFF(buffer);
+ ;
+ mov ax,word ptr [bp+6]
+ mov word ptr [bp-8],ax
+ ;
+ ; buf2=FP_SEG(buffer);
+ ;
+ mov ax,word ptr [bp+8]
+ mov word ptr [bp-10],ax
+ ;
+ ;
+ ; asm mov WORD PTR foff1,0 // file offset = 0 (start)
+ ;
+ mov WORD PTR [bp-12],0
+ ;
+ ; asm mov WORD PTR foff2,0
+ ;
+ mov WORD PTR [bp-14],0
+ ;
+ ;
+ ; asm mov dx,filename
+ ;
+ mov dx,[bp+4]
+ ;
+ ; asm mov ax,3d00h // OPEN w/handle (read only)
+ ;
+ mov ax,3d00h
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm jc out
+ ;
+ jc short @11@1274
+ ;
+ ;
+ ; asm mov handle,ax
+ ;
+ mov [bp-2],ax
+ ;
+ ; asm mov bx,ax
+ ;
+ mov bx,ax
+ ;
+ ; asm xor cx,cx
+ ;
+ xor cx,cx
+ ;
+ ; asm xor dx,dx
+ ;
+ xor dx,dx
+ ;
+ ; asm mov ax,4202h
+ ;
+ mov ax,4202h
+ ;
+ ; asm int 21h // SEEK (find file length)
+ ;
+ int 21h
+ ;
+ ; asm jc out
+ ;
+ jc short @11@1274
+ ;
+ ;
+ ; asm mov flength1,ax
+ ;
+ mov [bp-4],ax
+ ;
+ ; asm mov len1,ax
+ ;
+ mov [bp-16],ax
+ ;
+ ; asm mov flength2,dx
+ ;
+ mov [bp-6],dx
+ ;
+ ; asm mov len2,dx
+ ;
+ mov [bp-18],dx
+ ;
+ ;
+ ; asm mov bx,handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm xor cx,cx
+ ;
+ xor cx,cx
+ ;
+ ; asm xor dx,dx
+ ;
+ xor dx,dx
+ ;
+ ; asm mov ax,4200h
+ ;
+ mov ax,4200h
+ ;
+ ; asm int 21h // SEEK (to file start)
+ ;
+ int 21h
+ ;
+ ; asm jc out
+ ;
+ jc short @11@1274
+ ;
+ ;
+ ; asm cmp WORD PTR len2,0 // MULTI-SEGMENTAL?
+ ;
+ cmp WORD PTR [bp-18],0
+ ;
+ ; asm je L_2
+ ;
+ je short @11@1058
+@11@650:
+ ;
+ ;
+ ; L_1:
+ ;
+ ; asm push ds
+ ;
+ push ds
+ ;
+ ; asm mov bx,handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov cx,8000h // read 32K chunks
+ ;
+ mov cx,8000h
+ ;
+ ; asm mov dx,buf1
+ ;
+ mov dx,[bp-8]
+ ;
+ ; asm mov ax,buf2
+ ;
+ mov ax,[bp-10]
+ ;
+ ; asm mov ds,ax
+ ;
+ mov ds,ax
+ ;
+ ; asm mov ah,3fh // READ w/handle
+ ;
+ mov ah,3fh
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm pop ds
+ ;
+ pop ds
+ ;
+ ; asm jc out
+ ;
+ jc short @11@1274
+ ;
+ ;
+ ; asm add buf2,800h
+ ;
+ add [bp-10],800h
+ ;
+ ; asm sub len1,8000h
+ ;
+ sub [bp-16],8000h
+ ;
+ ; asm sbb WORD PTR len2,0
+ ;
+ sbb WORD PTR [bp-18],0
+ ;
+ ; asm cmp WORD PTR len2,0
+ ;
+ cmp WORD PTR [bp-18],0
+ ;
+ ; asm ja L_1
+ ;
+ ja short @11@650
+ ;
+ ; asm cmp len1,8000h
+ ;
+ cmp [bp-16],8000h
+ ;
+ ; asm jae L_1
+ ;
+ jae short @11@650
+@11@1058:
+ ;
+ ;
+ ; L_2:
+ ;
+ ; asm push ds
+ ;
+ push ds
+ ;
+ ; asm mov bx,handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov cx,len1
+ ;
+ mov cx,[bp-16]
+ ;
+ ; asm mov dx,buf1
+ ;
+ mov dx,[bp-8]
+ ;
+ ; asm mov ax,buf2
+ ;
+ mov ax,[bp-10]
+ ;
+ ; asm mov ds,ax
+ ;
+ mov ds,ax
+ ;
+ ; asm mov ah,3fh // READ w/handle
+ ;
+ mov ah,3fh
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm pop ds
+ ;
+ pop ds
+@11@1274:
+ ;
+ ;
+ ; out:
+ ;
+ ; asm mov bx,handle // CLOSE w/handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov ah,3eh
+ ;
+ mov ah,3eh
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ;
+ ;
+ ; return (flength2*0x10000+flength1);
+ ;
+ mov dx,word ptr [bp-6]
+ xor ax,ax
+ add ax,word ptr [bp-4]
+ adc dx,0
+ jmp short @11@1370
+@11@1370:
+ ;
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_LoadFile endp
+ ;
+ ; void SaveFile(char *filename,char huge *buffer, long size)
+ ;
+ assume cs:_TEXT
+_SaveFile proc near
+ push bp
+ mov bp,sp
+ sub sp,10
+ ;
+ ; {
+ ; unsigned int handle,buf1,buf2,foff1,foff2;
+ ;
+ ; buf1=FP_OFF(buffer);
+ ;
+ mov ax,word ptr [bp+6]
+ mov word ptr [bp-4],ax
+ ;
+ ; buf2=FP_SEG(buffer);
+ ;
+ mov ax,word ptr [bp+8]
+ mov word ptr [bp-6],ax
+ ;
+ ;
+ ; asm mov WORD PTR foff1,0 // file offset = 0 (start)
+ ;
+ mov WORD PTR [bp-8],0
+ ;
+ ; asm mov WORD PTR foff2,0
+ ;
+ mov WORD PTR [bp-10],0
+ ;
+ ;
+ ; asm mov dx,filename
+ ;
+ mov dx,[bp+4]
+ ;
+ ; asm mov ax,3c00h // CREATE w/handle (read only)
+ ;
+ mov ax,3c00h
+ ;
+ ; asm xor cx,cx
+ ;
+ xor cx,cx
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm jc out
+ ;
+ jc short @12@914
+ ;
+ ;
+ ; asm mov handle,ax
+ ;
+ mov [bp-2],ax
+ ;
+ ; asm cmp word ptr size+2,0 // larger than 1 segment?
+ ;
+ cmp word ptr [bp+10]+2,0
+ ;
+ ; asm je L2
+ ;
+ je short @12@674
+@12@290:
+ ;
+ ;
+ ; L1:
+ ;
+ ; asm push ds
+ ;
+ push ds
+ ;
+ ; asm mov bx,handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov cx,8000h
+ ;
+ mov cx,8000h
+ ;
+ ; asm mov dx,buf1
+ ;
+ mov dx,[bp-4]
+ ;
+ ; asm mov ax,buf2
+ ;
+ mov ax,[bp-6]
+ ;
+ ; asm mov ds,ax
+ ;
+ mov ds,ax
+ ;
+ ; asm mov ah,40h // WRITE w/handle
+ ;
+ mov ah,40h
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm pop ds
+ ;
+ pop ds
+ ;
+ ;
+ ; asm add buf2,800h // bump ptr up 1/2 segment
+ ;
+ add [bp-6],800h
+ ;
+ ; asm sub WORD PTR size,8000h // done yet?
+ ;
+ sub WORD PTR [bp+10],8000h
+ ;
+ ; asm sbb WORD PTR size+2,0
+ ;
+ sbb WORD PTR [bp+10]+2,0
+ ;
+ ; asm cmp WORD PTR size+2,0
+ ;
+ cmp WORD PTR [bp+10]+2,0
+ ;
+ ; asm ja L1
+ ;
+ ja short @12@290
+ ;
+ ; asm cmp WORD PTR size,8000h
+ ;
+ cmp WORD PTR [bp+10],8000h
+ ;
+ ; asm jae L1
+ ;
+ jae short @12@290
+@12@674:
+ ;
+ ;
+ ; L2:
+ ;
+ ; asm push ds
+ ;
+ push ds
+ ;
+ ; asm mov bx,handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov cx,WORD PTR size
+ ;
+ mov cx,WORD PTR [bp+10]
+ ;
+ ; asm mov dx,buf1
+ ;
+ mov dx,[bp-4]
+ ;
+ ; asm mov ax,buf2
+ ;
+ mov ax,[bp-6]
+ ;
+ ; asm mov ds,ax
+ ;
+ mov ds,ax
+ ;
+ ; asm mov ah,40h // WRITE w/handle
+ ;
+ mov ah,40h
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ; asm pop ds
+ ;
+ pop ds
+ ;
+ ; asm jmp out
+ ;
+ jmp short @12@914
+@12@914:
+ ;
+ ;
+ ; out:
+ ;
+ ; asm mov bx,handle // CLOSE w/handle
+ ;
+ mov bx,[bp-2]
+ ;
+ ; asm mov ah,3eh
+ ;
+ mov ah,3eh
+ ;
+ ; asm int 21h
+ ;
+ int 21h
+ ;
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_SaveFile endp
+ ;
+ ; void BloadinMM (char *filename,memptr *spot)
+ ;
+ assume cs:_TEXT
+_BloadinMM proc near
+ push bp
+ mov bp,sp
+ sub sp,86
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ mov di,word ptr [bp+6]
+ ;
+ ; {
+ ; int handle;
+ ; long length;
+ ; char huge *location;
+ ; char error[80];
+ ;
+ ; if ( (handle = open (filename,O_BINARY)) != -1 )
+ ;
+ mov ax,32768
+ push ax
+ push si
+ call near ptr _open
+ pop cx
+ pop cx
+ mov word ptr [bp-2],ax
+ cmp ax,65535
+ je short @13@74
+ ;
+ ; {
+ ; length = filelength (handle);
+ ;
+ push word ptr [bp-2]
+ call near ptr _filelength
+ pop cx
+ mov word ptr [bp-4],dx
+ mov word ptr [bp-6],ax
+ ;
+ ; MMGetPtr (spot,length);
+ ;
+ push word ptr [bp-4]
+ push word ptr [bp-6]
+ push di
+ call near ptr _MMGetPtr
+ add sp,6
+ ;
+ ; close (handle);
+ ;
+ push word ptr [bp-2]
+ call near ptr _close
+ pop cx
+ ;
+ ; LoadFile (filename,*spot);
+ ;
+ push word ptr [di]
+ xor ax,ax
+ push ax
+ push si
+ call near ptr _LoadFile
+ add sp,6
+ ;
+ ; }
+ ;
+ jmp short @13@98
+@13@74:
+ ;
+ ; else
+ ; {
+ ; strcpy (error,"BloadinMM: Can't find file ");
+ ;
+ mov ax,offset DGROUP:s@+446
+ push ax
+ lea ax,word ptr [bp-86]
+ push ax
+ call near ptr _strcpy
+ pop cx
+ pop cx
+ ;
+ ; strcat (error,filename);
+ ;
+ push si
+ lea ax,word ptr [bp-86]
+ push ax
+ call near ptr _strcat
+ pop cx
+ pop cx
+ ;
+ ; Quit (error);
+ ;
+ lea ax,word ptr [bp-86]
+ push ax
+ call near ptr _Quit
+ pop cx
+@13@98:
+ ;
+ ; }
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_BloadinMM endp
+ ;
+ ; void BloadinRLEMM (char *filename,memptr *spot)
+ ;
+ assume cs:_TEXT
+_BloadinRLEMM proc near
+ push bp
+ mov bp,sp
+ sub sp,6
+ push si
+ mov si,word ptr [bp+6]
+ ;
+ ; {
+ ; long length;
+ ; memptr org;
+ ;
+ ; BloadinMM (filename,&org);
+ ;
+ lea ax,word ptr [bp-6]
+ push ax
+ push word ptr [bp+4]
+ call near ptr _BloadinMM
+ pop cx
+ pop cx
+ ;
+ ; length = *(long _seg *)org; // rleb compressed length
+ ;
+ mov es,word ptr [bp-6]
+ mov ax,word ptr es:[2]
+ mov dx,word ptr es:[0]
+ mov word ptr [bp-2],ax
+ mov word ptr [bp-4],dx
+ ;
+ ; MMGetPtr (spot,length);
+ ;
+ push word ptr [bp-2]
+ push word ptr [bp-4]
+ push si
+ call near ptr _MMGetPtr
+ add sp,6
+ ;
+ ; RLEBExpand ((unsigned char far *)org,(unsigned char far *)*spot);
+ ;
+ push word ptr [si]
+ xor ax,ax
+ push ax
+ push word ptr [bp-6]
+ xor ax,ax
+ push ax
+ call near ptr _RLEBExpand
+ add sp,8
+ ;
+ ; MMFreePtr (&org);
+ ;
+ lea ax,word ptr [bp-6]
+ push ax
+ call near ptr _MMFreePtr
+ pop cx
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_BloadinRLEMM endp
+ ;
+ ; void BloadinHUFFMM (char *filename,memptr *spot)
+ ;
+ assume cs:_TEXT
+_BloadinHUFFMM proc near
+ push bp
+ mov bp,sp
+ sub sp,6
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ mov si,word ptr [bp+6]
+ ;
+ ; {
+ ; long length;
+ ; memptr org;
+ ;
+ ; if (useegamem)
+ ;
+ cmp word ptr DGROUP:_useegamem,0
+ je short @15@74
+ ;
+ ; {
+ ; org = (memptr)(0xa000+(linewidth*200)/16);
+ ;
+ mov ax,word ptr DGROUP:_linewidth
+ mov dx,200
+ imul dx
+ mov cl,4
+ shr ax,cl
+ add ax,40960
+ mov word ptr [bp-6],ax
+ ;
+ ; LoadFile (filename,MK_FP(org,0));
+ ;
+ xor ax,ax
+ push word ptr [bp-6]
+ push ax
+ push di
+ call near ptr _LoadFile
+ add sp,6
+ ;
+ ; }
+ ;
+ jmp short @15@98
+@15@74:
+ ;
+ ; else
+ ; BloadinMM (filename,&org);
+ ;
+ lea ax,word ptr [bp-6]
+ push ax
+ push di
+ call near ptr _BloadinMM
+ pop cx
+ pop cx
+@15@98:
+ ;
+ ;
+ ; length = *(((long _seg *)org)+1); // huff compressed length
+ ;
+ mov es,word ptr [bp-6]
+ mov ax,word ptr es:[6]
+ mov dx,word ptr es:[4]
+ mov word ptr [bp-2],ax
+ mov word ptr [bp-4],dx
+ ;
+ ; MMGetPtr (spot,length);
+ ;
+ push word ptr [bp-2]
+ push word ptr [bp-4]
+ push si
+ call near ptr _MMGetPtr
+ add sp,6
+ ;
+ ; HuffExpandFile ((unsigned char far *)org,(unsigned char far *)*spot);
+ ;
+ xor ax,ax
+ push word ptr [si]
+ push ax
+ xor ax,ax
+ push word ptr [bp-6]
+ push ax
+ call near ptr _HuffExpandFile
+ add sp,8
+ ;
+ ;
+ ; if (!useegamem)
+ ;
+ cmp word ptr DGROUP:_useegamem,0
+ jne short @15@146
+ ;
+ ; MMFreePtr (&org);
+ ;
+ lea ax,word ptr [bp-6]
+ push ax
+ call near ptr _MMFreePtr
+ pop cx
+@15@146:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_BloadinHUFFMM endp
+ ;
+ ; long Verify(char *filename)
+ ;
+ assume cs:_TEXT
+_Verify proc near
+ push bp
+ mov bp,sp
+ sub sp,4
+ push si
+ ;
+ ; {
+ ; int handle;
+ ; long size;
+ ;
+ ; if ((handle=open(filename,O_BINARY))==-1) return 0;
+ ;
+ mov ax,32768
+ push ax
+ push word ptr [bp+4]
+ call near ptr _open
+ pop cx
+ pop cx
+ mov si,ax
+ cmp ax,65535
+ jne short @16@74
+ xor dx,dx
+ xor ax,ax
+ jmp short @16@98
+@16@74:
+ ;
+ ; size=filelength(handle);
+ ;
+ push si
+ call near ptr _filelength
+ pop cx
+ mov word ptr [bp-2],dx
+ mov word ptr [bp-4],ax
+ ;
+ ; close(handle);
+ ;
+ push si
+ call near ptr _close
+ pop cx
+ ;
+ ; return size;
+ ;
+ mov dx,word ptr [bp-2]
+ mov ax,word ptr [bp-4]
+ jmp short @16@98
+@16@98:
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_Verify endp
+ ;
+ ; void StopDrive (void)
+ ;
+ assume cs:_TEXT
+_StopDrive proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int i;
+ ;
+ ; for (i=0;i<100;i++)
+ ;
+ xor si,si
+ jmp short @17@98
+@17@50:
+ ;
+ ; CallTimer();
+ ;
+ call near ptr _CallTimer
+ inc si
+@17@98:
+ cmp si,100
+ jl short @17@50
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_StopDrive endp
+ ;
+ ; void HuffExpandFile (unsigned char huge *infile,
+ ;
+ assume cs:_TEXT
+_HuffExpandFile proc near
+ push bp
+ mov bp,sp
+ sub sp,8
+ ;
+ ; unsigned char huge *outfile)
+ ; {
+ ; char header[4];
+ ; unsigned tag;
+ ; long length;
+ ;
+ ; header[0] = *infile;
+ ;
+ les bx,dword ptr [bp+4]
+ mov al,byte ptr es:[bx]
+ mov byte ptr [bp-4],al
+ ;
+ ; header[1] = *(infile+1);
+ ;
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,1
+ call near ptr N_PADD@
+ mov bx,ax
+ mov es,dx
+ mov al,byte ptr es:[bx]
+ mov byte ptr [bp-3],al
+ ;
+ ; header[2] = *(infile+2);
+ ;
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,2
+ call near ptr N_PADD@
+ mov bx,ax
+ mov es,dx
+ mov al,byte ptr es:[bx]
+ mov byte ptr [bp-2],al
+ ;
+ ; header[3] = *(infile+3);
+ ;
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,3
+ call near ptr N_PADD@
+ mov bx,ax
+ mov es,dx
+ mov al,byte ptr es:[bx]
+ mov byte ptr [bp-1],al
+ ;
+ ; if (strncmp (header,"HUFF",4))
+ ;
+ mov ax,4
+ push ax
+ mov ax,offset DGROUP:s@+474
+ push ax
+ lea ax,word ptr [bp-4]
+ push ax
+ call near ptr _strncmp
+ add sp,6
+ or ax,ax
+ je short @18@74
+ ;
+ ; Quit ("Tried to expand a file that isn't HUFF!");
+ ;
+ mov ax,offset DGROUP:s@+479
+ push ax
+ call near ptr _Quit
+ pop cx
+@18@74:
+ ;
+ ;
+ ; length = *(long huge *)(infile+4);
+ ;
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,4
+ call near ptr N_PADD@
+ mov bx,ax
+ mov es,dx
+ mov ax,word ptr es:[bx+2]
+ mov dx,word ptr es:[bx]
+ mov word ptr [bp-6],ax
+ mov word ptr [bp-8],dx
+ ;
+ ;
+ ; movedata(FP_SEG(infile+8),FP_OFF(infile+8),_DS,(unsigned)&nodearray,1020);
+ ;
+ mov ax,1020
+ push ax
+ mov ax,offset DGROUP:_nodearray
+ push ax
+ push ds
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,8
+ call near ptr N_PADD@
+ push ax
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,8
+ call near ptr N_PADD@
+ push dx
+ call near ptr _movedata
+ add sp,10
+ ;
+ ; OptimizeNodes (nodearray);
+ ;
+ mov ax,offset DGROUP:_nodearray
+ push ax
+ call near ptr _OptimizeNodes
+ pop cx
+ ;
+ ; HuffExpand (infile+1028,outfile,length,nodearray);
+ ;
+ mov ax,offset DGROUP:_nodearray
+ push ax
+ push word ptr [bp-6]
+ push word ptr [bp-8]
+ push word ptr [bp+10]
+ push word ptr [bp+8]
+ mov dx,word ptr [bp+6]
+ mov ax,word ptr [bp+4]
+ xor cx,cx
+ mov bx,1028
+ call near ptr N_PADD@
+ push dx
+ push ax
+ call near ptr _HuffExpand
+ add sp,14
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_HuffExpandFile endp
+ ;
+ ; void OptimizeNodes (huffnode *table)
+ ;
+ assume cs:_TEXT
+_OptimizeNodes proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ ;
+ ; {
+ ; huffnode *node;
+ ; int i;
+ ;
+ ; node = table;
+ ;
+ mov si,di
+ ;
+ ;
+ ; for (i=0;i<255;i++)
+ ;
+ xor bx,bx
+ jmp short @19@194
+@19@50:
+ ;
+ ; {
+ ; if (node->bit0 >= 256)
+ ;
+ cmp word ptr [si],256
+ jb short @19@98
+ ;
+ ; node->bit0 = (unsigned)(table+(node->bit0-256));
+ ;
+ mov ax,word ptr [si]
+ sub ax,256
+ shl ax,1
+ shl ax,1
+ mov dx,di
+ add dx,ax
+ mov word ptr [si],dx
+@19@98:
+ ;
+ ; if (node->bit1 >= 256)
+ ;
+ cmp word ptr [si+2],256
+ jb short @19@146
+ ;
+ ; node->bit1 = (unsigned)(table+(node->bit1-256));
+ ;
+ mov ax,word ptr [si+2]
+ sub ax,256
+ shl ax,1
+ shl ax,1
+ mov dx,di
+ add dx,ax
+ mov word ptr [si+2],dx
+@19@146:
+ ;
+ ; node++;
+ ;
+ add si,4
+ inc bx
+@19@194:
+ cmp bx,255
+ jl short @19@50
+ ;
+ ; }
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_OptimizeNodes endp
+ ;
+ ; void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+ ;
+ assume cs:_TEXT
+_HuffExpand proc near
+ push bp
+ mov bp,sp
+ sub sp,10
+ push si
+ push di
+ ;
+ ; long length,huffnode *hufftable)
+ ; {
+ ; unsigned bit,byte,node,code;
+ ; unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+ ; huffnode *nodeon,*headptr;
+ ;
+ ; headptr = hufftable+254; // head node is allways node 254
+ ;
+ mov ax,word ptr [bp+16]
+ add ax,1016
+ mov word ptr [bp-10],ax
+ ;
+ ;
+ ; #if0
+ ; bit = 1;
+ ; byte = *source++;
+ ;
+ ; while (length)
+ ; {
+ ; if (byte&bit)
+ ; code = nodeon->bit1;
+ ; else
+ ; code = nodeon->bit0;
+ ;
+ ; bit<<=1;
+ ; if (bit==256)
+ ; {
+ ; bit=1;
+ ; byte = *source++;
+ ; }
+ ;
+ ; if (code<256)
+ ; {
+ ; *dest++=code;
+ ; nodeon=headptr;
+ ; length--;
+ ; }
+ ; else
+ ; nodeon = (huffnode *)code;
+ ; }
+ ;
+ ; #endif
+ ;
+ ; source++; // normalize
+ ;
+ xor cx,cx
+ mov bx,1
+ mov dx,ss
+ lea ax,word ptr [bp+4]
+ call near ptr N_PADA@
+ ;
+ ; source--;
+ ;
+ xor cx,cx
+ mov bx,1
+ mov dx,ss
+ lea ax,word ptr [bp+4]
+ call near ptr N_PSBA@
+ ;
+ ; dest++;
+ ;
+ xor cx,cx
+ mov bx,1
+ mov dx,ss
+ lea ax,word ptr [bp+8]
+ call near ptr N_PADA@
+ ;
+ ; dest--;
+ ;
+ xor cx,cx
+ mov bx,1
+ mov dx,ss
+ lea ax,word ptr [bp+8]
+ call near ptr N_PSBA@
+ ;
+ ;
+ ; sourceseg = FP_SEG(source);
+ ;
+ mov ax,word ptr [bp+6]
+ mov word ptr [bp-2],ax
+ ;
+ ; sourceoff = FP_OFF(source);
+ ;
+ mov ax,word ptr [bp+4]
+ mov word ptr [bp-4],ax
+ ;
+ ; destseg = FP_SEG(dest);
+ ;
+ mov ax,word ptr [bp+10]
+ mov word ptr [bp-6],ax
+ ;
+ ; destoff = FP_OFF(dest);
+ ;
+ mov ax,word ptr [bp+8]
+ mov word ptr [bp-8],ax
+ ;
+ ;
+ ; length--;
+ ;
+ sub word ptr [bp+12],1
+ sbb word ptr [bp+14],0
+ ;
+ ; //
+ ; // al = source byte
+ ; // cl = bit in source (1,2,4,8,...)
+ ; // dx = code
+ ; //
+ ; // ds:si source
+ ; // es:di dest
+ ; // ss:bx node pointer
+ ; //
+ ;
+ ; asm mov bx,[headptr]
+ ;
+ mov bx,[[bp-10]]
+ ;
+ ; asm mov cl,1
+ ;
+ mov cl,1
+ ;
+ ;
+ ; asm mov si,[sourceoff]
+ ;
+ mov si,[[bp-4]]
+ ;
+ ; asm mov di,[destoff]
+ ;
+ mov di,[[bp-8]]
+ ;
+ ; asm mov es,[destseg]
+ ;
+ mov es,[[bp-6]]
+ ;
+ ; asm mov ds,[sourceseg]
+ ;
+ mov ds,[[bp-2]]
+ ;
+ ;
+ ; asm lodsb // load first byte
+ ;
+ lodsb
+@20@218:
+ ;
+ ;
+ ; expand:
+ ; asm test al,cl // bit set?
+ ;
+ test al,cl
+ ;
+ ; asm jnz bit1
+ ;
+ jne short @20@314
+ ;
+ ; asm mov dx,[ss:bx] // take bit0 path from node
+ ;
+ mov dx,[ss:bx]
+ ;
+ ; asm jmp gotcode
+ ;
+ jmp short @20@338
+@20@314:
+ ;
+ ; bit1:
+ ; asm mov dx,[ss:bx+2] // take bit1 path
+ ;
+ mov dx,[ss:bx+2]
+@20@338:
+ ;
+ ;
+ ; gotcode:
+ ; asm shl cl,1 // advance to next bit position
+ ;
+ shl cl,1
+ ;
+ ; asm jnc sourceup
+ ;
+ jnc short @20@578
+ ;
+ ; asm lodsb
+ ;
+ lodsb
+ ;
+ ; asm cmp si,0x10 // normalize ds:si
+ ;
+ cmp si,010H
+ ;
+ ; asm jb sinorm
+ ;
+ jb short @20@554
+ ;
+ ; asm mov cx,ds
+ ;
+ mov cx,ds
+ ;
+ ; asm inc cx
+ ;
+ inc cx
+ ;
+ ; asm mov ds,cx
+ ;
+ mov ds,cx
+ ;
+ ; asm xor si,si
+ ;
+ xor si,si
+@20@554:
+ ;
+ ; sinorm:
+ ; asm mov cl,1 // back to first bit
+ ;
+ mov cl,1
+@20@578:
+ ;
+ ;
+ ; sourceup:
+ ; asm or dh,dh // if dx<256 its a byte, else move node
+ ;
+ or dh,dh
+ ;
+ ; asm jz storebyte
+ ;
+ je short @20@674
+ ;
+ ; asm mov bx,dx // next node = (huffnode *)code
+ ;
+ mov bx,dx
+ ;
+ ; asm jmp expand
+ ;
+ jmp short @20@218
+@20@674:
+ ;
+ ;
+ ; storebyte:
+ ; asm mov [es:di],dl
+ ;
+ mov [es:di],dl
+ ;
+ ; asm inc di // write a decopmpressed byte out
+ ;
+ inc di
+ ;
+ ; asm mov bx,[headptr] // back to the head node for next bit
+ ;
+ mov bx,[[bp-10]]
+ ;
+ ;
+ ; asm cmp di,0x10 // normalize es:di
+ ;
+ cmp di,010H
+ ;
+ ; asm jb dinorm
+ ;
+ jb short @20@890
+ ;
+ ; asm mov dx,es
+ ;
+ mov dx,es
+ ;
+ ; asm inc dx
+ ;
+ inc dx
+ ;
+ ; asm mov es,dx
+ ;
+ mov es,dx
+ ;
+ ; asm xor di,di
+ ;
+ xor di,di
+@20@890:
+ ;
+ ; dinorm:
+ ;
+ ; asm sub [WORD PTR ss:length],1
+ ;
+ sub [WORD PTR ss:[bp+12]],1
+ ;
+ ; asm jnc expand
+ ;
+ jnc short @20@218
+ ;
+ ; asm dec [WORD PTR ss:length+2]
+ ;
+ dec [WORD PTR ss:[bp+12]+2]
+ ;
+ ; asm jns expand // when length = ffff ffff, done
+ ;
+ jns short @20@218
+ ;
+ ;
+ ; asm mov ax,ss
+ ;
+ mov ax,ss
+ ;
+ ; asm mov ds,ax
+ ;
+ mov ds,ax
+ ;
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_HuffExpand endp
+ ;
+ ; void RLEWExpand (unsigned far *source, unsigned far *dest)
+ ;
+ assume cs:_TEXT
+_RLEWExpand proc near
+ push bp
+ mov bp,sp
+ sub sp,10
+ push si
+ push di
+ ;
+ ; {
+ ; long length;
+ ; unsigned value,count,i;
+ ; unsigned far *start,far *end;
+ ;
+ ; length = *(long far *)source;
+ ;
+ les bx,dword ptr [bp+4]
+ mov ax,word ptr es:[bx+2]
+ mov dx,word ptr es:[bx]
+ mov word ptr [bp-2],ax
+ mov word ptr [bp-4],dx
+ ;
+ ; end = dest + (length)/2;
+ ;
+ xor ax,ax
+ mov dx,2
+ push ax
+ push dx
+ push word ptr [bp-2]
+ push word ptr [bp-4]
+ call near ptr N_LDIV@
+ shl ax,1
+ mov dx,word ptr [bp+10]
+ mov bx,word ptr [bp+8]
+ add bx,ax
+ mov word ptr [bp-8],dx
+ mov word ptr [bp-10],bx
+ ;
+ ;
+ ; source+=2; // skip length words
+ ;
+ add word ptr [bp+4],4
+@21@50:
+ ;
+ ; //
+ ; // expand it
+ ; //
+ ; do
+ ; {
+ ; value = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov si,word ptr es:[bx]
+ add word ptr [bp+4],2
+ ;
+ ; if (value != RLETAG)
+ ;
+ cmp si,65278
+ je short @21@98
+ ;
+ ; //
+ ; // uncompressed
+ ; //
+ ; *dest++=value;
+ ;
+ les bx,dword ptr [bp+8]
+ mov word ptr es:[bx],si
+ add word ptr [bp+8],2
+ jmp short @21@242
+@21@98:
+ ;
+ ; else
+ ; {
+ ; //
+ ; // compressed string
+ ; //
+ ; count = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov ax,word ptr es:[bx]
+ mov word ptr [bp-6],ax
+ add word ptr [bp+4],2
+ ;
+ ; value = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov si,word ptr es:[bx]
+ add word ptr [bp+4],2
+ ;
+ ; if (dest+count>end)
+ ;
+ mov ax,word ptr [bp-6]
+ shl ax,1
+ mov dx,word ptr [bp+8]
+ add dx,ax
+ cmp dx,word ptr [bp-10]
+ jbe short @21@146
+ ;
+ ; Quit("RLEWExpand error!");
+ ;
+ mov ax,offset DGROUP:s@+519
+ push ax
+ call near ptr _Quit
+ pop cx
+@21@146:
+ ;
+ ;
+ ; for (i=1;i<=count;i++)
+ ;
+ mov di,1
+ jmp short @21@218
+@21@170:
+ ;
+ ; *dest++ = value;
+ ;
+ les bx,dword ptr [bp+8]
+ mov word ptr es:[bx],si
+ add word ptr [bp+8],2
+ inc di
+@21@218:
+ cmp di,word ptr [bp-6]
+ jbe short @21@170
+@21@242:
+ ;
+ ; }
+ ; } while (dest<end);
+ ;
+ mov ax,word ptr [bp+8]
+ cmp ax,word ptr [bp-10]
+ jb short @21@50
+ ;
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_RLEWExpand endp
+ ;
+ ; void RLEBExpand (unsigned char far *source, unsigned char far *dest)
+ ;
+ assume cs:_TEXT
+_RLEBExpand proc near
+ push bp
+ mov bp,sp
+ sub sp,10
+ push si
+ ;
+ ; {
+ ; long length;
+ ; unsigned char value,count;
+ ; unsigned i;
+ ; unsigned char far *start,far *end;
+ ;
+ ; length = *(long far *)source;
+ ;
+ les bx,dword ptr [bp+4]
+ mov ax,word ptr es:[bx+2]
+ mov dx,word ptr es:[bx]
+ mov word ptr [bp-2],ax
+ mov word ptr [bp-4],dx
+ ;
+ ; end = dest + (length);
+ ;
+ mov ax,word ptr [bp+10]
+ mov dx,word ptr [bp+8]
+ add dx,word ptr [bp-4]
+ mov word ptr [bp-8],ax
+ mov word ptr [bp-10],dx
+ ;
+ ;
+ ; source+=4; // skip length words
+ ;
+ add word ptr [bp+4],4
+@22@50:
+ ;
+ ; //
+ ; // expand it
+ ; //
+ ; do
+ ; {
+ ; value = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov al,byte ptr es:[bx]
+ mov cl,al
+ inc word ptr [bp+4]
+ ;
+ ; if (value != RLEBTAG)
+ ;
+ cmp cl,254
+ je short @22@98
+ ;
+ ; //
+ ; // uncompressed
+ ; //
+ ; *dest++=value;
+ ;
+ les bx,dword ptr [bp+8]
+ mov al,cl
+ mov byte ptr es:[bx],al
+ inc word ptr [bp+8]
+ jmp short @22@194
+@22@98:
+ ;
+ ; else
+ ; {
+ ; //
+ ; // compressed string
+ ; //
+ ; count = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov al,byte ptr es:[bx]
+ mov byte ptr [bp-5],al
+ inc word ptr [bp+4]
+ ;
+ ; value = *source++;
+ ;
+ les bx,dword ptr [bp+4]
+ mov al,byte ptr es:[bx]
+ mov cl,al
+ inc word ptr [bp+4]
+ ;
+ ; for (i=1;i<=count;i++)
+ ;
+ mov si,1
+ jmp short @22@170
+@22@122:
+ ;
+ ; *dest++ = value;
+ ;
+ les bx,dword ptr [bp+8]
+ mov al,cl
+ mov byte ptr es:[bx],al
+ inc word ptr [bp+8]
+ inc si
+@22@170:
+ mov al,byte ptr [bp-5]
+ mov ah,0
+ cmp ax,si
+ jae short @22@122
+@22@194:
+ ;
+ ; }
+ ; } while (dest<end);
+ ;
+ mov ax,word ptr [bp+8]
+ cmp ax,word ptr [bp-10]
+ jb short @22@50
+ ;
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_RLEBExpand endp
+ ;
+ ; void LoadPage(char *filename,unsigned dest)
+ ;
+ assume cs:_TEXT
+_LoadPage proc near
+ push bp
+ mov bp,sp
+ sub sp,8
+ push si
+ push di
+ ;
+ ; {
+ ; memptr src;
+ ; unsigned from,source;
+ ; long length;
+ ; int i,j,width,height,xx,x,y,plane;
+ ;
+ ; //
+ ; // load the pic in
+ ; //
+ ;
+ ; BloadinHUFFMM (filename,&src);
+ ;
+ lea ax,word ptr [bp-2]
+ push ax
+ push word ptr [bp+4]
+ call near ptr _BloadinHUFFMM
+ pop cx
+ pop cx
+ ;
+ ; StopDrive();
+ ;
+ call near ptr _StopDrive
+ ;
+ ;
+ ; from = 8;
+ ;
+ mov word ptr [bp-4],8
+ ;
+ ; width = *((int far *)src+2);
+ ;
+ mov es,word ptr [bp-2]
+ mov ax,word ptr es:[4]
+ mov word ptr [bp-6],ax
+ ;
+ ; height = *((int far *)src+3);
+ ;
+ mov es,word ptr [bp-2]
+ mov ax,word ptr es:[6]
+ mov word ptr [bp-8],ax
+ ;
+ ; for (i=0;i<4;i++)
+ ;
+ xor di,di
+ jmp short @23@194
+@23@50:
+ ;
+ ; {
+ ; EGAplane(i);
+ ;
+ push di
+ call near ptr _EGAplane
+ pop cx
+ ;
+ ; for (j=0;j<height;j++)
+ ;
+ xor si,si
+ jmp short @23@122
+@23@74:
+ ;
+ ; movedata((unsigned)src,from+width*j,0xa000,dest+linewidth*j,width);
+ ;
+ push word ptr [bp-6]
+ mov ax,word ptr DGROUP:_linewidth
+ imul si
+ mov dx,word ptr [bp+6]
+ add dx,ax
+ push dx
+ mov ax,40960
+ push ax
+ mov ax,word ptr [bp-6]
+ imul si
+ mov dx,word ptr [bp-4]
+ add dx,ax
+ push dx
+ push word ptr [bp-2]
+ call near ptr _movedata
+ add sp,10
+ inc si
+@23@122:
+ cmp si,word ptr [bp-8]
+ jl short @23@74
+ ;
+ ; from += width*height;
+ ;
+ mov ax,word ptr [bp-6]
+ imul word ptr [bp-8]
+ add word ptr [bp-4],ax
+ inc di
+@23@194:
+ cmp di,4
+ jl short @23@50
+ ;
+ ; }
+ ; MMFreePtr (&src);
+ ;
+ lea ax,word ptr [bp-2]
+ push ax
+ call near ptr _MMFreePtr
+ pop cx
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_LoadPage endp
+ ;
+ ; void GenYlookup (void)
+ ;
+ assume cs:_TEXT
+_GenYlookup proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int i;
+ ;
+ ; for (i=0;i<256;i++)
+ ;
+ xor si,si
+ jmp short @24@98
+@24@50:
+ ;
+ ; ylookup[i]=i*linewidth;
+ ;
+ mov ax,si
+ imul word ptr DGROUP:_linewidth
+ mov bx,si
+ shl bx,1
+ mov word ptr DGROUP:_ylookup[bx],ax
+ inc si
+@24@98:
+ cmp si,256
+ jl short @24@50
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_GenYlookup endp
+ ;
+ ; void SetScreenMode (grtype mode)
+ ;
+ assume cs:_TEXT
+_SetScreenMode proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; switch (mode)
+ ;
+ mov ax,word ptr [bp+4]
+ or ax,ax
+ je short @25@146
+ cmp ax,1
+ je short @25@170
+ cmp ax,2
+ je short @25@194
+ jmp short @25@218
+@25@146:
+ ;
+ ; {
+ ; case text: _AX = 3;
+ ;
+ mov ax,3
+ ;
+ ; geninterrupt (0x10);
+ ;
+ int 16
+ ;
+ ; screenseg=0xb000;
+ ;
+ mov word ptr DGROUP:_screenseg,45056
+ ;
+ ; break;
+ ;
+ jmp short @25@218
+@25@170:
+ ;
+ ; case CGAgr: _AX = 4;
+ ;
+ mov ax,4
+ ;
+ ; geninterrupt (0x10);
+ ;
+ int 16
+ ;
+ ; screenseg=0xb800;
+ ;
+ mov word ptr DGROUP:_screenseg,47104
+ ;
+ ; break;
+ ;
+ jmp short @25@218
+@25@194:
+ ;
+ ; case EGAgr: _AX = 0xd;
+ ;
+ mov ax,13
+ ;
+ ; geninterrupt (0x10);
+ ;
+ int 16
+ ;
+ ; screenseg=0xa000;
+ ;
+ mov word ptr DGROUP:_screenseg,40960
+ ;
+ ; break;
+ ;
+ jmp short @25@218
+@25@218:
+ ;
+ ; #ifdef VGAGAME
+ ; case VGAgr:{
+ ; char extern VGAPAL; // deluxepaint vga pallet .OBJ file
+ ; void far *vgapal = &VGAPAL;
+ ; SetCool256 (); // custom 256 color mode
+ ; screenseg=0xa000;
+ ; _ES = FP_SEG(vgapal);
+ ; _DX = FP_OFF(vgapal);
+ ; _BX = 0;
+ ; _CX = 0x100;
+ ; _AX = 0x1012;
+ ; geninterrupt(0x10); // set the deluxepaint pallet
+ ;
+ ; break;
+ ; #endif
+ ; }
+ ; }
+ ;
+ pop bp
+ ret
+_SetScreenMode endp
+ ;
+ ; void EGASplitScreen (int linenum)
+ ;
+ assume cs:_TEXT
+_EGASplitScreen proc near
+ push bp
+ mov bp,sp
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; if (videocard==VGAcard)
+ ;
+ cmp word ptr DGROUP:_videocard,5
+ jne short @26@74
+ ;
+ ; linenum=linenum*2-1;
+ ;
+ mov ax,si
+ shl ax,1
+ dec ax
+ mov si,ax
+@26@74:
+ ;
+ ; outportb (CRTC_INDEX,CRTC_LINECOMPARE);
+ ;
+ mov dx,980
+ mov al,24
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX+1,linenum % 256);
+ ;
+ mov ax,si
+ mov bx,256
+ cwd
+ idiv bx
+ push dx
+ mov dx,981
+ pop ax
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX,CRTC_OVERFLOW);
+ ;
+ mov dx,980
+ mov al,7
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX+1, 1+16*(linenum/256));
+ ;
+ mov ax,si
+ mov bx,256
+ cwd
+ idiv bx
+ mov cl,4
+ shl al,cl
+ inc al
+ mov dx,981
+ out dx,al
+ ;
+ ; if (videocard==VGAcard)
+ ;
+ cmp word ptr DGROUP:_videocard,5
+ jne short @26@122
+ ;
+ ; {
+ ; outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
+ ;
+ mov dx,980
+ mov al,9
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
+ ;
+ mov dx,981
+ in al,dx
+ and al,191
+ mov dx,981
+ out dx,al
+@26@122:
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_EGASplitScreen endp
+ ;
+ ; void EGAVirtualScreen (int width) // sets screen width
+ ;
+ assume cs:_TEXT
+_EGAVirtualScreen proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; outportb(CRTC_INDEX,CRTC_OFFSET);
+ ;
+ mov dx,980
+ mov al,19
+ out dx,al
+ ;
+ ; outportb(CRTC_INDEX+1,width/2); // wide virtual screen
+ ;
+ mov ax,word ptr [bp+4]
+ mov bx,2
+ cwd
+ idiv bx
+ mov dx,981
+ out dx,al
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_EGAVirtualScreen endp
+ ;
+ ; void ColorBorder (int color)
+ ;
+ assume cs:_TEXT
+_ColorBorder proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; _AH=0x10;
+ ;
+ mov ah,16
+ ;
+ ; _AL=1;
+ ;
+ mov al,1
+ ;
+ ; _BH=color;
+ ;
+ mov bh,byte ptr [bp+4]
+ ;
+ ; geninterrupt (0x10); // color the border
+ ;
+ int 16
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_ColorBorder endp
+ ;
+ ; void CRTCstart (unsigned start)
+ ;
+ assume cs:_TEXT
+_CRTCstart proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; outportb (CRTC_INDEX,CRTC_STARTLOW);
+ ;
+ mov dx,980
+ mov al,13
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX+1,start % 256);
+ ;
+ mov al,byte ptr [bp+4]
+ and al,255
+ mov dx,981
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX,CRTC_STARTHIGH);
+ ;
+ mov dx,980
+ mov al,12
+ out dx,al
+ ;
+ ; outportb (CRTC_INDEX+1,start / 256);
+ ;
+ mov ax,word ptr [bp+4]
+ mov cl,8
+ shr ax,cl
+ mov dx,981
+ out dx,al
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_CRTCstart endp
+_TEXT ends
+_DATA segment word public 'DATA'
+_colors label byte
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 1
+ db 2
+ db 3
+ db 4
+ db 5
+ db 6
+ db 7
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 0
+ db 24
+ db 25
+ db 26
+ db 27
+ db 28
+ db 29
+ db 30
+ db 31
+ db 0
+ db 0
+ db 1
+ db 2
+ db 3
+ db 4
+ db 5
+ db 6
+ db 7
+ db 24
+ db 25
+ db 26
+ db 27
+ db 28
+ db 29
+ db 30
+ db 31
+ db 0
+ db 0
+ db 1
+ db 2
+ db 3
+ db 4
+ db 5
+ db 6
+ db 7
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 0
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 31
+ db 17 dup (0)
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void SetDefaultColors(void)
+ ;
+ assume cs:_TEXT
+_SetDefaultColors proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; colors[3][16] = bordercolor;
+ ;
+ mov al,byte ptr DGROUP:_bordercolor
+ mov byte ptr DGROUP:_colors+67,al
+ ;
+ ; _ES=FP_SEG(&colors[3]);
+ ;
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[3]);
+ ;
+ mov dx,offset DGROUP:_colors+51
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_SetDefaultColors endp
+ ;
+ ; void FadeIn(void)
+ ;
+ assume cs:_TEXT
+_FadeIn proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int i;
+ ;
+ ; for (i=0;i<4;i++)
+ ;
+ xor si,si
+ jmp short @31@98
+@31@50:
+ ;
+ ; {
+ ; colors[i][16] = bordercolor;
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ mov dl,byte ptr DGROUP:_bordercolor
+ mov bx,ax
+ mov byte ptr DGROUP:_colors[bx+16],dl
+ ;
+ ; _ES=FP_SEG(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov dx,ax
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; WaitVBL(6);
+ ;
+ mov ax,6
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ inc si
+@31@98:
+ cmp si,4
+ jl short @31@50
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_FadeIn endp
+ ;
+ ; void FadeUp(void)
+ ;
+ assume cs:_TEXT
+_FadeUp proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int i;
+ ;
+ ; for (i=3;i<7;i++)
+ ;
+ mov si,3
+ jmp short @32@98
+@32@50:
+ ;
+ ; {
+ ; colors[i][16] = bordercolor;
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ mov dl,byte ptr DGROUP:_bordercolor
+ mov bx,ax
+ mov byte ptr DGROUP:_colors[bx+16],dl
+ ;
+ ; _ES=FP_SEG(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov dx,ax
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; WaitVBL(6);
+ ;
+ mov ax,6
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ inc si
+@32@98:
+ cmp si,7
+ jl short @32@50
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_FadeUp endp
+ ;
+ ; void FadeDown(void)
+ ;
+ assume cs:_TEXT
+_FadeDown proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int i;
+ ;
+ ; for (i=6;i>2;i--)
+ ;
+ mov si,6
+ jmp short @33@98
+@33@50:
+ ;
+ ; {
+ ; colors[i][16] = bordercolor;
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ mov dl,byte ptr DGROUP:_bordercolor
+ mov bx,ax
+ mov byte ptr DGROUP:_colors[bx+16],dl
+ ;
+ ; _ES=FP_SEG(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov dx,ax
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; WaitVBL(6);
+ ;
+ mov ax,6
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ dec si
+@33@98:
+ cmp si,2
+ jg short @33@50
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_FadeDown endp
+ ;
+ ; void SetNormalPalette(void)
+ ;
+ assume cs:_TEXT
+_SetNormalPalette proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; int i;
+ ;
+ ; colors[3][16] = bordercolor;
+ ;
+ mov al,byte ptr DGROUP:_bordercolor
+ mov byte ptr DGROUP:_colors+67,al
+ ;
+ ; _ES=FP_SEG(&colors[3]);
+ ;
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[3]);
+ ;
+ mov dx,offset DGROUP:_colors+51
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_SetNormalPalette endp
+ ;
+ ; void FadeOut(void)
+ ;
+ assume cs:_TEXT
+_FadeOut proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ;
+ ; int i;
+ ;
+ ; for (i=3;i>=0;i--)
+ ;
+ mov si,3
+ jmp short @35@98
+@35@50:
+ ;
+ ; {
+ ; colors[i][16] = bordercolor;
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ mov dl,byte ptr DGROUP:_bordercolor
+ mov bx,ax
+ mov byte ptr DGROUP:_colors[bx+16],dl
+ ;
+ ; _ES=FP_SEG(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov ax,ds
+ mov es,ax
+ ;
+ ; _DX=FP_OFF(&colors[i]);
+ ;
+ mov ax,si
+ mov dx,17
+ imul dx
+ add ax,offset DGROUP:_colors
+ mov dx,ax
+ ;
+ ; _AX=0x1002;
+ ;
+ mov ax,4098
+ ;
+ ; geninterrupt(0x10);
+ ;
+ int 16
+ ;
+ ; WaitVBL(6);
+ ;
+ mov ax,6
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ dec si
+@35@98:
+ or si,si
+ jge short @35@50
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_FadeOut endp
+ ;
+ ; void SetLineWidth (int width)
+ ;
+ assume cs:_TEXT
+_SetLineWidth proc near
+ push bp
+ mov bp,sp
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; EGAVirtualScreen(width);
+ ;
+ push si
+ call near ptr _EGAVirtualScreen
+ pop cx
+ ;
+ ; linewidth = width;
+ ;
+ mov word ptr DGROUP:_linewidth,si
+ ;
+ ; GenYlookup();
+ ;
+ call near ptr _GenYlookup
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_SetLineWidth endp
+_TEXT ends
+_DATA segment word public 'DATA'
+_screencenterx label word
+ db 20
+ db 0
+_screencentery label word
+ db 11
+ db 0
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void DrawWindow (int xl, int yl, int xh, int yh)
+ ;
+ assume cs:_TEXT
+_DrawWindow proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ ;
+ ; {
+ ; int x,y;
+ ; win_xl=xl;
+ ;
+ mov word ptr DGROUP:_win_xl,di
+ ;
+ ; pxl = xl*8+8;
+ ;
+ mov ax,di
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ add ax,8
+ mov word ptr DGROUP:_pxl,ax
+ ;
+ ; win_yl=yl;
+ ;
+ mov ax,word ptr [bp+6]
+ mov word ptr DGROUP:_win_yl,ax
+ ;
+ ; win_xh=xh;
+ ;
+ mov ax,word ptr [bp+8]
+ mov word ptr DGROUP:_win_xh,ax
+ ;
+ ; pxh = xh*8;
+ ;
+ mov ax,word ptr [bp+8]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ mov word ptr DGROUP:_pxh,ax
+ ;
+ ; win_yh=yh; // so the window can be erased
+ ;
+ mov ax,word ptr [bp+10]
+ mov word ptr DGROUP:_win_yh,ax
+ ;
+ ;
+ ; DRAWCHAR (xl,yl,1);
+ ;
+ mov ax,1
+ push ax
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push di
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; for (x=xl+1;x<xh;x++)
+ ;
+ mov ax,di
+ inc ax
+ mov si,ax
+ jmp short @37@98
+@37@50:
+ ;
+ ; DRAWCHAR (x,yl,2);
+ ;
+ mov ax,2
+ push ax
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@37@98:
+ cmp si,word ptr [bp+8]
+ jl short @37@50
+ ;
+ ; DRAWCHAR (xh,yl,3);
+ ;
+ mov ax,3
+ push ax
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; for (y=yl+1;y<yh;y++)
+ ;
+ mov ax,word ptr [bp+6]
+ inc ax
+ mov word ptr [bp-2],ax
+ jmp short @37@290
+@37@146:
+ ;
+ ; {
+ ; DRAWCHAR (xl,y,4);
+ ;
+ mov ax,4
+ push ax
+ mov ax,word ptr [bp-2]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push di
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; for (x=xl+1;x<xh;x++)
+ ;
+ mov ax,di
+ inc ax
+ mov si,ax
+ jmp short @37@218
+@37@170:
+ ;
+ ; DRAWCHAR (x,y,9);
+ ;
+ mov ax,9
+ push ax
+ mov ax,word ptr [bp-2]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@37@218:
+ cmp si,word ptr [bp+8]
+ jl short @37@170
+ ;
+ ; DRAWCHAR (xh,y,5);
+ ;
+ mov ax,5
+ push ax
+ mov ax,word ptr [bp-2]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ inc word ptr [bp-2]
+@37@290:
+ mov ax,word ptr [bp-2]
+ cmp ax,word ptr [bp+10]
+ jl short @37@146
+ ;
+ ; }
+ ; DRAWCHAR (xl,yh,6);
+ ;
+ mov ax,6
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push di
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; for (x=xl+1;x<xh;x++)
+ ;
+ mov ax,di
+ inc ax
+ mov si,ax
+ jmp short @37@386
+@37@338:
+ ;
+ ; DRAWCHAR (x,yh,7);
+ ;
+ mov ax,7
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@37@386:
+ cmp si,word ptr [bp+8]
+ jl short @37@338
+ ;
+ ; DRAWCHAR (xh,yh,8);
+ ;
+ mov ax,8
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ;
+ ; sx = leftedge = xl+1;
+ ;
+ mov ax,di
+ inc ax
+ mov word ptr DGROUP:_leftedge,ax
+ mov word ptr DGROUP:_sx,ax
+ ;
+ ; sy = yl+1;
+ ;
+ mov ax,word ptr [bp+6]
+ inc ax
+ mov word ptr DGROUP:_sy,ax
+ ;
+ ; px=sx*8;
+ ;
+ mov ax,word ptr DGROUP:_sx
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; py=pyl=sy*8;
+ ;
+ mov ax,word ptr DGROUP:_sy
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ mov word ptr DGROUP:_pyl,ax
+ mov word ptr DGROUP:_py,ax
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_DrawWindow endp
+ ;
+ ; void CenterWindow (int width, int height)
+ ;
+ assume cs:_TEXT
+_CenterWindow proc near
+ push bp
+ mov bp,sp
+ sub sp,4
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ mov di,word ptr [bp+6]
+ ;
+ ; {
+ ; int xl = screencenterx-width/2;
+ ;
+ mov ax,si
+ mov bx,2
+ cwd
+ idiv bx
+ mov dx,word ptr DGROUP:_screencenterx
+ sub dx,ax
+ mov word ptr [bp-2],dx
+ ;
+ ; int yl = screencentery-height/2;
+ ;
+ mov ax,di
+ mov bx,2
+ cwd
+ idiv bx
+ mov dx,word ptr DGROUP:_screencentery
+ sub dx,ax
+ mov word ptr [bp-4],dx
+ ;
+ ;
+ ; DrawWindow (xl,yl,xl+width+1,yl+height+1);
+ ;
+ mov ax,word ptr [bp-4]
+ add ax,di
+ inc ax
+ push ax
+ mov ax,word ptr [bp-2]
+ add ax,si
+ inc ax
+ push ax
+ push word ptr [bp-4]
+ push word ptr [bp-2]
+ call near ptr _DrawWindow
+ add sp,8
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_CenterWindow endp
+ ;
+ ; void CharBar (int xl, int yl, int xh, int yh, int ch)
+ ;
+ assume cs:_TEXT
+_CharBar proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ ;
+ ; {
+ ; int x,y;
+ ;
+ ; for (y=yl;y<=yh;y++)
+ ;
+ mov di,word ptr [bp+6]
+ jmp short @39@170
+@39@50:
+ ;
+ ; for (x=xl;x<=xh;x++)
+ ;
+ mov si,word ptr [bp+4]
+ jmp short @39@122
+@39@74:
+ ;
+ ; DRAWCHAR (x,y,ch);
+ ;
+ push word ptr [bp+12]
+ mov ax,di
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@39@122:
+ cmp si,word ptr [bp+8]
+ jle short @39@74
+ inc di
+@39@170:
+ cmp di,word ptr [bp+10]
+ jle short @39@50
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_CharBar endp
+ ;
+ ; void ExpWin (int width, int height)
+ ;
+ assume cs:_TEXT
+_ExpWin proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ mov si,word ptr [bp+6]
+ ;
+ ; {
+ ; if (width > 2)
+ ;
+ cmp di,2
+ jle short @40@146
+ ;
+ ; {
+ ; if (height >2)
+ ;
+ cmp si,2
+ jle short @40@98
+ ;
+ ; ExpWin (width-2,height-2);
+ ;
+ mov ax,si
+ add ax,65534
+ push ax
+ mov ax,di
+ add ax,65534
+ push ax
+ call near ptr _ExpWin
+ pop cx
+ pop cx
+ jmp short @40@122
+@40@98:
+ ;
+ ; else
+ ; ExpWinH (width-2,height);
+ ;
+ push si
+ mov ax,di
+ add ax,65534
+ push ax
+ call near ptr _ExpWinH
+ pop cx
+ pop cx
+@40@122:
+ ;
+ ; }
+ ;
+ jmp short @40@194
+@40@146:
+ ;
+ ; else
+ ; if (height >2)
+ ;
+ cmp si,2
+ jle short @40@194
+ ;
+ ; ExpWinV (width,height-2);
+ ;
+ mov ax,si
+ add ax,65534
+ push ax
+ push di
+ call near ptr _ExpWinV
+ pop cx
+ pop cx
+@40@194:
+ ;
+ ;
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; CenterWindow (width,height);
+ ;
+ push si
+ push di
+ call near ptr _CenterWindow
+ pop cx
+ pop cx
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_ExpWin endp
+ ;
+ ; void ExpWinH (int width, int height)
+ ;
+ assume cs:_TEXT
+_ExpWinH proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ mov di,word ptr [bp+6]
+ ;
+ ; {
+ ; if (width > 2)
+ ;
+ cmp si,2
+ jle short @41@74
+ ;
+ ; ExpWinH (width-2,height);
+ ;
+ push di
+ mov ax,si
+ add ax,65534
+ push ax
+ call near ptr _ExpWinH
+ pop cx
+ pop cx
+@41@74:
+ ;
+ ;
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; CenterWindow (width,height);
+ ;
+ push di
+ push si
+ call near ptr _CenterWindow
+ pop cx
+ pop cx
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_ExpWinH endp
+ ;
+ ; void ExpWinV (int width, int height)
+ ;
+ assume cs:_TEXT
+_ExpWinV proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ mov si,word ptr [bp+6]
+ ;
+ ; {
+ ; if (height >2)
+ ;
+ cmp si,2
+ jle short @42@74
+ ;
+ ; ExpWinV (width,height-2);
+ ;
+ mov ax,si
+ add ax,65534
+ push ax
+ push di
+ call near ptr _ExpWinV
+ pop cx
+ pop cx
+@42@74:
+ ;
+ ;
+ ; WaitVBL (1);
+ ;
+ mov ax,1
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; CenterWindow (width,height);
+ ;
+ push si
+ push di
+ call near ptr _CenterWindow
+ pop cx
+ pop cx
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_ExpWinV endp
+ ;
+ ; void DrawFrame(int x1,int y1,int x2,int y2,int type)
+ ;
+ assume cs:_TEXT
+_DrawFrame proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov di,word ptr [bp+12]
+ ;
+ ; {
+ ; int loop;
+ ;
+ ; type=type*22+1;
+ ;
+ mov ax,di
+ mov dx,22
+ imul dx
+ inc ax
+ mov di,ax
+ ;
+ ;
+ ; for (loop=x1+1;loop<x2;loop++)
+ ;
+ mov ax,word ptr [bp+4]
+ inc ax
+ mov si,ax
+ jmp short @43@98
+@43@50:
+ ;
+ ; {
+ ; DRAWCHAR(loop,y1,type+1);
+ ;
+ mov ax,di
+ inc ax
+ push ax
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; DRAWCHAR(loop,y2,type+6);
+ ;
+ mov ax,di
+ add ax,6
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push si
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@43@98:
+ cmp si,word ptr [bp+8]
+ jl short @43@50
+ ;
+ ; }
+ ; for (loop=y1+1;loop<y2;loop++)
+ ;
+ mov ax,word ptr [bp+6]
+ inc ax
+ mov si,ax
+ jmp short @43@194
+@43@146:
+ ;
+ ; {
+ ; DRAWCHAR(x1,loop,type+3);
+ ;
+ mov ax,di
+ add ax,3
+ push ax
+ mov ax,si
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+4]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; DRAWCHAR(x2,loop,type+4);
+ ;
+ mov ax,di
+ add ax,4
+ push ax
+ mov ax,si
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ inc si
+@43@194:
+ cmp si,word ptr [bp+10]
+ jl short @43@146
+ ;
+ ; }
+ ;
+ ; DRAWCHAR(x1,y1,type);
+ ;
+ push di
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+4]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; DRAWCHAR(x2,y1,type+2);
+ ;
+ mov ax,di
+ inc ax
+ inc ax
+ push ax
+ mov ax,word ptr [bp+6]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; DRAWCHAR(x2,y2,type+7);
+ ;
+ mov ax,di
+ add ax,7
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+8]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; DRAWCHAR(x1,y2,type+5);
+ ;
+ mov ax,di
+ add ax,5
+ push ax
+ mov ax,word ptr [bp+10]
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr [bp+4]
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_DrawFrame endp
+ ;
+ ; int Get (void)
+ ;
+ assume cs:_TEXT
+_Get proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ ;
+ ; {
+ ; int cycle,key;
+ ;
+ ; ClearKeys();
+ ;
+ call near ptr _ClearKeys
+@44@50:
+ ;
+ ; do
+ ; {
+ ; cycle = 9;
+ ;
+ mov si,9
+ jmp short @44@98
+@44@74:
+ ;
+ ; while (!(key = NoBiosKey(1)) && cycle<13)
+ ; {
+ ; DRAWCHAR (sx,sy,cycle++);
+ ;
+ mov ax,si
+ inc si
+ push ax
+ mov ax,word ptr DGROUP:_sy
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; WaitVBL (5);
+ ;
+ mov ax,5
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+@44@98:
+ mov ax,1
+ push ax
+ call near ptr _NoBiosKey
+ pop cx
+ mov word ptr [bp-2],ax
+ or ax,ax
+ jne short @44@146
+ cmp si,13
+ jl short @44@74
+@44@146:
+ ;
+ ; }
+ ; } while (key == 0);
+ ;
+ cmp word ptr [bp-2],0
+ je short @44@50
+ ;
+ ; DRAWCHAR (sx,sy,' ');
+ ;
+ mov ax,32
+ push ax
+ mov ax,word ptr DGROUP:_sy
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ push word ptr DGROUP:_sx
+ call near ptr _DrawChar
+ add sp,6
+ ;
+ ; return NoBiosKey(0); // take it out of the buffer
+ ;
+ xor ax,ax
+ push ax
+ call near ptr _NoBiosKey
+ pop cx
+ jmp short @44@194
+@44@194:
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_Get endp
+ ;
+ ; void Print (const char *str)
+ ;
+ assume cs:_TEXT
+_Print proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ mov si,word ptr [bp+4]
+ jmp short @45@170
+@45@50:
+ ;
+ ; {
+ ; unsigned char ch;
+ ;
+ ; while ((ch=*str++) != 0)
+ ; if (ch == '\n')
+ ;
+ cmp byte ptr [bp-1],10
+ jne short @45@98
+ ;
+ ; {
+ ; sy++;
+ ;
+ inc word ptr DGROUP:_sy
+ ;
+ ; sx=leftedge;
+ ;
+ mov ax,word ptr DGROUP:_leftedge
+ mov word ptr DGROUP:_sx,ax
+ ;
+ ; }
+ ;
+ jmp short @45@170
+@45@98:
+ ;
+ ; else if (ch == '\r')
+ ;
+ cmp byte ptr [bp-1],13
+ jne short @45@146
+ ;
+ ; sx=leftedge;
+ ;
+ mov ax,word ptr DGROUP:_leftedge
+ mov word ptr DGROUP:_sx,ax
+ jmp short @45@170
+@45@146:
+ ;
+ ; else
+ ; DRAWCHAR (sx++,sy,ch);
+ ;
+ mov al,byte ptr [bp-1]
+ mov ah,0
+ push ax
+ mov ax,word ptr DGROUP:_sy
+ shl ax,1
+ shl ax,1
+ shl ax,1
+ push ax
+ mov ax,word ptr DGROUP:_sx
+ inc word ptr DGROUP:_sx
+ push ax
+ call near ptr _DrawChar
+ add sp,6
+@45@170:
+ mov bx,si
+ inc si
+ mov al,byte ptr [bx]
+ mov byte ptr [bp-1],al
+ or al,al
+ jne short @45@50
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_Print endp
+ ;
+ ; void Printxy(int x,int y,char *string)
+ ;
+ assume cs:_TEXT
+_Printxy proc near
+ push bp
+ mov bp,sp
+ sub sp,4
+ ;
+ ; {
+ ; int osx,osy;
+ ;
+ ; osx=sx;
+ ;
+ mov ax,word ptr DGROUP:_sx
+ mov word ptr [bp-2],ax
+ ;
+ ; osy=sy;
+ ;
+ mov ax,word ptr DGROUP:_sy
+ mov word ptr [bp-4],ax
+ ;
+ ; sx=x;
+ ;
+ mov ax,word ptr [bp+4]
+ mov word ptr DGROUP:_sx,ax
+ ;
+ ; sy=y;
+ ;
+ mov ax,word ptr [bp+6]
+ mov word ptr DGROUP:_sy,ax
+ ;
+ ; Print(string);
+ ;
+ push word ptr [bp+8]
+ call near ptr _Print
+ pop cx
+ ;
+ ; sx=osx;
+ ;
+ mov ax,word ptr [bp-2]
+ mov word ptr DGROUP:_sx,ax
+ ;
+ ; sy=osy;
+ ;
+ mov ax,word ptr [bp-4]
+ mov word ptr DGROUP:_sy,ax
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_Printxy endp
+ ;
+ ; void PrintInt (int val)
+ ;
+ assume cs:_TEXT
+_PrintInt proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; itoa(val,str,10);
+ ;
+ mov ax,10
+ push ax
+ mov ax,offset DGROUP:_str
+ push ax
+ push word ptr [bp+4]
+ call near ptr _itoa
+ add sp,6
+ ;
+ ; Print (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _Print
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PrintInt endp
+ ;
+ ; void PrintLong (long val)
+ ;
+ assume cs:_TEXT
+_PrintLong proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; ltoa(val,str,10);
+ ;
+ mov ax,10
+ push ax
+ mov ax,offset DGROUP:_str
+ push ax
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ call near ptr _ltoa
+ add sp,8
+ ;
+ ; Print (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _Print
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PrintLong endp
+_TEXT ends
+_DATA segment word public 'DATA'
+ db 48
+ db 49
+ db 50
+ db 51
+ db 52
+ db 53
+ db 54
+ db 55
+ db 56
+ db 57
+ db 65
+ db 66
+ db 67
+ db 68
+ db 69
+ db 70
+ db 2 dup (0)
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void PrintHexB(unsigned char value)
+ ;
+ assume cs:_TEXT
+_PrintHexB proc near
+ push bp
+ mov bp,sp
+ sub sp,20
+ push ss
+ lea ax,word ptr [bp-20]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+251
+ push ax
+ mov cx,16
+ call near ptr N_SCOPY@
+ push ss
+ lea ax,word ptr [bp-4]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+267
+ push ax
+ mov cx,2
+ call near ptr N_SCOPY@
+ ;
+ ; {
+ ; int loop;
+ ; char hexstr[16]="0123456789ABCDEF",str[2]="";
+ ;
+ ; for (loop=0;loop<2;loop++)
+ ;
+ mov word ptr [bp-2],0
+ jmp short @49@98
+@49@50:
+ ;
+ ; {
+ ; str[0]=hexstr[(value>>(1-loop)*4)&15];
+ ;
+ mov al,byte ptr [bp+4]
+ mov ah,0
+ mov dl,1
+ sub dl,byte ptr [bp-2]
+ shl dl,1
+ shl dl,1
+ mov cl,dl
+ sar ax,cl
+ and ax,15
+ lea dx,word ptr [bp-20]
+ add ax,dx
+ mov bx,ax
+ mov al,byte ptr [bx]
+ mov byte ptr [bp-4],al
+ ;
+ ; Print(str);
+ ;
+ lea ax,word ptr [bp-4]
+ push ax
+ call near ptr _Print
+ pop cx
+ inc word ptr [bp-2]
+@49@98:
+ cmp word ptr [bp-2],2
+ jl short @49@50
+ ;
+ ; }
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_PrintHexB endp
+ ;
+ ; void PrintHex(unsigned value)
+ ;
+ assume cs:_TEXT
+_PrintHex proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; Print("$");
+ ;
+ mov ax,offset DGROUP:s@+537
+ push ax
+ call near ptr _Print
+ pop cx
+ ;
+ ; PrintHexB(value>>8);
+ ;
+ mov ax,word ptr [bp+4]
+ mov cl,8
+ shr ax,cl
+ push ax
+ call near ptr _PrintHexB
+ pop cx
+ ;
+ ; PrintHexB(value&0xff);
+ ;
+ mov al,byte ptr [bp+4]
+ and al,255
+ push ax
+ call near ptr _PrintHexB
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PrintHex endp
+ ;
+ ; void PrintBin(unsigned value)
+ ;
+ assume cs:_TEXT
+_PrintBin proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ ;
+ ; {
+ ; int loop;
+ ;
+ ; Print("%");
+ ;
+ mov ax,offset DGROUP:s@+539
+ push ax
+ call near ptr _Print
+ pop cx
+ ;
+ ; for (loop=0;loop<16;loop++)
+ ;
+ mov word ptr [bp-2],0
+ jmp short @51@146
+@51@50:
+ ;
+ ; if ((value>>15-loop)&1) Print("1"); else Print("0");
+ ;
+ mov cl,15
+ sub cl,byte ptr [bp-2]
+ mov ax,word ptr [bp+4]
+ shr ax,cl
+ test ax,1
+ je short @51@98
+ mov ax,offset DGROUP:s@+541
+ push ax
+ call near ptr _Print
+ pop cx
+ jmp short @51@122
+@51@98:
+ mov ax,offset DGROUP:s@+543
+ push ax
+ call near ptr _Print
+ pop cx
+@51@122:
+ inc word ptr [bp-2]
+@51@146:
+ cmp word ptr [bp-2],16
+ jl short @51@50
+ ;
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_PrintBin endp
+ ;
+ ; void PrintC(char *string)
+ ;
+ assume cs:_TEXT
+_PrintC proc near
+ push bp
+ mov bp,sp
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; sx=1+screencenterx-(strlen(string)/2);
+ ;
+ push si
+ call near ptr _strlen
+ pop cx
+ mov bx,2
+ cwd
+ idiv bx
+ mov dx,word ptr DGROUP:_screencenterx
+ inc dx
+ sub dx,ax
+ mov word ptr DGROUP:_sx,dx
+ ;
+ ; Print(string);
+ ;
+ push si
+ call near ptr _Print
+ pop cx
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_PrintC endp
+_TEXT ends
+_DATA segment word public 'DATA'
+ db 18 dup (0)
+ db 48
+ db 49
+ db 50
+ db 51
+ db 52
+ db 53
+ db 54
+ db 55
+ db 56
+ db 57
+ db 65
+ db 66
+ db 67
+ db 68
+ db 69
+ db 70
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; unsigned InputInt(void)
+ ;
+ assume cs:_TEXT
+_InputInt proc near
+ push bp
+ mov bp,sp
+ sub sp,40
+ push si
+ push di
+ push ss
+ lea ax,word ptr [bp-24]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+269
+ push ax
+ mov cx,18
+ call near ptr N_SCOPY@
+ push ss
+ lea ax,word ptr [bp-40]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+287
+ push ax
+ mov cx,16
+ call near ptr N_SCOPY@
+ ;
+ ; {
+ ; char string[18]="",digit,hexstr[16]="0123456789ABCDEF";
+ ; unsigned value,loop,loop1;
+ ;
+ ; Input(string,17);
+ ;
+ mov ax,17
+ push ax
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _Input
+ pop cx
+ pop cx
+ ;
+ ; if (string[0]=='$')
+ ;
+ cmp byte ptr [bp-24],36
+ jne short @53@314
+ ;
+ ; {
+ ; int digits;
+ ;
+ ; digits=strlen(string)-2;
+ ;
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _strlen
+ pop cx
+ add ax,65534
+ mov word ptr [bp-6],ax
+ ;
+ ; if (digits<0) return 0;
+ ;
+ cmp word ptr [bp-6],0
+ jge short @53@98
+ xor ax,ax
+ jmp @53@626
+@53@98:
+ ;
+ ;
+ ; for (value=0,loop1=0;loop1<=digits;loop1++)
+ ;
+ xor si,si
+ mov word ptr [bp-4],0
+ jmp short @53@266
+@53@122:
+ ;
+ ; {
+ ; digit=toupper(string[loop1+1]);
+ ;
+ mov bx,word ptr [bp-4]
+ inc bx
+ lea ax,word ptr [bp-24]
+ add bx,ax
+ mov al,byte ptr [bx]
+ cbw
+ push ax
+ call near ptr _toupper
+ pop cx
+ mov byte ptr [bp-1],al
+ ;
+ ; for (loop=0;loop<16;loop++)
+ ;
+ xor di,di
+ jmp short @53@218
+@53@146:
+ ;
+ ; if (digit==hexstr[loop])
+ ;
+ mov al,byte ptr [bp+di-40]
+ cmp al,byte ptr [bp-1]
+ jne short @53@194
+ ;
+ ; {
+ ; value|=(loop<<(digits-loop1)*4);
+ ;
+ mov al,byte ptr [bp-6]
+ sub al,byte ptr [bp-4]
+ shl al,1
+ shl al,1
+ mov dx,di
+ mov cl,al
+ shl dx,cl
+ or si,dx
+ ;
+ ; break;
+ ;
+ jmp short @53@242
+@53@194:
+ inc di
+@53@218:
+ cmp di,16
+ jb short @53@146
+@53@242:
+ inc word ptr [bp-4]
+@53@266:
+ mov ax,word ptr [bp-4]
+ cmp ax,word ptr [bp-6]
+ jbe short @53@122
+ ;
+ ; }
+ ; }
+ ; }
+ ;
+ jmp short @53@602
+@53@314:
+ ;
+ ; else if (string[0]=='%')
+ ;
+ cmp byte ptr [bp-24],37
+ jne short @53@578
+ ;
+ ; {
+ ; int digits;
+ ;
+ ; digits=strlen(string)-2;
+ ;
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _strlen
+ pop cx
+ add ax,65534
+ mov word ptr [bp-6],ax
+ ;
+ ; if (digits<0) return 0;
+ ;
+ cmp word ptr [bp-6],0
+ jge short @53@386
+ xor ax,ax
+ jmp short @53@626
+@53@386:
+ ;
+ ;
+ ; for (value=0,loop1=0;loop1<=digits;loop1++)
+ ;
+ xor si,si
+ mov word ptr [bp-4],0
+ jmp short @53@530
+@53@410:
+ ;
+ ; {
+ ; if (string[loop1+1]<'0' || string[loop1+1]>'1') return 0;
+ ;
+ mov bx,word ptr [bp-4]
+ inc bx
+ lea ax,word ptr [bp-24]
+ add bx,ax
+ cmp byte ptr [bx],48
+ jl short @53@458
+ mov bx,word ptr [bp-4]
+ inc bx
+ lea ax,word ptr [bp-24]
+ add bx,ax
+ cmp byte ptr [bx],49
+ jle short @53@482
+@53@458:
+ xor ax,ax
+ jmp short @53@626
+@53@482:
+ ;
+ ; value|=(string[loop1+1]-'0')<<(digits-loop1);
+ ;
+ mov bx,word ptr [bp-4]
+ inc bx
+ lea ax,word ptr [bp-24]
+ add bx,ax
+ mov al,byte ptr [bx]
+ cbw
+ add ax,65488
+ mov cl,byte ptr [bp-6]
+ sub cl,byte ptr [bp-4]
+ shl ax,cl
+ or si,ax
+ inc word ptr [bp-4]
+@53@530:
+ mov ax,word ptr [bp-4]
+ cmp ax,word ptr [bp-6]
+ jbe short @53@410
+ ;
+ ; }
+ ; }
+ ;
+ jmp short @53@602
+@53@578:
+ ;
+ ; else value=atoi(string);
+ ;
+ lea ax,word ptr [bp-24]
+ push ax
+ call near ptr _atol
+ pop cx
+ mov si,ax
+@53@602:
+ ;
+ ; return value;
+ ;
+ mov ax,si
+ jmp short @53@626
+@53@626:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_InputInt endp
+ ;
+ ; int Input(char *string,int max)
+ ;
+ assume cs:_TEXT
+_Input proc near
+ push bp
+ mov bp,sp
+ sub sp,182
+ push si
+ push di
+ ;
+ ; {
+ ; char key;
+ ; int count=0,loop;
+ ;
+ xor si,si
+ ;
+ ; int pxt[90];
+ ;
+ ; pxt[0]=px;
+ ;
+ mov ax,word ptr DGROUP:_px
+ mov word ptr [bp-182],ax
+@54@50:
+ ;
+ ;
+ ; do {
+ ; key=toupper(PGet()&0xff);
+ ;
+ call near ptr _PGet
+ and ax,255
+ push ax
+ call near ptr _toupper
+ pop cx
+ mov byte ptr [bp-1],al
+ ;
+ ; if ((key==127 || key==8)&&count>0)
+ ;
+ cmp byte ptr [bp-1],127
+ je short @54@98
+ cmp byte ptr [bp-1],8
+ jne short @54@146
+@54@98:
+ or si,si
+ jle short @54@146
+ ;
+ ; {
+ ; count--;
+ ;
+ dec si
+ ;
+ ; px=pxt[count];
+ ;
+ mov bx,si
+ shl bx,1
+ lea ax,word ptr [bp-182]
+ add bx,ax
+ mov ax,word ptr [bx]
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; DrawPchar(string[count]);
+ ;
+ mov bx,word ptr [bp+4]
+ mov al,byte ptr [bx+si]
+ cbw
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; px=pxt[count];
+ ;
+ mov bx,si
+ shl bx,1
+ lea ax,word ptr [bp-182]
+ add bx,ax
+ mov ax,word ptr [bx]
+ mov word ptr DGROUP:_px,ax
+@54@146:
+ ;
+ ; }
+ ;
+ ; if (key>=' ' && key<='z' && count<max)
+ ;
+ cmp byte ptr [bp-1],32
+ jl short @54@242
+ cmp byte ptr [bp-1],122
+ jg short @54@242
+ cmp si,word ptr [bp+6]
+ jge short @54@242
+ ;
+ ; {
+ ; *(string+count++)=key;
+ ;
+ mov bx,word ptr [bp+4]
+ mov al,byte ptr [bp-1]
+ mov byte ptr [bx+si],al
+ inc si
+ ;
+ ; DrawPchar(key);
+ ;
+ mov al,byte ptr [bp-1]
+ cbw
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; pxt[count]=px;
+ ;
+ mov bx,si
+ shl bx,1
+ lea ax,word ptr [bp-182]
+ add bx,ax
+ mov ax,word ptr DGROUP:_px
+ mov word ptr [bx],ax
+@54@242:
+ ;
+ ; }
+ ;
+ ; } while (key!=27 && key!=13);
+ ;
+ cmp byte ptr [bp-1],27
+ je short @54@290
+ cmp byte ptr [bp-1],13
+ je @@83
+ jmp @54@50
+@@83:
+@54@290:
+ ;
+ ;
+ ; for (loop=count;loop<max;loop++) *(string+loop)=0;
+ ;
+ mov di,si
+ jmp short @54@362
+@54@314:
+ mov bx,word ptr [bp+4]
+ mov byte ptr [bx+di],0
+ inc di
+@54@362:
+ cmp di,word ptr [bp+6]
+ jl short @54@314
+ ;
+ ;
+ ; if (key==13) return 1;
+ ;
+ cmp byte ptr [bp-1],13
+ jne short @54@434
+ mov ax,1
+ jmp short @54@458
+@54@434:
+ ;
+ ; return 0;
+ ;
+ xor ax,ax
+ jmp short @54@458
+@54@458:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_Input endp
+ ;
+ ; void PPrint (const char *str)
+ ;
+ assume cs:_TEXT
+_PPrint proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ mov si,word ptr [bp+4]
+ jmp short @55@170
+@55@50:
+ ;
+ ; {
+ ; unsigned char ch;
+ ;
+ ; while ((ch=*str++) != 0)
+ ; if (ch == '\n')
+ ;
+ cmp byte ptr [bp-1],10
+ jne short @55@98
+ ;
+ ; {
+ ; py+=10;
+ ;
+ add word ptr DGROUP:_py,10
+ ;
+ ; px=pxl;
+ ;
+ mov ax,word ptr DGROUP:_pxl
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; }
+ ;
+ jmp short @55@170
+@55@98:
+ ;
+ ; else if (ch == '')
+ ;
+ cmp byte ptr [bp-1],127
+ jne short @55@146
+ ;
+ ; fontcolor=(*str++)-'A'; // set color A-P
+ ;
+ mov al,byte ptr [si]
+ cbw
+ add ax,65471
+ mov word ptr DGROUP:_fontcolor,ax
+ inc si
+ jmp short @55@170
+@55@146:
+ ;
+ ; else
+ ; DrawPchar (ch);
+ ;
+ mov al,byte ptr [bp-1]
+ mov ah,0
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+@55@170:
+ mov bx,si
+ inc si
+ mov al,byte ptr [bx]
+ mov byte ptr [bp-1],al
+ or al,al
+ jne short @55@50
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_PPrint endp
+ ;
+ ; int PGet (void)
+ ;
+ assume cs:_TEXT
+_PGet proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int oldx;
+ ;
+ ; oldx=px;
+ ;
+ mov si,word ptr DGROUP:_px
+ ;
+ ;
+ ; ClearKeys();
+ ;
+ call near ptr _ClearKeys
+ jmp short @56@122
+@56@50:
+ ;
+ ; while (!(NoBiosKey(1)&0xff))
+ ; {
+ ; DrawPchar ('_');
+ ;
+ mov ax,95
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; WaitVBL (5);
+ ;
+ mov ax,5
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+ ;
+ ; px=oldx;
+ ;
+ mov word ptr DGROUP:_px,si
+ ;
+ ; DrawPchar ('_');
+ ;
+ mov ax,95
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; px=oldx;
+ ;
+ mov word ptr DGROUP:_px,si
+ ;
+ ; if (NoBiosKey(1)&0xff) // slight response improver
+ ;
+ mov ax,1
+ push ax
+ call near ptr _NoBiosKey
+ pop cx
+ test ax,255
+ je short @56@98
+ ;
+ ; break;
+ ;
+ jmp short @56@146
+@56@98:
+ ;
+ ; WaitVBL (5);
+ ;
+ mov ax,5
+ push ax
+ call near ptr _WaitVBL
+ pop cx
+@56@122:
+ mov ax,1
+ push ax
+ call near ptr _NoBiosKey
+ pop cx
+ test ax,255
+ je short @56@50
+@56@146:
+ ;
+ ; }
+ ; px=oldx;
+ ;
+ mov word ptr DGROUP:_px,si
+ ;
+ ; return NoBiosKey(0); // take it out of the buffer
+ ;
+ xor ax,ax
+ push ax
+ call near ptr _NoBiosKey
+ pop cx
+ jmp short @56@170
+@56@170:
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_PGet endp
+ ;
+ ; int PSize (const char *str)
+ ;
+ assume cs:_TEXT
+_PSize proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; int length=0;
+ ;
+ xor di,di
+ jmp short @57@122
+@57@50:
+ ;
+ ; unsigned char ch;
+ ;
+ ; while ((ch=*str++) != 0)
+ ; {
+ ; if (ch=='') // skip color changes
+ ;
+ cmp dl,127
+ jne short @57@98
+ ;
+ ; {
+ ; str++;
+ ;
+ inc si
+ ;
+ ; continue;
+ ;
+ jmp short @57@122
+@57@98:
+ ;
+ ; }
+ ; length += ((fontstruct _seg *)fontseg)->width[ch];
+ ;
+ mov es,word ptr DGROUP:_fontseg
+ mov al,dl
+ mov ah,0
+ mov bx,ax
+ mov al,byte ptr es:[bx+514]
+ cbw
+ add di,ax
+@57@122:
+ mov bx,si
+ inc si
+ mov al,byte ptr [bx]
+ mov dl,al
+ or al,al
+ jne short @57@50
+ ;
+ ; }
+ ;
+ ; return length;
+ ;
+ mov ax,di
+ jmp short @57@170
+@57@170:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_PSize endp
+ ;
+ ; void CPPrint (const char *str)
+ ;
+ assume cs:_TEXT
+_CPPrint proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; {
+ ; int width;
+ ;
+ ; width = PSize(str);
+ ;
+ push si
+ call near ptr _PSize
+ pop cx
+ mov word ptr [bp-2],ax
+ ;
+ ; px=pxl+(int)(pxh-pxl-width)/2;
+ ;
+ mov ax,word ptr DGROUP:_pxh
+ sub ax,word ptr DGROUP:_pxl
+ sub ax,word ptr [bp-2]
+ mov bx,2
+ cwd
+ idiv bx
+ mov dx,word ptr DGROUP:_pxl
+ add dx,ax
+ mov word ptr DGROUP:_px,dx
+ ;
+ ; PPrint (str);
+ ;
+ push si
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_CPPrint endp
+ ;
+ ; void PWrap (const char *str)
+ ;
+ assume cs:_TEXT
+_PWrap proc near
+ push bp
+ mov bp,sp
+ dec sp
+ dec sp
+ push si
+ mov si,word ptr [bp+4]
+ jmp short @59@170
+@59@50:
+ ;
+ ; {
+ ; unsigned char ch;
+ ;
+ ; while ((ch=*str++) != 0)
+ ; if (ch == '\n')
+ ;
+ cmp byte ptr [bp-1],10
+ jne short @59@98
+ ;
+ ; {
+ ; py+=10;
+ ;
+ add word ptr DGROUP:_py,10
+ ;
+ ; px=leftedge;
+ ;
+ mov ax,word ptr DGROUP:_leftedge
+ mov word ptr DGROUP:_px,ax
+ ;
+ ; }
+ ;
+ jmp short @59@170
+@59@98:
+ ;
+ ; else if (ch == '\r')
+ ;
+ cmp byte ptr [bp-1],13
+ jne short @59@146
+ ;
+ ; px=leftedge;
+ ;
+ mov ax,word ptr DGROUP:_leftedge
+ mov word ptr DGROUP:_px,ax
+ jmp short @59@170
+@59@146:
+ ;
+ ; else
+ ; DrawPchar (ch);
+ ;
+ mov al,byte ptr [bp-1]
+ mov ah,0
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+@59@170:
+ mov bx,si
+ inc si
+ mov al,byte ptr [bx]
+ mov byte ptr [bp-1],al
+ or al,al
+ jne short @59@50
+ ;
+ ; }
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_PWrap endp
+ ;
+ ; void PPrintInt (int val)
+ ;
+ assume cs:_TEXT
+_PPrintInt proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; itoa(val,str,10);
+ ;
+ mov ax,10
+ push ax
+ mov ax,offset DGROUP:_str
+ push ax
+ push word ptr [bp+4]
+ call near ptr _itoa
+ add sp,6
+ ;
+ ; PPrint (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PPrintInt endp
+ ;
+ ; void PPrintUnsigned (unsigned val)
+ ;
+ assume cs:_TEXT
+_PPrintUnsigned proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; ltoa((long)val,str,10);
+ ;
+ mov ax,10
+ push ax
+ mov ax,offset DGROUP:_str
+ push ax
+ xor ax,ax
+ push ax
+ push word ptr [bp+4]
+ call near ptr _ltoa
+ add sp,8
+ ;
+ ; PPrint (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PPrintUnsigned endp
+ ;
+ ; void PPrintLong (long val)
+ ;
+ assume cs:_TEXT
+_PPrintLong proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; ltoa((long)val,str,10);
+ ;
+ mov ax,10
+ push ax
+ mov ax,offset DGROUP:_str
+ push ax
+ push word ptr [bp+6]
+ push word ptr [bp+4]
+ call near ptr _ltoa
+ add sp,8
+ ;
+ ; PPrint (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PPrintLong endp
+ ;
+ ; int PInput(char *string,int max)
+ ;
+ assume cs:_TEXT
+_PInput proc near
+ push bp
+ mov bp,sp
+ sub sp,6
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ ;
+ ; {
+ ; char key;
+ ; int count,loop,oldx;
+ ;
+ ; count = strlen(string);
+ ;
+ push di
+ call near ptr _strlen
+ pop cx
+ mov si,ax
+ ;
+ ; PPrint (str);
+ ;
+ mov ax,offset DGROUP:_str
+ push ax
+ call near ptr _PPrint
+ pop cx
+@63@50:
+ ;
+ ;
+ ; do {
+ ; key=toupper(PGet()&0xff);
+ ;
+ call near ptr _PGet
+ and ax,255
+ push ax
+ call near ptr _toupper
+ pop cx
+ mov byte ptr [bp-1],al
+ ;
+ ; if ((key==127 || key==8)&&count>0)
+ ;
+ cmp byte ptr [bp-1],127
+ je short @63@98
+ cmp byte ptr [bp-1],8
+ jne short @63@146
+@63@98:
+ or si,si
+ jle short @63@146
+ ;
+ ; {
+ ; px-= ((fontstruct _seg *)fontseg)->width[ch];
+ ;
+ mov es,word ptr DGROUP:_fontseg
+ mov al,byte ptr DGROUP:_ch
+ cbw
+ mov bx,ax
+ mov al,byte ptr es:[bx+514]
+ cbw
+ sub word ptr DGROUP:_px,ax
+ ;
+ ; oldx=px;
+ ;
+ mov ax,word ptr DGROUP:_px
+ mov word ptr [bp-6],ax
+ ;
+ ; count--;
+ ;
+ dec si
+ ;
+ ; DrawPchar(string[count]);
+ ;
+ mov bx,si
+ mov al,byte ptr [bx+di]
+ cbw
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+ ;
+ ; px=oldx;
+ ;
+ mov ax,word ptr [bp-6]
+ mov word ptr DGROUP:_px,ax
+@63@146:
+ ;
+ ; }
+ ;
+ ; if (key>=' ' && key<='z' && count<max)
+ ;
+ cmp byte ptr [bp-1],32
+ jl short @63@242
+ cmp byte ptr [bp-1],122
+ jg short @63@242
+ cmp si,word ptr [bp+6]
+ jge short @63@242
+ ;
+ ; {
+ ; *(string+count++)=key;
+ ;
+ mov bx,si
+ mov al,byte ptr [bp-1]
+ mov byte ptr [bx+di],al
+ inc si
+ ;
+ ; DrawPchar(key);
+ ;
+ mov al,byte ptr [bp-1]
+ cbw
+ push ax
+ call near ptr _DrawPchar
+ pop cx
+@63@242:
+ ;
+ ; }
+ ;
+ ; } while (key!=27 && key!=13);
+ ;
+ cmp byte ptr [bp-1],27
+ je short @63@290
+ cmp byte ptr [bp-1],13
+ jne short @63@50
+@63@290:
+ ;
+ ;
+ ; for (loop=count;loop<max;loop++)
+ ;
+ mov word ptr [bp-4],si
+ jmp short @63@362
+@63@314:
+ ;
+ ; *(string+loop)=0;
+ ;
+ mov bx,word ptr [bp-4]
+ mov byte ptr [bx+di],0
+ inc word ptr [bp-4]
+@63@362:
+ mov ax,word ptr [bp-4]
+ cmp ax,word ptr [bp+6]
+ jl short @63@314
+ ;
+ ;
+ ; if (key==13)
+ ;
+ cmp byte ptr [bp-1],13
+ jne short @63@434
+ ;
+ ; return 1;
+ ;
+ mov ax,1
+ jmp short @63@458
+@63@434:
+ ;
+ ; return 0;
+ ;
+ xor ax,ax
+ jmp short @63@458
+@63@458:
+ ;
+ ; }
+ ;
+ pop di
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_PInput endp
+_TEXT ends
+_DATA segment word public 'DATA'
+ db 48
+ db 49
+ db 50
+ db 51
+ db 52
+ db 53
+ db 54
+ db 55
+ db 56
+ db 57
+ db 65
+ db 66
+ db 67
+ db 68
+ db 69
+ db 70
+ db 2 dup (0)
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; void PPrintHexB(unsigned char value)
+ ;
+ assume cs:_TEXT
+_PPrintHexB proc near
+ push bp
+ mov bp,sp
+ sub sp,20
+ push ss
+ lea ax,word ptr [bp-20]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+303
+ push ax
+ mov cx,16
+ call near ptr N_SCOPY@
+ push ss
+ lea ax,word ptr [bp-4]
+ push ax
+ push ds
+ mov ax,offset DGROUP:d@+319
+ push ax
+ mov cx,2
+ call near ptr N_SCOPY@
+ ;
+ ; {
+ ; int loop;
+ ; char hexstr[16]="0123456789ABCDEF",str[2]="";
+ ;
+ ; for (loop=0;loop<2;loop++)
+ ;
+ mov word ptr [bp-2],0
+ jmp short @64@98
+@64@50:
+ ;
+ ; {
+ ; str[0]=hexstr[(value>>(1-loop)*4)&15];
+ ;
+ mov al,byte ptr [bp+4]
+ mov ah,0
+ mov dl,1
+ sub dl,byte ptr [bp-2]
+ shl dl,1
+ shl dl,1
+ mov cl,dl
+ sar ax,cl
+ and ax,15
+ lea dx,word ptr [bp-20]
+ add ax,dx
+ mov bx,ax
+ mov al,byte ptr [bx]
+ mov byte ptr [bp-4],al
+ ;
+ ; PPrint(str);
+ ;
+ lea ax,word ptr [bp-4]
+ push ax
+ call near ptr _PPrint
+ pop cx
+ inc word ptr [bp-2]
+@64@98:
+ cmp word ptr [bp-2],2
+ jl short @64@50
+ ;
+ ; }
+ ; }
+ ;
+ mov sp,bp
+ pop bp
+ ret
+_PPrintHexB endp
+ ;
+ ; void PPrintHex(unsigned value)
+ ;
+ assume cs:_TEXT
+_PPrintHex proc near
+ push bp
+ mov bp,sp
+ ;
+ ; {
+ ; PPrint("$");
+ ;
+ mov ax,offset DGROUP:s@+545
+ push ax
+ call near ptr _PPrint
+ pop cx
+ ;
+ ; PPrintHexB(value>>8);
+ ;
+ mov ax,word ptr [bp+4]
+ mov cl,8
+ shr ax,cl
+ push ax
+ call near ptr _PPrintHexB
+ pop cx
+ ;
+ ; PPrintHexB(value&0xff);
+ ;
+ mov al,byte ptr [bp+4]
+ and al,255
+ push ax
+ call near ptr _PPrintHexB
+ pop cx
+ ;
+ ; }
+ ;
+ pop bp
+ ret
+_PPrintHex endp
+ ;
+ ; void LoadCtrls (void)
+ ;
+ assume cs:_TEXT
+_LoadCtrls proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int handle;
+ ;
+ ; if ((handle = open("CTLPANEL."EXTENSION, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1)
+ ;
+ mov ax,384
+ push ax
+ mov ax,32769
+ push ax
+ mov ax,offset DGROUP:s@+547
+ push ax
+ call near ptr _open
+ add sp,6
+ mov si,ax
+ cmp ax,65535
+ jne short @66@74
+ ;
+ ; //
+ ; // set up default control panel settings
+ ; //
+ ; {
+ ; key[0] = 0x48;
+ ;
+ mov byte ptr DGROUP:_key,72
+ ;
+ ; key[1] = 0x49;
+ ;
+ mov byte ptr DGROUP:_key+1,73
+ ;
+ ; key[2] = 0x4d;
+ ;
+ mov byte ptr DGROUP:_key+2,77
+ ;
+ ; key[3] = 0x51;
+ ;
+ mov byte ptr DGROUP:_key+3,81
+ ;
+ ; key[4] = 0x50;
+ ;
+ mov byte ptr DGROUP:_key+4,80
+ ;
+ ; key[5] = 0x4f;
+ ;
+ mov byte ptr DGROUP:_key+5,79
+ ;
+ ; key[6] = 0x4b;
+ ;
+ mov byte ptr DGROUP:_key+6,75
+ ;
+ ; key[7] = 0x47;
+ ;
+ mov byte ptr DGROUP:_key+7,71
+ ;
+ ; keyB1 = 0x1d;
+ ;
+ mov byte ptr DGROUP:_keyB1,29
+ ;
+ ; keyB2 = 0x38;
+ ;
+ mov byte ptr DGROUP:_keyB2,56
+ ;
+ ; }
+ ;
+ jmp short @66@98
+@66@74:
+ ;
+ ; else
+ ; {
+ ; read(handle, &key, sizeof(key));
+ ;
+ mov ax,8
+ push ax
+ mov ax,offset DGROUP:_key
+ push ax
+ push si
+ call near ptr _read
+ add sp,6
+ ;
+ ; read(handle, &keyB1, sizeof(keyB1));
+ ;
+ mov ax,1
+ push ax
+ mov ax,offset DGROUP:_keyB1
+ push ax
+ push si
+ call near ptr _read
+ add sp,6
+ ;
+ ; read(handle, &keyB2, sizeof(keyB2));
+ ;
+ mov ax,1
+ push ax
+ mov ax,offset DGROUP:_keyB2
+ push ax
+ push si
+ call near ptr _read
+ add sp,6
+ ;
+ ; read(handle, &highscore, sizeof(highscore));
+ ;
+ mov ax,4
+ push ax
+ mov ax,offset DGROUP:_highscore
+ push ax
+ push si
+ call near ptr _read
+ add sp,6
+ ;
+ ; close(handle);
+ ;
+ push si
+ call near ptr _close
+ pop cx
+@66@98:
+ ;
+ ; }
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_LoadCtrls endp
+ ;
+ ; void SaveCtrls (void)
+ ;
+ assume cs:_TEXT
+_SaveCtrls proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; {
+ ; int handle;
+ ;
+ ; if ((handle = open("CTLPANEL."EXTENSION, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE)) == -1)
+ ;
+ mov ax,384
+ push ax
+ mov ax,33538
+ push ax
+ mov ax,offset DGROUP:s@+560
+ push ax
+ call near ptr _open
+ add sp,6
+ mov si,ax
+ cmp ax,65535
+ jne short @67@74
+ ;
+ ; return;
+ ;
+ jmp short @67@98
+@67@74:
+ ;
+ ;
+ ; write(handle, &key, sizeof(key));
+ ;
+ mov ax,8
+ push ax
+ mov ax,offset DGROUP:_key
+ push ax
+ push si
+ call near ptr _write
+ add sp,6
+ ;
+ ; write(handle, &keyB1, sizeof(keyB1));
+ ;
+ mov ax,1
+ push ax
+ mov ax,offset DGROUP:_keyB1
+ push ax
+ push si
+ call near ptr _write
+ add sp,6
+ ;
+ ; write(handle, &keyB2, sizeof(keyB2));
+ ;
+ mov ax,1
+ push ax
+ mov ax,offset DGROUP:_keyB2
+ push ax
+ push si
+ call near ptr _write
+ add sp,6
+ ;
+ ; write(handle, &highscore, sizeof(highscore));
+ ;
+ mov ax,4
+ push ax
+ mov ax,offset DGROUP:_highscore
+ push ax
+ push si
+ call near ptr _write
+ add sp,6
+ ;
+ ;
+ ; close(handle);
+ ;
+ push si
+ call near ptr _close
+ pop cx
+@67@98:
+ ;
+ ; }
+ ;
+ pop si
+ pop bp
+ ret
+_SaveCtrls endp
+_TEXT ends
+_BSS segment word public 'BSS'
+_ch label byte
+ db 1 dup (?)
+ db 1 dup (?)
+_mapwidthextra label word
+ db 2 dup (?)
+_score label word
+ db 4 dup (?)
+_JoyXlow label word
+ db 6 dup (?)
+_JoyXhigh label word
+ db 6 dup (?)
+_JoyYlow label word
+ db 6 dup (?)
+_JoyYhigh label word
+ db 6 dup (?)
+_sx label word
+ db 2 dup (?)
+_nodearray label word
+ db 1024 dup (?)
+_keyB1 label byte
+ db 1 dup (?)
+_keyB2 label byte
+ db 1 dup (?)
+_str label byte
+ db 80 dup (?)
+_useegamem label word
+ db 2 dup (?)
+_pxl label word
+ db 2 dup (?)
+_pxh label word
+ db 2 dup (?)
+_key label byte
+ db 8 dup (?)
+_sy label word
+ db 2 dup (?)
+_bordercolor label word
+ db 2 dup (?)
+_charptr label dword
+ db 4 dup (?)
+_level label word
+ db 2 dup (?)
+_pyl label word
+ db 2 dup (?)
+_pyh label word
+ db 2 dup (?)
+_playermode label word
+ db 6 dup (?)
+_needgr label byte
+ db 77 dup (?)
+ db 1 dup (?)
+_maprle label dword
+ db 4 dup (?)
+_spriteptr label dword
+ db 4 dup (?)
+_mapbwide label word
+ db 2 dup (?)
+_mapwwide label word
+ db 2 dup (?)
+_picptr label dword
+ db 4 dup (?)
+_leftedge label word
+ db 2 dup (?)
+_win_xl label word
+ db 2 dup (?)
+_win_xh label word
+ db 2 dup (?)
+_win_yl label word
+ db 2 dup (?)
+_win_yh label word
+ db 2 dup (?)
+_pictable label word
+ db 296 dup (?)
+_tileptr label dword
+ db 4 dup (?)
+_mapplane label dword
+ db 16 dup (?)
+_mapheight label word
+ db 2 dup (?)
+_grmode label word
+ db 2 dup (?)
+_grsegs label word
+ db 154 dup (?)
+_buttonflip label word
+ db 2 dup (?)
+_highscore label word
+ db 4 dup (?)
+_videocard label word
+ db 2 dup (?)
+_levelheader label dword
+ db 4 dup (?)
+ ?debug C E9
+_BSS ends
+_DATA segment word public 'DATA'
+s@ label byte
+ db 'Joystick Configuration'
+ db 10
+ db 0
+ db 'Hold the joystick in the UPPER LEFT'
+ db 10
+ db 0
+ db 'corner and press a button:'
+ db 0
+ db 10
+ db 'Hold the joystick in the LOWER RIGHT'
+ db 10
+ db 0
+ db 'corner and press a button:'
+ db 0
+ db 10
+ db '(F)ire or (A)fterburn with B1 ?'
+ db 0
+ db 'ESC'
+ db 0
+ db 'BKSP'
+ db 0
+ db 'TAB'
+ db 0
+ db 'CTRL'
+ db 0
+ db 'LSHIFT'
+ db 0
+ db 'SPACE'
+ db 0
+ db 'CAPSLK'
+ db 0
+ db 'F'
+ db 0
+ db 'F11'
+ db 0
+ db 'F12'
+ db 0
+ db 'SCRLLK'
+ db 0
+ db 'ENTER'
+ db 0
+ db 'RSHIFT'
+ db 0
+ db 'PRTSC'
+ db 0
+ db 'ALT'
+ db 0
+ db 'HOME'
+ db 0
+ db 'PGUP'
+ db 0
+ db 'END'
+ db 0
+ db 'PGDN'
+ db 0
+ db 'INS'
+ db 0
+ db 'DEL'
+ db 0
+ db 'NUMLK'
+ db 0
+ db 'UP'
+ db 0
+ db 'DOWN'
+ db 0
+ db 'LEFT'
+ db 0
+ db 'RIGHT'
+ db 0
+ db 'Keyboard Configuration'
+ db 0
+ db 10
+ db '1 north'
+ db 0
+ db 10
+ db '2 east'
+ db 0
+ db 10
+ db '3 south'
+ db 0
+ db 10
+ db '4 west'
+ db 0
+ db 10
+ db '5 button1'
+ db 0
+ db 10
+ db '6 button2'
+ db 0
+ db 10
+ db 'Modify which action:'
+ db 0
+ db ':'
+ db 0
+ db ':'
+ db 0
+ db ':'
+ db 0
+ db 10
+ db 'Press the new key:'
+ db 0
+ db ':'
+ db 0
+ db 'BloadinMM: Can'
+ db 39
+ db 't find file '
+ db 0
+ db 'HUFF'
+ db 0
+ db 'Tried to expand a file that isn'
+ db 39
+ db 't HUFF!'
+ db 0
+ db 'RLEWExpand error!'
+ db 0
+ db '$'
+ db 0
+ db '%'
+ db 0
+ db '1'
+ db 0
+ db '0'
+ db 0
+ db '$'
+ db 0
+ db 'CTLPANEL.HOV'
+ db 0
+ db 'CTLPANEL.HOV'
+ db 0
+_DATA ends
+_TEXT segment byte public 'CODE'
+_TEXT ends
+ public _CenterWindow
+ public _CalibrateJoy
+ public _InputInt
+ public _printscan
+ public _SetScreenMode
+ public _PWrap
+ public _PrintBin
+ extrn _NBKascii:word
+ extrn _DrawPchar:near
+ extrn _filelength:near
+ public _PGet
+ public _PrintHex
+ public _PrintC
+ public _GenYlookup
+ public _ReadJoystick
+ extrn _write:near
+ public _levelheader
+ extrn _DrawChar:near
+ extrn _linewidth:word
+ public _videocard
+ public _highscore
+ public _HuffExpand
+ public _Input
+ extrn _MMFreePtr:near
+ public _buttonflip
+ public _grsegs
+ public _Ack
+ extrn _NBKscan:word
+ public _grmode
+ public _Print
+ public _FadeDown
+ public _PPrintUnsigned
+ public _SaveCtrls
+ public _mapheight
+ extrn _MMGetPtr:near
+ extrn _keydown:byte
+ public _mapplane
+ public _tileptr
+ public _pictable
+ public _win_yh
+ public _win_yl
+ public _win_xh
+ public _win_xl
+ public _OptimizeNodes
+ public _SaveFile
+ public _FadeOut
+ extrn _CallTimer:near
+ public _leftedge
+ public _PPrintHexB
+ public _picptr
+ public _mapwwide
+ public _mapbwide
+ public _PInput
+ public _EGAVirtualScreen
+ public _spriteptr
+ public _maprle
+ public _ClearKeys
+ public _screencentery
+ public _screencenterx
+ public _StopDrive
+ public _RLEWExpand
+ public _RLEBExpand
+ public _PPrintLong
+ public _needgr
+ public _ControlJoystick
+ extrn _memset:near
+ public _playermode
+ public _Verify
+ public _PPrintInt
+ public _pyh
+ public _pyl
+ public _EGASplitScreen
+ public _BloadinHUFFMM
+ extrn _ylookup:word
+ public _level
+ public _charptr
+ public _PPrintHex
+ public _ControlPlayer
+ public _BloadinRLEMM
+ extrn _strncmp:near
+ public _bordercolor
+ extrn _Quit:near
+ public _sy
+ extrn _read:near
+ public _ExpWinV
+ public _ExpWinH
+ extrn _strcpy:near
+ public _CPPrint
+ extrn _py:word
+ public _FadeUp
+ public _key
+ public _PPrint
+ extrn _close:near
+ public _Get
+ public _ColorBorder
+ extrn _WaitVBL:near
+ extrn _fontcolor:word
+ extrn _strlen:near
+ extrn N_SCOPY@:far
+ public _FadeIn
+ public _ExpWin
+ extrn _movedata:near
+ public _CharBar
+ extrn _Bar:near
+ public _JoyButton
+ extrn _strcat:near
+ public _SetNormalPalette
+ public _pxh
+ public _pxl
+ public _LoadCtrls
+ public _BloadinMM
+ extrn _ltoa:near
+ public _SetDefaultColors
+ extrn _itoa:near
+ public _useegamem
+ extrn _screenseg:word
+ extrn _atol:near
+ public _str
+ extrn N_LDIV@:far
+ public _keyB2
+ public _keyB1
+ public _nodearray
+ extrn _NoBiosKey:near
+ extrn _EGAplane:near
+ public _LoadFile
+ extrn _open:near
+ public _sx
+ public _LoadPage
+ public _JoyYhigh
+ public _JoyYlow
+ public _JoyXhigh
+ public _JoyXlow
+ public _colors
+ extrn _px:word
+ public _calibratekeys
+ public _PSize
+ extrn _toupper:near
+ public _PrintHexB
+ extrn _fontseg:word
+ public _score
+ public _mapwidthextra
+ public _DrawWindow
+ extrn N_PADD@:far
+ public _HuffExpandFile
+ extrn N_PSBA@:far
+ extrn N_PADA@:far
+ public _CRTCstart
+ public _PrintLong
+ public _ch
+ public _SetLineWidth
+ public _DrawFrame
+ public _ControlKBD
+ public _Printxy
+ public _PrintInt
+ end
+ \ No newline at end of file
diff --git a/IDLIBC.C b/IDLIBC.C
new file mode 100644
index 0000000..68a33e2
--- /dev/null
+++ b/IDLIBC.C
@@ -0,0 +1,2288 @@
+/* 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 "IDLIB.H"
+#pragma hdrstop
+
+/*
+=============================================================================
+
+ Library, C section
+
+=============================================================================
+*/
+
+#define BLANKCHAR 9
+
+char ch,str[80]; // scratch space
+
+
+inputtype playermode[3];
+
+int JoyXlow [3], JoyXhigh [3], JoyYlow [3], JoyYhigh [3], buttonflip;
+
+char key[8],keyB1,keyB2;
+
+
+////////////////////
+//
+// prototypes
+//
+////////////////////
+
+void CalibrateJoy (int joynum);
+void Printscan (int sc);
+void calibratekeys (void);
+
+//=========================================================================
+
+
+
+////////////////
+//
+// CalibrateJoy
+// Brings up a dialog and has the user calibrate
+// either joystick1 or joystick2
+//
+////////////////
+
+void CalibrateJoy (int joynum)
+{
+ int stage,dx,dy,xl,yl,xh,yh;
+ ControlStruct ctr;
+
+ ExpWin (34,11);
+
+
+ fontcolor=13;
+ CPPrint("Joystick Configuration\n");
+ py+=6;
+ fontcolor=15;
+ PPrint("Hold the joystick in the UPPER LEFT\n");
+ PPrint("corner and press a button:");
+ stage=15;
+ sx=(px+7)/8;
+ do // wait for a button press
+ {
+ DrawChar (sx,py,stage);
+ WaitVBL (3);
+ if (++stage==23)
+ stage=15;
+ ReadJoystick (joynum,&xl,&yl);
+ ctr = ControlJoystick(joynum);
+ if (keydown[1])
+ return;
+ } while (ctr.button1!= 1 && ctr.button2!=1);
+ DrawChar(sx,py,BLANKCHAR);
+ do // wait for the button release
+ {
+ ctr = ControlJoystick(joynum);
+ } while (ctr.button1);
+ WaitVBL (4); // so the button can't bounce
+
+ py+=6;
+ PPrint("\nHold the joystick in the LOWER RIGHT\n");
+ PPrint("corner and press a button:");
+ do // wait for a button press
+ {
+ DrawChar (sx,py,stage);
+ WaitVBL (3);
+ if (++stage==23)
+ stage=15;
+ ReadJoystick (joynum,&xh,&yh);
+ ctr = ControlJoystick(joynum);
+ if (keydown[1])
+ return;
+ } while (ctr.button1!= 1 && ctr.button2!=1);
+ DrawChar (sx,py,BLANKCHAR);
+ do // wait for the button release
+ {
+ ctr = ControlJoystick(joynum);
+ } while (ctr.button1);
+
+ //
+ // figure out good boundaries
+ //
+
+ dx=(xh-xl) / 6;
+ dy=(yh-yl) / 6;
+ JoyXlow[joynum]=xl+dx;
+ JoyXhigh[joynum]=xh-dx;
+ JoyYlow[joynum]=yl+dy;
+ JoyYhigh[joynum]=yh-dy;
+ if (joynum==1)
+ playermode[1]=joystick1;
+ else
+ playermode[1]=joystick2;
+
+ py+=6;
+ PPrint ("\n(F)ire or (A)fterburn with B1 ?");
+ ch = PGet();
+ if ( ch == 'A' || ch == 'a')
+ buttonflip = 1;
+ else
+ buttonflip = 0;
+}
+
+/////////////////////////////
+//
+// print a representation of the scan code key
+//
+////////////////////////////
+void printscan (int sc)
+{
+ char static chartable[128] =
+ {'?','?','1','2','3','4','5','6','7','8','9','0','-','+','?','?',
+ 'Q','W','E','R','T','Y','U','I','O','P','[',']','|','?','A','S',
+ 'D','F','G','H','J','K','L',';','"','?','?','?','Z','X','C','V',
+ 'B','N','M',',','.','/','?','?','?','?','?','?','?','?','?','?',
+ '?','?','?','?','?','?','?','?', 15,'?','-', 21,'5', 17,'+','?',
+ 19,'?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+ '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?',
+ '?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'};
+
+ sc = sc & 0x7f;
+
+ if (sc==1)
+ PPrint ("ESC");
+ else if (sc==0xe)
+ PPrint ("BKSP");
+ else if (sc==0xf)
+ PPrint ("TAB");
+ else if (sc==0x1d)
+ PPrint ("CTRL");
+ else if (sc==0x2A)
+ PPrint ("LSHIFT");
+ else if (sc==0x39)
+ PPrint ("SPACE");
+ else if (sc==0x3A)
+ PPrint ("CAPSLK");
+ else if (sc>=0x3b && sc<=0x44)
+ {
+ char str[3];
+ PPrint ("F");
+ itoa (sc-0x3a,str,10);
+ PPrint (str);
+ }
+ else if (sc==0x57)
+ PPrint ("F11");
+ else if (sc==0x59)
+ PPrint ("F12");
+ else if (sc==0x46)
+ PPrint ("SCRLLK");
+ else if (sc==0x1c)
+ PPrint ("ENTER");
+ else if (sc==0x36)
+ PPrint ("RSHIFT");
+ else if (sc==0x37)
+ PPrint ("PRTSC");
+ else if (sc==0x38)
+ PPrint ("ALT");
+ else if (sc==0x47)
+ PPrint ("HOME");
+ else if (sc==0x49)
+ PPrint ("PGUP");
+ else if (sc==0x4f)
+ PPrint ("END");
+ else if (sc==0x51)
+ PPrint ("PGDN");
+ else if (sc==0x52)
+ PPrint ("INS");
+ else if (sc==0x53)
+ PPrint ("DEL");
+ else if (sc==0x45)
+ PPrint ("NUMLK");
+ else if (sc==0x48)
+ PPrint ("UP");
+ else if (sc==0x50)
+ PPrint ("DOWN");
+ else if (sc==0x4b)
+ PPrint ("LEFT");
+ else if (sc==0x4d)
+ PPrint ("RIGHT");
+ else
+ {
+ str[0]=chartable[sc];
+ str[1]=0;
+ PPrint (str);
+ }
+}
+
+/////////////////////////////
+//
+// calibratekeys
+//
+////////////////////////////
+void calibratekeys (void)
+{
+ char ch;
+ int hx,hy,i,select,new;
+
+ ExpWin (22,12);
+ fontcolor=13;
+ CPPrint ("Keyboard Configuration");
+ fontcolor=15;
+ PPrint ("\n1 north");
+ PPrint ("\n2 east");
+ PPrint ("\n3 south");
+ PPrint ("\n4 west");
+ PPrint ("\n5 button1");
+ PPrint ("\n6 button2");
+ PPrint ("\nModify which action:");
+ hx=(px+7)/8;
+ hy=py;
+ for (i=0;i<4;i++)
+ {
+ px=pxl+8*12;
+ py=pyl+10*(1+i);
+ PPrint(":");
+ printscan (key[i*2]);
+ }
+ px=pxl+8*12;
+ py=pyl+10*5;
+ PPrint(":");
+ printscan (keyB1);
+ px=pxl+8*12;
+ py=pyl+10*6;
+ PPrint(":");
+ printscan (keyB2);
+
+ do
+ {
+ px=hx*8;
+ py=hy;
+ DrawChar (hx,hy,BLANKCHAR);
+ ch=PGet() % 256;
+ if (ch<'1' || ch>'6')
+ continue;
+ select = ch - '1';
+ DrawPchar (ch);
+ PPrint ("\nPress the new key:");
+ ClearKeys ();
+ new=-1;
+ while (!keydown[++new])
+ if (new==0x79)
+ new=-1;
+ else if (new==0x29)
+ new++; // skip STUPID left shifts!
+ Bar(leftedge,py,22,10,0xff);
+ if (select<4)
+ key[select*2]=new;
+ if (select==4)
+ keyB1=new;
+ if (select==5)
+ keyB2=new;
+ px=pxl+8*12;
+ py=pyl+(select+1)*10;
+ Bar(px/8,py,9,10,0xff);
+ PPrint (":");
+ printscan (new);
+ ClearKeys ();
+ ch='0'; // so the loop continues
+ } while (ch>='0' && ch<='9');
+ playermode[1]=keyboard;
+}
+
+//=========================================================================
+
+/*
+===========================
+=
+= ControlKBD
+=
+===========================
+*/
+
+ControlStruct ControlKBD ()
+{
+ int xmove=0,
+ ymove=0;
+ ControlStruct action;
+
+ if (keydown [key[north]])
+ ymove=-1;
+ if (keydown [key[east]])
+ xmove=1;
+ if (keydown [key[south]])
+ ymove=1;
+ if (keydown [key[west]])
+ xmove=-1;
+
+ if (keydown [key[northeast]])
+ {
+ ymove=-1;
+ xmove=1;
+ }
+ if (keydown [key[northwest]])
+ {
+ ymove=-1;
+ xmove=-1;
+ }
+ if (keydown [key[southeast]])
+ {
+ ymove=1;
+ xmove=1;
+ }
+ if (keydown [key[southwest]])
+ {
+ ymove=1;
+ xmove=-1;
+ }
+
+ switch (ymove*3+xmove)
+ {
+ case -4: action.dir = northwest; break;
+ case -3: action.dir = north; break;
+ case -2: action.dir = northeast; break;
+ case -1: action.dir = west; break;
+ case 0: action.dir = nodir; break;
+ case 1: action.dir = east; break;
+ case 2: action.dir = southwest; break;
+ case 3: action.dir = south; break;
+ case 4: action.dir = southeast; break;
+ }
+
+ action.button1 = keydown [keyB1];
+ action.button2 = keydown [keyB2];
+
+ return (action);
+}
+
+
+/*
+===============================
+=
+= ReadJoystick
+= Just return the resistance count of the joystick
+=
+===============================
+*/
+
+void ReadJoystick (int joynum,int *xcount,int *ycount)
+{
+ int portval,a1,a2,xbit,ybit;
+
+ if (joynum==1)
+ {
+ xbit=1;
+ ybit=2;
+ }
+ else
+ {
+ xbit=4;
+ ybit=8;
+ }
+
+ *xcount = 0;
+ *ycount = 0;
+
+ outportb (0x201,inportb (0x201)); /* start the signal pulse */
+
+ asm cli;
+
+ do
+ {
+ portval = inportb (0x201);
+ a1 = (portval & xbit) != 0;
+ a2 = (portval & ybit) != 0;
+ *xcount+=a1;
+ *ycount+=a2;
+ } while ((a1+a2!=0) && (*xcount<500) && (*ycount<500));
+
+ asm sti;
+}
+
+
+/*
+=============================
+=
+= JoyButton
+=
+= Returns the joystick button pressed, or 0
+=
+=============================
+*/
+
+int JoyButton (void)
+{
+ int buttons = inportb (0x201); /* Get all four button status */
+ if ((buttons & 0x10) == 0)
+ return 1;
+ if ((buttons & 0x20) == 0)
+ return 2;
+
+ return 0;
+}
+
+
+/*
+=============================
+=
+= ControlJoystick (joy# = 1 / 2)
+=
+=============================
+*/
+
+ControlStruct ControlJoystick (int joynum)
+{
+ int joyx = 0,joyy = 0, /* resistance in joystick */
+ xmove = 0,
+ ymove = 0,
+ buttons;
+ ControlStruct action;
+
+ ReadJoystick (joynum,&joyx,&joyy);
+ if ( (joyx>500) | (joyy>500) )
+ {
+ joyx=JoyXlow [joynum] + 1; /* no joystick connected, do nothing */
+ joyy=JoyYlow [joynum] + 1;
+ }
+
+ if (joyx > JoyXhigh [joynum])
+ xmove = 1;
+ else if (joyx < JoyXlow [joynum])
+ xmove = -1;
+ if (joyy > JoyYhigh [joynum])
+ ymove = 1;
+ else if (joyy < JoyYlow [joynum])
+ ymove = -1;
+
+ switch (ymove*3+xmove)
+ {
+ case -4: action.dir = northwest; break;
+ case -3: action.dir = north; break;
+ case -2: action.dir = northeast; break;
+ case -1: action.dir = west; break;
+ case 0: action.dir = nodir; break;
+ case 1: action.dir = east; break;
+ case 2: action.dir = southwest; break;
+ case 3: action.dir = south; break;
+ case 4: action.dir = southeast; break;
+ }
+
+ buttons = inportb (0x201); /* Get all four button status */
+ if (joynum == 1)
+ {
+ action.button1 = ((buttons & 0x10) == 0);
+ action.button2 = ((buttons & 0x20) == 0);
+ }
+ else
+ {
+ action.button1 = ((buttons & 0x40) == 0);
+ action.button2 = ((buttons & 0x80) == 0);
+ }
+ if (buttonflip)
+ {
+ buttons = action.button1;
+ action.button1 = action.button2;
+ action.button2 = buttons;
+ }
+ return (action);
+}
+
+
+/*
+=============================
+=
+= ControlPlayer
+=
+= Expects a 1 or a 2
+=
+=============================
+*/
+
+ControlStruct ControlPlayer (int player)
+{
+ ControlStruct ret;
+
+ switch (playermode[player])
+ {
+ case keyboard : return ControlKBD ();
+ case joystick1: return ControlJoystick(1);
+ case joystick2: return ControlJoystick(2);
+ }
+
+ return ControlKBD();
+}
+
+
+#define DRAWCHAR(x,y,n) DrawChar(x,(y)*8,n)
+
+/*
+=============================================================================
+**
+** Miscellaneous library routines
+**
+=============================================================================
+*/
+
+
+///////////////////////////////
+//
+// ClearKeys
+// Clears out the bios buffer and zeros out the keydown array
+//
+///////////////////////////////
+
+void ClearKeys (void)
+{
+ int i;
+ NBKscan=NBKascii=0;
+ memset (keydown,0,sizeof(keydown));
+}
+
+
+/*
+===============
+=
+= Ack
+=
+= Waits for a keypress or putton press
+=
+===============
+*/
+
+void Ack(void)
+{
+ ControlStruct c;
+
+ ClearKeys();
+ while (1)
+ {
+ if (NBKscan>127)
+ {
+ NBKscan&=0x7f;
+ return;
+ }
+ c = ControlPlayer(1);
+ if (c.button1 || c.button2)
+ return;
+ }
+}
+
+
+//==========================================================================
+
+/////////////////////////////////////////////////////////
+//
+// Load a LARGE file into a FAR buffer!
+//
+/////////////////////////////////////////////////////////
+unsigned long LoadFile(char *filename,char huge *buffer)
+{
+ unsigned handle,flength1=0,flength2=0,buf1,buf2,foff1,foff2,
+ len1,len2;
+
+ buf1=FP_OFF(buffer);
+ buf2=FP_SEG(buffer);
+
+asm mov WORD PTR foff1,0 // file offset = 0 (start)
+asm mov WORD PTR foff2,0
+
+asm mov dx,filename
+asm mov ax,3d00h // OPEN w/handle (read only)
+asm int 21h
+asm jc out
+
+asm mov handle,ax
+asm mov bx,ax
+asm xor cx,cx
+asm xor dx,dx
+asm mov ax,4202h
+asm int 21h // SEEK (find file length)
+asm jc out
+
+asm mov flength1,ax
+asm mov len1,ax
+asm mov flength2,dx
+asm mov len2,dx
+
+asm mov bx,handle
+asm xor cx,cx
+asm xor dx,dx
+asm mov ax,4200h
+asm int 21h // SEEK (to file start)
+asm jc out
+
+asm cmp WORD PTR len2,0 // MULTI-SEGMENTAL?
+asm je L_2
+
+L_1:
+
+asm push ds
+asm mov bx,handle
+asm mov cx,8000h // read 32K chunks
+asm mov dx,buf1
+asm mov ax,buf2
+asm mov ds,ax
+asm mov ah,3fh // READ w/handle
+asm int 21h
+asm pop ds
+asm jc out
+
+asm add buf2,800h
+asm sub len1,8000h
+asm sbb WORD PTR len2,0
+asm cmp WORD PTR len2,0
+asm ja L_1
+asm cmp len1,8000h
+asm jae L_1
+
+L_2:
+
+asm push ds
+asm mov bx,handle
+asm mov cx,len1
+asm mov dx,buf1
+asm mov ax,buf2
+asm mov ds,ax
+asm mov ah,3fh // READ w/handle
+asm int 21h
+asm pop ds
+
+out:
+
+asm mov bx,handle // CLOSE w/handle
+asm mov ah,3eh
+asm int 21h
+
+
+return (flength2*0x10000+flength1);
+
+}
+
+
+//===========================================================================
+
+/*
+==============================================
+=
+= Save a *LARGE* file far a FAR buffer!
+= by John Romero (C) 1990 PCRcade
+=
+==============================================
+*/
+
+void SaveFile(char *filename,char huge *buffer, long size)
+{
+ unsigned int handle,buf1,buf2,foff1,foff2;
+
+ buf1=FP_OFF(buffer);
+ buf2=FP_SEG(buffer);
+
+asm mov WORD PTR foff1,0 // file offset = 0 (start)
+asm mov WORD PTR foff2,0
+
+asm mov dx,filename
+asm mov ax,3c00h // CREATE w/handle (read only)
+asm xor cx,cx
+asm int 21h
+asm jc out
+
+asm mov handle,ax
+asm cmp word ptr size+2,0 // larger than 1 segment?
+asm je L2
+
+L1:
+
+asm push ds
+asm mov bx,handle
+asm mov cx,8000h
+asm mov dx,buf1
+asm mov ax,buf2
+asm mov ds,ax
+asm mov ah,40h // WRITE w/handle
+asm int 21h
+asm pop ds
+
+asm add buf2,800h // bump ptr up 1/2 segment
+asm sub WORD PTR size,8000h // done yet?
+asm sbb WORD PTR size+2,0
+asm cmp WORD PTR size+2,0
+asm ja L1
+asm cmp WORD PTR size,8000h
+asm jae L1
+
+L2:
+
+asm push ds
+asm mov bx,handle
+asm mov cx,WORD PTR size
+asm mov dx,buf1
+asm mov ax,buf2
+asm mov ds,ax
+asm mov ah,40h // WRITE w/handle
+asm int 21h
+asm pop ds
+asm jmp out
+
+out:
+
+asm mov bx,handle // CLOSE w/handle
+asm mov ah,3eh
+asm int 21h
+
+}
+
+//==========================================================================
+
+
+/*
+====================================
+=
+= BloadinMM
+=
+====================================
+*/
+
+void BloadinMM (char *filename,memptr *spot)
+{
+ int handle;
+ long length;
+ char huge *location;
+ char error[80];
+
+ if ( (handle = open (filename,O_BINARY)) != -1 )
+ {
+ length = filelength (handle);
+ MMGetPtr (spot,length);
+ close (handle);
+ LoadFile (filename,*spot);
+ }
+ else
+ {
+ strcpy (error,"BloadinMM: Can't find file ");
+ strcat (error,filename);
+ Quit (error);
+ }
+}
+
+
+/*
+========================================
+=
+= BloadinRLEMM
+= Returns a paraligned pointer to a file that has been unpacked off disk
+=
+========================================
+*/
+
+void BloadinRLEMM (char *filename,memptr *spot)
+{
+ long length;
+ memptr org;
+
+ BloadinMM (filename,&org);
+ length = *(long _seg *)org; // rleb compressed length
+ MMGetPtr (spot,length);
+ RLEBExpand ((unsigned char far *)org,(unsigned char far *)*spot);
+ MMFreePtr (&org);
+}
+
+
+/*
+========================================
+=
+= BloadinHUFFMM
+= Returns a paraligned pointer to a file that has been unpacked off disk
+=
+========================================
+*/
+
+int useegamem;
+
+void BloadinHUFFMM (char *filename,memptr *spot)
+{
+ long length;
+ memptr org;
+
+ if (useegamem)
+ {
+ org = (memptr)(0xa000+(linewidth*200)/16);
+ LoadFile (filename,MK_FP(org,0));
+ }
+ else
+ BloadinMM (filename,&org);
+
+ length = *(((long _seg *)org)+1); // huff compressed length
+ MMGetPtr (spot,length);
+ HuffExpandFile ((unsigned char far *)org,(unsigned char far *)*spot);
+
+ if (!useegamem)
+ MMFreePtr (&org);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Verify a file's existence
+//
+////////////////////////////////////////////////////////////////////
+long Verify(char *filename)
+{
+ int handle;
+ long size;
+
+ if ((handle=open(filename,O_BINARY))==-1) return 0;
+ size=filelength(handle);
+ close(handle);
+ return size;
+}
+
+
+/*
+====================
+=
+= StopDrive
+=
+= Stop a floppy drive after sounds have been started
+=
+====================
+*/
+
+void StopDrive (void)
+{
+ int i;
+
+ for (i=0;i<100;i++)
+ CallTimer();
+}
+
+
+/*
+============================================================================
+
+ COMPRESSION routines, see JHUFF.C for more
+
+============================================================================
+*/
+
+huffnode nodearray[256]; // 256 nodes is worst case
+
+void OptimizeNodes (huffnode *table);
+
+/*
+==================
+=
+= HuffExpandFile
+=
+= Expands a file with all needed header info
+=
+==================
+*/
+
+void HuffExpandFile (unsigned char huge *infile,
+ unsigned char huge *outfile)
+{
+ char header[4];
+ unsigned tag;
+ long length;
+
+ header[0] = *infile;
+ header[1] = *(infile+1);
+ header[2] = *(infile+2);
+ header[3] = *(infile+3);
+ if (strncmp (header,"HUFF",4))
+ Quit ("Tried to expand a file that isn't HUFF!");
+
+ length = *(long huge *)(infile+4);
+
+ movedata(FP_SEG(infile+8),FP_OFF(infile+8),_DS,(unsigned)&nodearray,1020);
+ OptimizeNodes (nodearray);
+ HuffExpand (infile+1028,outfile,length,nodearray);
+}
+
+
+/*
+===============
+=
+= OptimizeNodes
+=
+= Goes through a huffman table and changes the 256-511 node numbers to the
+= actular address of the node. Must be called before HuffExpand
+=
+===============
+*/
+
+void OptimizeNodes (huffnode *table)
+{
+ huffnode *node;
+ int i;
+
+ node = table;
+
+ for (i=0;i<255;i++)
+ {
+ if (node->bit0 >= 256)
+ node->bit0 = (unsigned)(table+(node->bit0-256));
+ if (node->bit1 >= 256)
+ node->bit1 = (unsigned)(table+(node->bit1-256));
+ node++;
+ }
+}
+
+
+
+/*
+======================
+=
+= HuffExpand
+=
+======================
+*/
+
+void HuffExpand (unsigned char huge *source, unsigned char huge *dest,
+ long length,huffnode *hufftable)
+{
+ unsigned bit,byte,node,code;
+ unsigned sourceseg,sourceoff,destseg,destoff,endseg,endoff;
+ huffnode *nodeon,*headptr;
+
+ headptr = hufftable+254; // head node is allways node 254
+
+#if0
+ bit = 1;
+ byte = *source++;
+
+ while (length)
+ {
+ if (byte&bit)
+ code = nodeon->bit1;
+ else
+ code = nodeon->bit0;
+
+ bit<<=1;
+ if (bit==256)
+ {
+ bit=1;
+ byte = *source++;
+ }
+
+ if (code<256)
+ {
+ *dest++=code;
+ nodeon=headptr;
+ length--;
+ }
+ else
+ nodeon = (huffnode *)code;
+ }
+
+#endif
+
+ source++; // normalize
+ source--;
+ dest++;
+ dest--;
+
+ sourceseg = FP_SEG(source);
+ sourceoff = FP_OFF(source);
+ destseg = FP_SEG(dest);
+ destoff = FP_OFF(dest);
+
+ length--;
+//
+// al = source byte
+// cl = bit in source (1,2,4,8,...)
+// dx = code
+//
+// ds:si source
+// es:di dest
+// ss:bx node pointer
+//
+
+asm mov bx,[headptr]
+asm mov cl,1
+
+asm mov si,[sourceoff]
+asm mov di,[destoff]
+asm mov es,[destseg]
+asm mov ds,[sourceseg]
+
+asm lodsb // load first byte
+
+expand:
+asm test al,cl // bit set?
+asm jnz bit1
+asm mov dx,[ss:bx] // take bit0 path from node
+asm jmp gotcode
+bit1:
+asm mov dx,[ss:bx+2] // take bit1 path
+
+gotcode:
+asm shl cl,1 // advance to next bit position
+asm jnc sourceup
+asm lodsb
+asm cmp si,0x10 // normalize ds:si
+asm jb sinorm
+asm mov cx,ds
+asm inc cx
+asm mov ds,cx
+asm xor si,si
+sinorm:
+asm mov cl,1 // back to first bit
+
+sourceup:
+asm or dh,dh // if dx<256 its a byte, else move node
+asm jz storebyte
+asm mov bx,dx // next node = (huffnode *)code
+asm jmp expand
+
+storebyte:
+asm mov [es:di],dl
+asm inc di // write a decopmpressed byte out
+asm mov bx,[headptr] // back to the head node for next bit
+
+asm cmp di,0x10 // normalize es:di
+asm jb dinorm
+asm mov dx,es
+asm inc dx
+asm mov es,dx
+asm xor di,di
+dinorm:
+
+asm sub [WORD PTR ss:length],1
+asm jnc expand
+asm dec [WORD PTR ss:length+2]
+asm jns expand // when length = ffff ffff, done
+
+asm mov ax,ss
+asm mov ds,ax
+
+}
+
+/*========================================================================*/
+
+
+/*
+======================
+=
+= RLEWexpand
+=
+======================
+*/
+#define RLETAG 0xFEFE
+
+void RLEWExpand (unsigned far *source, unsigned far *dest)
+{
+ long length;
+ unsigned value,count,i;
+ unsigned far *start,far *end;
+
+ length = *(long far *)source;
+ end = dest + (length)/2;
+
+ source+=2; // skip length words
+//
+// expand it
+//
+ do
+ {
+ value = *source++;
+ if (value != RLETAG)
+ //
+ // uncompressed
+ //
+ *dest++=value;
+ else
+ {
+ //
+ // compressed string
+ //
+ count = *source++;
+ value = *source++;
+ if (dest+count>end)
+ Quit("RLEWExpand error!");
+
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+ } while (dest<end);
+
+}
+
+
+#define RLEBTAG 0xFE
+
+
+/*
+======================
+=
+= RLEBExpand
+=
+======================
+*/
+
+void RLEBExpand (unsigned char far *source, unsigned char far *dest)
+{
+ long length;
+ unsigned char value,count;
+ unsigned i;
+ unsigned char far *start,far *end;
+
+ length = *(long far *)source;
+ end = dest + (length);
+
+ source+=4; // skip length words
+//
+// expand it
+//
+ do
+ {
+ value = *source++;
+ if (value != RLEBTAG)
+ //
+ // uncompressed
+ //
+ *dest++=value;
+ else
+ {
+ //
+ // compressed string
+ //
+ count = *source++;
+ value = *source++;
+ for (i=1;i<=count;i++)
+ *dest++ = value;
+ }
+ } while (dest<end);
+
+}
+
+
+/*
+============================================================================
+
+ GRAPHIC ROUTINES
+
+============================================================================
+*/
+
+/*
+** Graphic routines
+*/
+
+cardtype videocard;
+
+void huge *charptr; // 8*8 tileset
+void huge *tileptr; // 16*16 tileset
+void huge *picptr; // any size picture set
+void huge *spriteptr; // any size masked and hit rect sprites
+
+grtype grmode;
+
+int bordercolor;
+
+/*
+===============
+=
+= LoadPage
+=
+= Loads an rleb lbm2pic pic into latch memory
+=
+===============
+*/
+void LoadPage(char *filename,unsigned dest)
+{
+ memptr src;
+ unsigned from,source;
+ long length;
+ int i,j,width,height,xx,x,y,plane;
+
+//
+// load the pic in
+//
+
+ BloadinHUFFMM (filename,&src);
+ StopDrive();
+
+ from = 8;
+ width = *((int far *)src+2);
+ height = *((int far *)src+3);
+ for (i=0;i<4;i++)
+ {
+ EGAplane(i);
+ for (j=0;j<height;j++)
+ movedata((unsigned)src,from+width*j,0xa000,dest+linewidth*j,width);
+ from += width*height;
+ }
+ MMFreePtr (&src);
+}
+
+
+
+
+/*
+========================
+=
+= GenYlookup
+=
+= Builds ylookup based on linewidth
+=
+========================
+*/
+
+void GenYlookup (void)
+{
+ int i;
+
+ for (i=0;i<256;i++)
+ ylookup[i]=i*linewidth;
+}
+
+
+/*
+========================
+=
+= SetScreenMode
+= Call BIOS to set TEXT / CGAgr / EGAgr / VGAgr
+=
+========================
+*/
+
+void SetScreenMode (grtype mode)
+{
+ switch (mode)
+ {
+ case text: _AX = 3;
+ geninterrupt (0x10);
+ screenseg=0xb000;
+ break;
+ case CGAgr: _AX = 4;
+ geninterrupt (0x10);
+ screenseg=0xb800;
+ break;
+ case EGAgr: _AX = 0xd;
+ geninterrupt (0x10);
+ screenseg=0xa000;
+ break;
+#ifdef VGAGAME
+ case VGAgr:{
+ char extern VGAPAL; // deluxepaint vga pallet .OBJ file
+ void far *vgapal = &VGAPAL;
+ SetCool256 (); // custom 256 color mode
+ screenseg=0xa000;
+ _ES = FP_SEG(vgapal);
+ _DX = FP_OFF(vgapal);
+ _BX = 0;
+ _CX = 0x100;
+ _AX = 0x1012;
+ geninterrupt(0x10); // set the deluxepaint pallet
+
+ break;
+#endif
+ }
+}
+
+
+/*
+========================
+=
+= egasplitscreen
+=
+========================
+*/
+
+void EGASplitScreen (int linenum)
+{
+ WaitVBL (1);
+ if (videocard==VGAcard)
+ linenum=linenum*2-1;
+ outportb (CRTC_INDEX,CRTC_LINECOMPARE);
+ outportb (CRTC_INDEX+1,linenum % 256);
+ outportb (CRTC_INDEX,CRTC_OVERFLOW);
+ outportb (CRTC_INDEX+1, 1+16*(linenum/256));
+ if (videocard==VGAcard)
+ {
+ outportb (CRTC_INDEX,CRTC_MAXSCANLINE);
+ outportb (CRTC_INDEX+1,inportb(CRTC_INDEX+1) & (255-64));
+ }
+}
+
+
+/*
+========================
+=
+= EGAVirtualScreen
+=
+========================
+*/
+
+void EGAVirtualScreen (int width) // sets screen width
+{
+ WaitVBL (1);
+ outportb(CRTC_INDEX,CRTC_OFFSET);
+ outportb(CRTC_INDEX+1,width/2); // wide virtual screen
+}
+
+
+/*
+========================
+=
+= ColorBorder
+=
+========================
+*/
+
+void ColorBorder (int color)
+{
+ _AH=0x10;
+ _AL=1;
+ _BH=color;
+ geninterrupt (0x10); // color the border
+}
+
+
+/*
+========================
+=
+= crtcstart
+=
+========================
+*/
+
+void CRTCstart (unsigned start)
+{
+ WaitVBL (1);
+ outportb (CRTC_INDEX,CRTC_STARTLOW);
+ outportb (CRTC_INDEX+1,start % 256);
+ outportb (CRTC_INDEX,CRTC_STARTHIGH);
+ outportb (CRTC_INDEX+1,start / 256);
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Fade EGA screen in
+//
+////////////////////////////////////////////////////////////////////
+ char colors[7][17]=
+{{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,1,2,3,4,5,6,7,0},
+ {0,0,0,0,0,0,0,0,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},
+ {0,1,2,3,4,5,6,7,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0},
+ {0,1,2,3,4,5,6,7,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0},
+ {0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f,0x1f}};
+
+
+void SetDefaultColors(void)
+{
+ colors[3][16] = bordercolor;
+ _ES=FP_SEG(&colors[3]);
+ _DX=FP_OFF(&colors[3]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+}
+
+
+void FadeIn(void)
+{
+ int i;
+
+ for (i=0;i<4;i++)
+ {
+ colors[i][16] = bordercolor;
+ _ES=FP_SEG(&colors[i]);
+ _DX=FP_OFF(&colors[i]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+ WaitVBL(6);
+ }
+}
+
+
+void FadeUp(void)
+{
+ int i;
+
+ for (i=3;i<6;i++)
+ {
+ colors[i][16] = bordercolor;
+ _ES=FP_SEG(&colors[i]);
+ _DX=FP_OFF(&colors[i]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+ WaitVBL(6);
+ }
+}
+
+void FadeDown(void)
+{
+ int i;
+
+ for (i=5;i>2;i--)
+ {
+ colors[i][16] = bordercolor;
+ _ES=FP_SEG(&colors[i]);
+ _DX=FP_OFF(&colors[i]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+ WaitVBL(6);
+ }
+}
+
+void SetNormalPalette(void)
+{
+ int i;
+
+ colors[3][16] = bordercolor;
+ _ES=FP_SEG(&colors[3]);
+ _DX=FP_OFF(&colors[3]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Fade EGA screen out
+//
+////////////////////////////////////////////////////////////////////
+void FadeOut(void)
+{
+
+ int i;
+
+ for (i=3;i>=0;i--)
+ {
+ colors[i][16] = bordercolor;
+ _ES=FP_SEG(&colors[i]);
+ _DX=FP_OFF(&colors[i]);
+ _AX=0x1002;
+ geninterrupt(0x10);
+ WaitVBL(6);
+ }
+}
+
+/*
+====================
+=
+= SetLineWidth
+=
+====================
+*/
+
+void SetLineWidth (int width)
+{
+ EGAVirtualScreen(width);
+ linewidth = width;
+ GenYlookup();
+}
+
+
+/*
+============================================================================
+
+ IGRAB STUFF
+
+============================================================================
+*/
+
+
+memptr grsegs[NUMCHUNKS];
+char needgr[NUMCHUNKS]; // for caching
+
+#if NUMPICS>0
+pictype pictable[NUMPICS];
+#endif
+
+#if NUMPICM>0
+pictype picmtable[NUMPICS];
+unsigned picmsize[NUMPICS]; // plane size for drawing
+#endif
+
+#if NUMSPRITES>0
+spritetype image, spritetable[NUMSPRITES];
+unsigned spritesize[NUMSPRITES]; // plane size for drawing
+#endif
+
+#if NUMFONTS+NUMFONTSM>0
+unsigned fontcolor,pdrawmode;
+unsigned px,py;
+unsigned pxl,pxh,pyl,pyh;
+
+fontstruct _seg * fontseg; // used by drawpchar and drawmpchar
+#endif
+
+
+
+#if NUMSPRITES
+
+/*
+============
+=
+= DrawSprite
+=
+============
+*/
+
+void DrawSprite (int xcoord, int ycoord, int spritenum)
+{
+ int shapenum;
+ unsigned dest;
+
+ shapenum = spritenum;
+
+ switch (spritetable[spritenum].shifts)
+ {
+ case 2:
+ shapenum += (xcoord&7)/4;
+ break;
+ case 4:
+ shapenum += (xcoord&7)/2;
+ break;
+ case 8:
+ shapenum += (xcoord&7);
+ break;
+ }
+
+ xcoord = (xcoord+64)/8-8;
+ dest = ycoord*linewidth+xcoord+screenofs;
+
+ EGAWRITEMODE(0);
+
+ DrawSpriteT (spritetable[shapenum].width,spritetable[shapenum].height,
+ (unsigned)grsegs[shapenum+STARTSPRITES],dest,spritesize[shapenum]);
+}
+
+#endif
+
+
+/*
+============================================================================
+
+ MID LEVEL GRAPHIC ROUTINES
+
+============================================================================
+*/
+
+
+int win_xl,win_yl,win_xh,win_yh;
+
+int sx,sy,leftedge;
+
+int screencenterx = 20,screencentery = 11;
+
+
+//////////////////////////
+//
+// DrawWindow
+// draws a bordered window and homes the cursor
+//
+//////////////////////////
+
+void DrawWindow (int xl, int yl, int xh, int yh)
+{
+ int x,y;
+ win_xl=xl;
+ pxl = xl*8+8;
+ win_yl=yl;
+ win_xh=xh;
+ pxh = xh*8;
+ win_yh=yh; // so the window can be erased
+
+ DRAWCHAR (xl,yl,1);
+ for (x=xl+1;x<xh;x++)
+ DRAWCHAR (x,yl,2);
+ DRAWCHAR (xh,yl,3);
+ for (y=yl+1;y<yh;y++)
+ {
+ DRAWCHAR (xl,y,4);
+ for (x=xl+1;x<xh;x++)
+ DRAWCHAR (x,y,9);
+ DRAWCHAR (xh,y,5);
+ }
+ DRAWCHAR (xl,yh,6);
+ for (x=xl+1;x<xh;x++)
+ DRAWCHAR (x,yh,7);
+ DRAWCHAR (xh,yh,8);
+
+ sx = leftedge = xl+1;
+ sy = yl+1;
+ px=sx*8;
+ py=pyl=sy*8;
+}
+
+
+void EraseWindow (void)
+{
+ int x,y;
+
+ for (y=win_yl+1;y<win_yh;y++)
+ for (x=win_xl+1;x<win_xh;x++)
+ DRAWCHAR (x,y,9);
+
+ sx = leftedge = win_xl+1;
+ sy = win_yl+1;
+ px=sx*8;
+ py=pyl=sy*8;
+}
+
+/////////////////////////////
+//
+// CenterWindow
+// Centers a DrawWindow of the given size
+//
+/////////////////////////////
+
+void CenterWindow (int width, int height)
+{
+ int xl = screencenterx-width/2;
+ int yl = screencentery-height/2;
+
+ DrawWindow (xl,yl,xl+width+1,yl+height+1);
+}
+
+
+/////////////////////
+//
+// CharBar
+//
+/////////////////////
+void CharBar (int xl, int yl, int xh, int yh, int ch)
+{
+ int x,y;
+
+ for (y=yl;y<=yh;y++)
+ for (x=xl;x<=xh;x++)
+ DRAWCHAR (x,y,ch);
+}
+
+
+
+///////////////////////////////
+//
+// ExpWin {h / v}
+// Grows the window outward
+//
+///////////////////////////////
+void ExpWin (int width, int height)
+{
+ if (width > 2)
+ {
+ if (height >2)
+ ExpWin (width-2,height-2);
+ else
+ ExpWinH (width-2,height);
+ }
+ else
+ if (height >2)
+ ExpWinV (width,height-2);
+
+ WaitVBL (1);
+ CenterWindow (width,height);
+}
+
+void ExpWinH (int width, int height)
+{
+ if (width > 2)
+ ExpWinH (width-2,height);
+
+ WaitVBL (1);
+ CenterWindow (width,height);
+}
+
+void ExpWinV (int width, int height)
+{
+ if (height >2)
+ ExpWinV (width,height-2);
+
+ WaitVBL (1);
+ CenterWindow (width,height);
+}
+
+
+//////////////////////////////////////////////////
+//
+// Draw Frame 0/1 (for flashing)
+//
+//////////////////////////////////////////////////
+void DrawFrame(int x1,int y1,int x2,int y2,int type)
+{
+ int loop;
+
+ type=type*22+1;
+
+ for (loop=x1+1;loop<x2;loop++)
+ {
+ DRAWCHAR(loop,y1,type+1);
+ DRAWCHAR(loop,y2,type+6);
+ }
+ for (loop=y1+1;loop<y2;loop++)
+ {
+ DRAWCHAR(x1,loop,type+3);
+ DRAWCHAR(x2,loop,type+4);
+ }
+
+ DRAWCHAR(x1,y1,type);
+ DRAWCHAR(x2,y1,type+2);
+ DRAWCHAR(x2,y2,type+7);
+ DRAWCHAR(x1,y2,type+5);
+}
+
+
+/////////////////////////
+//
+// Get
+// Flash a cursor at sx,sy and waits for a user NoBiosKey
+//
+/////////////////////////
+
+int Get (void)
+{
+ int cycle,key;
+
+ ClearKeys();
+ do
+ {
+ cycle = 9;
+ while (!(key = NoBiosKey(1)) && cycle<13)
+ {
+ DRAWCHAR (sx,sy,cycle++);
+ WaitVBL (5);
+ }
+ } while (key == 0);
+ DRAWCHAR (sx,sy,' ');
+ return NoBiosKey(0); // take it out of the buffer
+}
+
+/*
+===========================================================================
+
+ CHARACTER BASED PRINTING ROUTINES
+
+===========================================================================
+*/
+
+
+/////////////////////////
+//
+// Print
+// Prints a string at sx,sy. No clipping!!!
+//
+/////////////////////////
+
+void Print (const char *str)
+{
+ unsigned char ch;
+
+ while ((ch=*str++) != 0)
+ if (ch == '\n')
+ {
+ sy++;
+ sx=leftedge;
+ }
+ else if (ch == '\r')
+ sx=leftedge;
+ else
+ DRAWCHAR (sx++,sy,ch);
+}
+
+
+///////////////////////////////////////////////////////////
+//
+// printxy
+//
+///////////////////////////////////////////////////////////
+void Printxy(int x,int y,char *string)
+{
+ int osx,osy;
+
+ osx=sx;
+ osy=sy;
+ sx=x;
+ sy=y;
+ Print(string);
+ sx=osx;
+ sy=osy;
+}
+
+
+///////////////////////////
+//
+// PrintInt / PrintLong
+// Converts the value to a string and Prints it
+//
+///////////////////////////
+
+void PrintInt (int val)
+{
+ itoa(val,str,10);
+ Print (str);
+}
+
+void PrintLong (long val)
+{
+ ltoa(val,str,10);
+ Print (str);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Print hex byte
+//
+////////////////////////////////////////////////////////////////////
+void PrintHexB(unsigned char value)
+{
+ int loop;
+ char hexstr[16]="0123456789ABCDEF",str[2]="";
+
+ for (loop=0;loop<2;loop++)
+ {
+ str[0]=hexstr[(value>>(1-loop)*4)&15];
+ Print(str);
+ }
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Print hex
+//
+////////////////////////////////////////////////////////////////////
+void PrintHex(unsigned value)
+{
+ Print("$");
+ PrintHexB(value>>8);
+ PrintHexB(value&0xff);
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Print bin
+//
+////////////////////////////////////////////////////////////////////
+void PrintBin(unsigned value)
+{
+ int loop;
+
+ Print("%");
+ for (loop=0;loop<16;loop++)
+ if ((value>>15-loop)&1) Print("1"); else Print("0");
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// center Print
+//
+////////////////////////////////////////////////////////////////////
+void PrintC(char *string)
+{
+ sx=1+screencenterx-(strlen(string)/2);
+ Print(string);
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Input unsigned
+//
+////////////////////////////////////////////////////////////////////
+unsigned InputInt(void)
+{
+ char string[18]="",digit,hexstr[16]="0123456789ABCDEF";
+ unsigned value,loop,loop1;
+
+ Input(string,2);
+ if (string[0]=='$')
+ {
+ int digits;
+
+ digits=strlen(string)-2;
+ if (digits<0) return 0;
+
+ for (value=0,loop1=0;loop1<=digits;loop1++)
+ {
+ digit=toupper(string[loop1+1]);
+ for (loop=0;loop<16;loop++)
+ if (digit==hexstr[loop])
+ {
+ value|=(loop<<(digits-loop1)*4);
+ break;
+ }
+ }
+ }
+ else if (string[0]=='%')
+ {
+ int digits;
+
+ digits=strlen(string)-2;
+ if (digits<0) return 0;
+
+ for (value=0,loop1=0;loop1<=digits;loop1++)
+ {
+ if (string[loop1+1]<'0' || string[loop1+1]>'1') return 0;
+ value|=(string[loop1+1]-'0')<<(digits-loop1);
+ }
+ }
+ else value=atoi(string);
+ return value;
+}
+
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// line Input routine (PROPORTIONAL)
+//
+////////////////////////////////////////////////////////////////////
+int Input(char *string,int max)
+{
+ char key;
+ int count=0,loop;
+ int pxt[90];
+
+ pxt[0]=px;
+
+ do {
+ key=toupper(PGet()&0xff);
+ if ((key==127 || key==8)&&count>0)
+ {
+ count--;
+ px=pxt[count];
+ DrawPchar(string[count]);
+ px=pxt[count];
+ }
+
+ if (key>=' ' && key<='z' && count<max)
+ {
+ *(string+count++)=key;
+ DrawPchar(key);
+ pxt[count]=px;
+ }
+
+ } while (key!=27 && key!=13);
+
+ for (loop=count;loop<max;loop++) *(string+loop)=0;
+
+ if (key==13) return 1;
+ return 0;
+}
+
+/*
+===========================================================================
+
+ PROPORTIONAL PRINTING ROUTINES
+
+===========================================================================
+*/
+
+unsigned pxl,pxh,pyl,pyh;
+
+/////////////////////////
+//
+// PPrint
+// Prints a string at px,py. No clipping!!!
+//
+/////////////////////////
+
+void PPrint (const char *str)
+{
+ unsigned char ch;
+
+ while ((ch=*str++) != 0)
+ if (ch == '\n')
+ {
+ py+=10;
+ px=pxl;
+ }
+ else if (ch == '')
+ fontcolor=(*str++)-'A'; // set color A-P
+ else
+ DrawPchar (ch);
+}
+
+
+
+/////////////////////////
+//
+// PGet
+// Flash a cursor at px,py and waits for a user NoBiosKey
+//
+/////////////////////////
+
+int PGet (void)
+{
+ int oldx;
+
+ oldx=px;
+
+ ClearKeys();
+ while (!(NoBiosKey(1)&0xff))
+ {
+ DrawPchar ('_');
+ WaitVBL (5);
+ px=oldx;
+ DrawPchar ('_');
+ px=oldx;
+ if (NoBiosKey(1)&0xff) // slight response improver
+ break;
+ WaitVBL (5);
+ }
+ px=oldx;
+ return NoBiosKey(0); // take it out of the buffer
+}
+
+
+/////////////////////////
+//
+// PSize
+// Return the pixels required to proportionaly print a string
+//
+/////////////////////////
+
+int PSize (const char *str)
+{
+ int length=0;
+ unsigned char ch;
+
+ while ((ch=*str++) != 0)
+ {
+ if (ch=='') // skip color changes
+ {
+ str++;
+ continue;
+ }
+ length += ((fontstruct _seg *)fontseg)->width[ch];
+ }
+
+ return length;
+}
+
+
+/////////////////////////
+//
+// CPPrint
+// Centers the string between pxl/pxh
+//
+/////////////////////////
+
+void CPPrint (const char *str)
+{
+ int width;
+
+ width = PSize(str);
+ px=pxl+(int)(pxh-pxl-width)/2;
+ PPrint (str);
+}
+
+
+/////////////////////////
+//
+// PWarap
+// Prints a string at px,py, word wrapping to pxl/pxh
+//
+/////////////////////////
+
+void PWrap (const char *str)
+{
+ unsigned char ch;
+
+ while ((ch=*str++) != 0)
+ if (ch == '\n')
+ {
+ py+=10;
+ px=leftedge;
+ }
+ else if (ch == '\r')
+ px=leftedge;
+ else
+ DrawPchar (ch);
+}
+
+
+void PPrintInt (int val)
+{
+ itoa(val,str,10);
+ PPrint (str);
+}
+
+void PPrintUnsigned (unsigned val)
+{
+ ltoa((long)val,str,10);
+ PPrint (str);
+}
+
+void PPrintLong (long val)
+{
+ ltoa((long)val,str,10);
+ PPrint (str);
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// line Input routine with default string
+//
+////////////////////////////////////////////////////////////////////
+int PInput(char *string,int max)
+{
+ char key;
+ int count,loop,oldx;
+
+ count = strlen(string);
+ PPrint (str);
+
+ do {
+ key=toupper(PGet()&0xff);
+ if ((key==127 || key==8)&&count>0)
+ {
+ px-= ((fontstruct _seg *)fontseg)->width[ch];
+ oldx=px;
+ count--;
+ DrawPchar(string[count]);
+ px=oldx;
+ }
+
+ if (key>=' ' && key<='z' && count<max)
+ {
+ *(string+count++)=key;
+ DrawPchar(key);
+ }
+
+ } while (key!=27 && key!=13);
+
+ for (loop=count;loop<max;loop++)
+ *(string+loop)=0;
+
+ if (key==13)
+ return 1;
+ return 0;
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Print hex byte
+//
+////////////////////////////////////////////////////////////////////
+void PPrintHexB(unsigned char value)
+{
+ int loop;
+ char hexstr[16]="0123456789ABCDEF",str[2]="";
+
+ for (loop=0;loop<2;loop++)
+ {
+ str[0]=hexstr[(value>>(1-loop)*4)&15];
+ PPrint(str);
+ }
+}
+
+
+
+////////////////////////////////////////////////////////////////////
+//
+// Print hex
+//
+////////////////////////////////////////////////////////////////////
+void PPrintHex(unsigned value)
+{
+ PPrint("$");
+ PPrintHexB(value>>8);
+ PPrintHexB(value&0xff);
+}
+
+
+/*
+===========================================================================
+
+ GAME ROUTINES
+
+===========================================================================
+*/
+
+long score,highscore;
+int level,bestlevel;
+
+char far *maprle;
+
+LevelDef far *levelheader;
+unsigned far *mapplane[4]; // points into map
+int mapbwide,mapwwide,mapwidthextra,mapheight;
+
+
+////////////////////////
+//
+// loadctrls
+// Tries to load the control panel settings
+// creates a default if not present
+//
+////////////////////////
+
+void LoadCtrls (void)
+{
+ int handle;
+
+ if ((handle = open("CTLPANEL."EXTENSION, O_RDONLY | O_BINARY, S_IWRITE | S_IREAD)) == -1)
+ //
+ // set up default control panel settings
+ //
+ {
+ key[0] = 0x48;
+ key[1] = 0x49;
+ key[2] = 0x4d;
+ key[3] = 0x51;
+ key[4] = 0x50;
+ key[5] = 0x4f;
+ key[6] = 0x4b;
+ key[7] = 0x47;
+ keyB1 = 0x1d;
+ keyB2 = 0x38;
+ }
+ else
+ {
+ read(handle, &key, sizeof(key));
+ read(handle, &keyB1, sizeof(keyB1));
+ read(handle, &keyB2, sizeof(keyB2));
+ read(handle, &highscore, sizeof(highscore));
+ read(handle, &bestlevel, sizeof(bestlevel));
+ close(handle);
+ }
+}
+
+void SaveCtrls (void)
+{
+ int handle;
+
+ if ((handle = open("CTLPANEL."EXTENSION, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE)) == -1)
+ return;
+
+ write(handle, &key, sizeof(key));
+ write(handle, &keyB1, sizeof(keyB1));
+ write(handle, &keyB2, sizeof(keyB2));
+ write(handle, &highscore, sizeof(highscore));
+ write(handle, &bestlevel, sizeof(bestlevel));
+
+ close(handle);
+}
+
diff --git a/JM.H b/JM.H
new file mode 100644
index 0000000..c6f250c
--- /dev/null
+++ b/JM.H
@@ -0,0 +1,34 @@
+/* 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.
+ */
+
+//
+// jm.h
+// Constants, structs, and function prototypes for my music stuff
+//
+
+#ifndef __jm__
+#define __jm__
+
+typedef unsigned int word;
+typedef unsigned long longword;
+
+#define false 0
+#define true 1
+#define nil 0L
+
+#endif
diff --git a/JM_SB.ASM b/JM_SB.ASM
new file mode 100644
index 0000000..49d8aa5
--- /dev/null
+++ b/JM_SB.ASM
@@ -0,0 +1,1176 @@
+; 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.
+
+ ifndef ??version
+?debug macro
+ endm
+publicdll macro name
+ public name
+ endm
+$comm macro name,dist,size,count
+ comm dist name:BYTE:count*size
+ endm
+ else
+$comm macro name,dist,size,count
+ comm dist name[size]:BYTE:count
+ endm
+ endif
+ ?debug S "jm_sb.c"
+ ?debug C E9573E9E16076A6D5F73622E63
+ ?debug C E900104D1613433A5C42435C494E434C5544455C646F732E68
+ ?debug C E9DB749D16076A6D5F73622E68
+ ?debug C E978749D16046A6D2E68
+_TEXT segment byte public 'CODE'
+_TEXT ends
+DGROUP group _DATA,_BSS
+ assume cs:_TEXT,ds:DGROUP
+_DATA segment word public 'DATA'
+d@ label byte
+d@w label word
+_DATA ends
+_BSS segment word public 'BSS'
+b@ label byte
+b@w label word
+_BSS ends
+_DATA segment word public 'DATA'
+sbSamplePlaying label word
+ db 0
+ db 0
+sbOldIntMask label byte
+ db 255
+sbLocation label word
+ db 255
+ db 255
+sbInterrupt label word
+ db 7
+ db 0
+sbIntVec label word
+ db 15
+ db 0
+sbIntVectors label word
+ db 255
+ db 255
+ db 255
+ db 255
+ db 10
+ db 0
+ db 11
+ db 0
+ db 255
+ db 255
+ db 13
+ db 0
+ db 255
+ db 255
+ db 15
+ db 0
+_DATA ends
+_TEXT segment byte public 'CODE'
+ ;
+ ; static void
+ ;
+ assume cs:_TEXT
+jmDelay proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov di,word ptr [bp+4]
+ jmp short @1@122
+@1@50:
+ ;
+ ; jmDelay(int usec)
+ ; {
+ ; // DEBUG - use real timing routines
+ ; int i;
+ ;
+ ; while (usec--)
+ ;
+ xor si,si
+ jmp short @1@98
+@1@74:
+ inc si
+@1@98:
+ cmp si,1000
+ jl short @1@74
+@1@122:
+ mov ax,di
+ dec di
+ or ax,ax
+ jne short @1@50
+ ;
+ ; for (i = 0;i < 1000;i++)
+ ; ;
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+jmDelay endp
+ ;
+ ; static longword
+ ;
+ assume cs:_TEXT
+jmPlaySeg proc near
+ push bp
+ mov bp,sp
+ sub sp,10
+ ;
+ ; jmPlaySeg(byte huge *data,longword length)
+ ; {
+ ; unsigned datapage;
+ ; longword dataofs,uselen;
+ ;
+ ;
+ mov ax,word ptr [bp+10]
+ mov dx,word ptr [bp+8]
+ mov word ptr [bp-8],ax
+ mov word ptr [bp-10],dx
+ ;
+ ; uselen = length;
+ ;
+ mov ax,word ptr [bp+6]
+ mov cl,12
+ shr ax,cl
+ mov word ptr [bp-2],ax
+ ;
+ ; datapage = FP_SEG(data) >> 12;
+ ;
+ mov ax,word ptr [bp+6]
+ and ax,4095
+ mov cl,4
+ shl ax,cl
+ add ax,word ptr [bp+4]
+ mov word ptr [bp-4],0
+ mov word ptr [bp-6],ax
+ ;
+ ; dataofs = ( (FP_SEG(data)&0xfff)<<4 ) + FP_OFF(data);
+ ;
+ cmp word ptr [bp-4],1
+ jb short @2@122
+ jne short @2@98
+ cmp word ptr [bp-6],0
+ jb short @2@122
+@2@98:
+ ;
+ ; if (dataofs>=0x10000)
+ ; {
+ ;
+ inc word ptr [bp-2]
+ ;
+ ; datapage++;
+ ;
+ sub word ptr [bp-6],0
+ sbb word ptr [bp-4],1
+@2@122:
+ ;
+ ; dataofs-=0x10000;
+ ; }
+ ;
+ ;
+ mov ax,word ptr [bp-4]
+ mov dx,word ptr [bp-6]
+ add dx,word ptr [bp-10]
+ adc ax,word ptr [bp-8]
+ cmp ax,1
+ jb short @2@218
+ ja short @2@194
+ or dx,dx
+ jbe short @2@218
+@2@194:
+ ;
+ ; if (dataofs + uselen > 0x10000)
+ ;
+ mov ax,1
+ xor dx,dx
+ sub dx,word ptr [bp-6]
+ sbb ax,word ptr [bp-4]
+ mov word ptr [bp-8],ax
+ mov word ptr [bp-10],dx
+@2@218:
+ ;
+ ; uselen = 0x10000 - dataofs;
+ ;
+ ;
+ sub word ptr [bp-10],1
+ sbb word ptr [bp-8],0
+ ;
+ ; uselen--; // DEBUG
+ ;
+ ; // Program the DMA controller
+ ;
+ mov dx,10
+ mov al,5
+ out dx,al
+ ;
+ ; outportb(0x0a,5); // Mask off channel 1 DMA
+ ;
+ mov dx,12
+ mov al,0
+ out dx,al
+ ;
+ ; outportb(0x0c,0); // Clear byte ptr F/F to lower byte
+ ;
+ mov dx,11
+ mov al,73
+ out dx,al
+ ;
+ ; outportb(0x0b,0x49); // Set transfer mode for D/A conv
+ ;
+ mov dx,2
+ mov al,byte ptr [bp-6]
+ out dx,al
+ ;
+ ; outportb(0x02,(byte)dataofs); // Give LSB of address
+ ;
+ mov dx,word ptr [bp-4]
+ mov ax,word ptr [bp-6]
+ mov cl,8
+ call near ptr N_LXURSH@
+ mov dx,2
+ out dx,al
+ ;
+ ; outportb(0x02,(byte)(dataofs >> 8)); // Give MSB of address
+ ;
+ mov dx,131
+ mov al,byte ptr [bp-2]
+ out dx,al
+ ;
+ ; outportb(0x83,(byte)datapage); // Give page of address
+ ;
+ mov dx,3
+ mov al,byte ptr [bp-10]
+ out dx,al
+ ;
+ ; outportb(0x03,(byte)uselen); // Give LSB of length
+ ;
+ mov dx,word ptr [bp-8]
+ mov ax,word ptr [bp-10]
+ mov cl,8
+ call near ptr N_LXURSH@
+ mov dx,3
+ out dx,al
+ ;
+ ; outportb(0x03,(byte)(uselen >> 8)); // Give MSB of length
+ ;
+ mov dx,10
+ mov al,1
+ out dx,al
+ jmp short @2@242
+@2@242:
+ ;
+ ; outportb(0x0a,1); // Turn on channel 1 DMA
+ ;
+ ; // Start playing the thing
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @2@242
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,20
+ out dx,al
+ jmp short @2@290
+@2@290:
+ ;
+ ; sbOut(sbWriteCmd,0x14);
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @2@290
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,byte ptr [bp-10]
+ out dx,al
+ jmp short @2@338
+@2@338:
+ ;
+ ; sbOut(sbWriteData,(byte)uselen);
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @2@338
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr [bp-8]
+ mov ax,word ptr [bp-10]
+ mov cl,8
+ call near ptr N_LXURSH@
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ out dx,al
+ ;
+ ; sbOut(sbWriteData,(byte)(uselen >> 8));
+ ;
+ ;
+ add word ptr [bp-10],1
+ mov ax,word ptr [bp-10]
+ adc word ptr [bp-8],0
+ mov dx,word ptr [bp-8]
+ jmp short @2@386
+@2@386:
+ ;
+ ; return(++uselen);
+ ;
+ mov sp,bp
+ pop bp
+ ret
+jmPlaySeg endp
+ ;
+ ; void interrupt
+ ;
+ assume cs:_TEXT
+_jmSBService proc far
+ push ax
+ push bx
+ push cx
+ push dx
+ push es
+ push ds
+ push si
+ push di
+ push bp
+ mov bp,DGROUP
+ mov ds,bp
+ mov bp,sp
+ sub sp,4
+ ;
+ ; jmSBService(void)
+ ; {
+ ; longword used;
+ ;
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,526
+ in al,dx
+ ;
+ ; sbIn(sbDataAvail);
+ ;
+ mov dx,32
+ mov al,32
+ out dx,al
+ ;
+ ; outportb(0x20,0x20);
+ ;
+ ;
+ xor cx,cx
+ xor bx,bx
+ mov dx,word ptr DGROUP:sbNextSegPtr+2
+ mov ax,word ptr DGROUP:sbNextSegPtr
+ call near ptr N_PCMP@
+ je short @3@194
+ ;
+ ; if (sbNextSegPtr)
+ ; {
+ ;
+ push word ptr DGROUP:sbNextSegLen+2
+ push word ptr DGROUP:sbNextSegLen
+ push word ptr DGROUP:sbNextSegPtr+2
+ push word ptr DGROUP:sbNextSegPtr
+ call near ptr jmPlaySeg
+ add sp,8
+ mov word ptr [bp-2],dx
+ mov word ptr [bp-4],ax
+ ;
+ ; used = jmPlaySeg(sbNextSegPtr,sbNextSegLen);
+ ;
+ mov ax,word ptr DGROUP:sbNextSegLen+2
+ mov dx,word ptr DGROUP:sbNextSegLen
+ cmp ax,word ptr [bp-2]
+ ja short @3@146
+ jne short @3@122
+ cmp dx,word ptr [bp-4]
+ ja short @3@146
+@3@122:
+ ;
+ ; if (sbNextSegLen <= used)
+ ;
+ mov word ptr DGROUP:sbNextSegPtr+2,0
+ mov word ptr DGROUP:sbNextSegPtr,0
+ jmp short @3@170
+@3@146:
+ ;
+ ; sbNextSegPtr = nil;
+ ; else
+ ; {
+ ;
+ mov cx,word ptr [bp-2]
+ mov bx,word ptr [bp-4]
+ mov dx,ds
+ mov ax,offset DGROUP:sbNextSegPtr
+ call near ptr N_PADA@
+ ;
+ ; sbNextSegPtr += used;
+ ;
+ mov ax,word ptr [bp-2]
+ mov dx,word ptr [bp-4]
+ sub word ptr DGROUP:sbNextSegLen,dx
+ sbb word ptr DGROUP:sbNextSegLen+2,ax
+@3@170:
+ ;
+ ; sbNextSegLen -= used;
+ ; }
+ ;
+ jmp short @3@218
+@3@194:
+ ;
+ ; }
+ ; else
+ ;
+ call near ptr _jmStopSample
+@3@218:
+ ;
+ ; jmStopSample();
+ ;
+ mov sp,bp
+ pop bp
+ pop di
+ pop si
+ pop ds
+ pop es
+ pop dx
+ pop cx
+ pop bx
+ pop ax
+ iret
+_jmSBService endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmPlaySample proc near
+ push bp
+ mov bp,sp
+ sub sp,24
+ push si
+ mov si,word ptr [bp+4]
+ ;
+ ; jmPlaySample(sound)
+ ; int sound;
+ ; {
+ ; byte huge *data,
+ ; timevalue;
+ ; longword used;
+ ; SampledSound sample;
+ ;
+ ;
+ call near ptr _jmStopSample
+ ;
+ ; jmStopSample();
+ ;
+ ;
+ dec si
+ lea ax,word ptr [bp-24]
+ push ss
+ push ax
+ mov ax,si
+ cwd
+ push ax
+ push dx
+ xor dx,dx
+ mov ax,14
+ pop cx
+ pop bx
+ call near ptr N_LXMUL@
+ push ax
+ push dx
+ mov dx,word ptr DGROUP:sbSamples+2
+ mov ax,word ptr DGROUP:sbSamples
+ pop cx
+ pop bx
+ call near ptr N_PADD@
+ push dx
+ push ax
+ mov cx,14
+ call near ptr N_SCOPY@
+ ;
+ ; sample = sbSamples[--sound];
+ ;
+ ;
+ mov dx,word ptr DGROUP:sbSamples+2
+ mov ax,word ptr DGROUP:sbSamples
+ mov cx,word ptr [bp-22]
+ mov bx,word ptr [bp-24]
+ call near ptr N_PADD@
+ mov word ptr [bp-2],dx
+ mov word ptr [bp-4],ax
+ ;
+ ; data = ((byte huge *)sbSamples) + sample.offset;
+ ;
+ push word ptr [bp-14]
+ push word ptr [bp-16]
+ mov ax,15
+ mov dx,16960
+ push ax
+ push dx
+ call near ptr N_LUDIV@
+ mov dl,0
+ sub dl,al
+ mov byte ptr [bp-5],dl
+ jmp short @4@50
+@4@50:
+ ;
+ ; timevalue = 256 - (1000000 / sample.hertz);
+ ;
+ ; // printf("sample #%d ",sound);
+ ; // printf("%ld bytes, %ldHz, tc=%d\n",sample.length,sample.hertz,timevalue);
+ ;
+ ; // printf("setting time constant\n");
+ ; // Set the SoundBlaster DAC time constant
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @4@50
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,64
+ out dx,al
+ jmp short @4@98
+@4@98:
+ ;
+ ; sbOut(sbWriteCmd,0x40);
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @4@98
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,byte ptr [bp-5]
+ out dx,al
+ ;
+ ; sbOut(sbWriteData,timevalue);
+ ;
+ ;
+ push word ptr [bp-18]
+ push word ptr [bp-20]
+ push word ptr [bp-2]
+ push word ptr [bp-4]
+ call near ptr jmPlaySeg
+ add sp,8
+ mov word ptr [bp-8],dx
+ mov word ptr [bp-10],ax
+ ;
+ ; used = jmPlaySeg(data,sample.length);
+ ;
+ mov ax,word ptr [bp-18]
+ mov dx,word ptr [bp-20]
+ cmp ax,word ptr [bp-8]
+ ja short @4@218
+ jne short @4@194
+ cmp dx,word ptr [bp-10]
+ ja short @4@218
+@4@194:
+ ;
+ ; if (sample.length <= used)
+ ;
+ mov word ptr DGROUP:sbNextSegPtr+2,0
+ mov word ptr DGROUP:sbNextSegPtr,0
+ jmp short @4@242
+@4@218:
+ ;
+ ; sbNextSegPtr = nil;
+ ; else
+ ; {
+ ;
+ mov dx,word ptr [bp-2]
+ mov ax,word ptr [bp-4]
+ mov cx,word ptr [bp-8]
+ mov bx,word ptr [bp-10]
+ call near ptr N_PADD@
+ mov word ptr DGROUP:sbNextSegPtr+2,dx
+ mov word ptr DGROUP:sbNextSegPtr,ax
+ ;
+ ; sbNextSegPtr = data + used;
+ ;
+ mov ax,word ptr [bp-18]
+ mov dx,word ptr [bp-20]
+ sub dx,word ptr [bp-10]
+ sbb ax,word ptr [bp-8]
+ mov word ptr DGROUP:sbNextSegLen+2,ax
+ mov word ptr DGROUP:sbNextSegLen,dx
+@4@242:
+ ;
+ ; sbNextSegLen = sample.length - used;
+ ; }
+ ;
+ ; // printf("enabling SB irq #%d\n",sbInterrupt);
+ ; // Save old interrupt status and unmask ours
+ ;
+ mov dx,33
+ in al,dx
+ mov byte ptr DGROUP:sbOldIntMask,al
+ ;
+ ; sbOldIntMask = inportb(0x21);
+ ;
+ mov al,1
+ mov cl,byte ptr DGROUP:sbInterrupt
+ shl al,cl
+ not al
+ push ax
+ mov al,byte ptr DGROUP:sbOldIntMask
+ pop dx
+ and al,dl
+ mov dx,33
+ out dx,al
+ jmp short @4@266
+@4@266:
+ ;
+ ; outportb(0x21,sbOldIntMask & ~(1 << sbInterrupt));
+ ;
+ ; // printf("enabling DSP DMA request\n");
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @4@266
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,212
+ out dx,al
+ ;
+ ; sbOut(sbWriteCmd,0xd4); // Make sure DSP DMA is enabled
+ ;
+ ; // printf("sound should be playing\n");
+ ;
+ mov word ptr DGROUP:sbSamplePlaying,1
+ ;
+ ; sbSamplePlaying = true;
+ ;
+ pop si
+ mov sp,bp
+ pop bp
+ ret
+_jmPlaySample endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmStopSample proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmStopSample(void)
+ ; {
+ ; byte is;
+ ;
+ ;
+ cmp word ptr DGROUP:sbSamplePlaying,0
+ je short @5@194
+ jmp short @5@74
+@5@74:
+ ;
+ ; if (sbSamplePlaying)
+ ; {
+ ; // printf("turning off DSP DMA\n");
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @5@74
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,208
+ out dx,al
+ ;
+ ; sbOut(sbWriteCmd,0xd0); // Turn off DSP DMA
+ ;
+ ; // printf("restoring interrupt\n");
+ ;
+ mov dx,33
+ in al,dx
+ mov bl,al
+ ;
+ ; is = inportb(0x21); // Restore interrupt mask bit
+ ;
+ mov ax,1
+ mov cl,byte ptr DGROUP:sbInterrupt
+ shl ax,cl
+ mov dl,byte ptr DGROUP:sbOldIntMask
+ mov dh,0
+ test ax,dx
+ je short @5@146
+ ;
+ ; if (sbOldIntMask & (1 << sbInterrupt))
+ ;
+ mov al,1
+ mov cl,byte ptr DGROUP:sbInterrupt
+ shl al,cl
+ or bl,al
+ jmp short @5@170
+@5@146:
+ ;
+ ; is |= (1 << sbInterrupt);
+ ; else
+ ;
+ mov al,1
+ mov cl,byte ptr DGROUP:sbInterrupt
+ shl al,cl
+ not al
+ and bl,al
+@5@170:
+ ;
+ ; is &= ~(1 << sbInterrupt);
+ ;
+ mov dx,33
+ mov al,bl
+ out dx,al
+ ;
+ ; outportb(0x21,is);
+ ;
+ ;
+ ;
+ mov word ptr DGROUP:sbSamplePlaying,0
+@5@194:
+ ;
+ ; sbSamplePlaying = false;
+ ; }
+ ;
+ pop bp
+ ret
+_jmStopSample endp
+ ;
+ ; static boolean
+ ;
+ assume cs:_TEXT
+jmCheckSB proc near
+ push bp
+ mov bp,sp
+ push si
+ ;
+ ; jmCheckSB(int port)
+ ; {
+ ; int i;
+ ;
+ ;
+ mov ax,word ptr [bp+4]
+ mov cl,4
+ shl ax,cl
+ mov word ptr DGROUP:sbLocation,ax
+ ;
+ ; sbLocation = port << 4; // Initialize stuff for later use
+ ;
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,518
+ mov al,1
+ out dx,al
+ ;
+ ; sbOut(sbReset,true); // Reset the SoundBlaster DSP
+ ;
+ mov ax,4
+ push ax
+ call near ptr jmDelay
+ pop cx
+ ;
+ ; jmDelay(4); // Wait 4usec
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,518
+ mov al,0
+ out dx,al
+ ;
+ ; sbOut(sbReset,false); // Turn off sb DSP reset
+ ;
+ mov ax,100
+ push ax
+ call near ptr jmDelay
+ pop cx
+ ;
+ ; jmDelay(100); // Wait 100usec
+ ;
+ xor si,si
+ jmp short @6@194
+@6@50:
+ ;
+ ; for (i = 0;i < 100;i++)
+ ; {
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,526
+ in al,dx
+ test al,128
+ je short @6@170
+ ;
+ ; if (sbIn(sbDataAvail) & 0x80) // If data is available...
+ ; {
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,522
+ in al,dx
+ cmp al,170
+ jne short @6@146
+ ;
+ ; if (sbIn(sbReadData) == 0xaa) // If it matches correct value
+ ;
+ mov ax,1
+ jmp short @6@242
+ jmp short @6@170
+@6@146:
+ ;
+ ; return(true);
+ ; else
+ ; {
+ ;
+ mov word ptr DGROUP:sbLocation,65535
+ ;
+ ; sbLocation = -1; // Otherwise not a SoundBlaster
+ ;
+ xor ax,ax
+ jmp short @6@242
+@6@170:
+ inc si
+@6@194:
+ cmp si,100
+ jl short @6@50
+ ;
+ ; return(false);
+ ; }
+ ; }
+ ; }
+ ;
+ mov word ptr DGROUP:sbLocation,65535
+ ;
+ ; sbLocation = -1; // Retry count exceeded - fail
+ ;
+ xor ax,ax
+ jmp short @6@242
+@6@242:
+ ;
+ ; return(false);
+ ;
+ pop si
+ pop bp
+ ret
+jmCheckSB endp
+ ;
+ ; boolean
+ ;
+ assume cs:_TEXT
+_jmDetectSoundBlaster proc near
+ push bp
+ mov bp,sp
+ push si
+ push di
+ mov si,word ptr [bp+4]
+ ;
+ ; jmDetectSoundBlaster(int port)
+ ; {
+ ; int i;
+ ;
+ ;
+ or si,si
+ jne short @7@74
+ ;
+ ; if (port == 0) // If user specifies default address, use 2
+ ;
+ mov si,2
+@7@74:
+ ;
+ ; port = 2;
+ ;
+ cmp si,65535
+ jne short @7@266
+ ;
+ ; if (port == -1)
+ ; {
+ ;
+ mov di,1
+ jmp short @7@194
+@7@122:
+ ;
+ ; for (i = 1;i <= 6;i++) // Scan through possible SB locations
+ ; {
+ ;
+ push di
+ call near ptr jmCheckSB
+ pop cx
+ or ax,ax
+ je short @7@170
+ ;
+ ; if (jmCheckSB(i)) // If found at this address,
+ ;
+ mov ax,1
+ jmp short @7@290
+@7@170:
+ inc di
+@7@194:
+ cmp di,6
+ jle short @7@122
+ ;
+ ; return(true); // return success
+ ; }
+ ;
+ xor ax,ax
+ jmp short @7@290
+ ;
+ ; return(false); // All addresses failed, return failure
+ ;
+ jmp short @7@290
+@7@266:
+ ;
+ ; }
+ ; else
+ ;
+ push si
+ call near ptr jmCheckSB
+ pop cx
+ jmp short @7@290
+@7@290:
+ ;
+ ; return(jmCheckSB(port)); // User specified address or default
+ ;
+ pop di
+ pop si
+ pop bp
+ ret
+_jmDetectSoundBlaster endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmSetSBInterrupt proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmSetSBInterrupt(int num)
+ ; {
+ ;
+ mov ax,word ptr [bp+4]
+ mov word ptr DGROUP:sbInterrupt,ax
+ ;
+ ; sbInterrupt = num;
+ ;
+ mov bx,word ptr DGROUP:sbInterrupt
+ shl bx,1
+ mov ax,word ptr DGROUP:sbIntVectors[bx]
+ mov word ptr DGROUP:sbIntVec,ax
+ ;
+ ; sbIntVec = sbIntVectors[sbInterrupt];
+ ;
+ pop bp
+ ret
+_jmSetSBInterrupt endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmStartSB proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmStartSB(void)
+ ; {
+ ; // printf("setting interrupt #0x%02x handler\n",sbIntVec);
+ ;
+ push word ptr DGROUP:sbIntVec
+ call near ptr _getvect
+ pop cx
+ mov word ptr DGROUP:sbOldIntHand+2,dx
+ mov word ptr DGROUP:sbOldIntHand,ax
+ ;
+ ; sbOldIntHand = getvect(sbIntVec); // Get old interrupt handler
+ ;
+ push cs
+ mov ax,offset _jmSBService
+ push ax
+ push word ptr DGROUP:sbIntVec
+ call near ptr _setvect
+ add sp,6
+ jmp short @9@50
+@9@50:
+ ;
+ ; setvect(sbIntVec,jmSBService); // Set mine
+ ;
+ ; // printf("setting DSP modes\n");
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ in al,dx
+ mov ah,0
+ test ax,128
+ jne short @9@50
+ ;
+ ; sbWriteDelay();
+ ;
+ mov dx,word ptr DGROUP:sbLocation
+ add dx,524
+ mov al,209
+ out dx,al
+ ;
+ ; sbOut(sbWriteCmd,0xd1); // Turn on DSP speaker
+ ;
+ pop bp
+ ret
+_jmStartSB endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmShutSB proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmShutSB(void)
+ ; {
+ ;
+ call near ptr _jmStopSample
+ ;
+ ; jmStopSample();
+ ;
+ ; // printf("restoring interrupt vector\n");
+ ;
+ push word ptr DGROUP:sbOldIntHand+2
+ push word ptr DGROUP:sbOldIntHand
+ push word ptr DGROUP:sbIntVec
+ call near ptr _setvect
+ add sp,6
+ ;
+ ; setvect(sbIntVec,sbOldIntHand); // Set vector back
+ ;
+ pop bp
+ ret
+_jmShutSB endp
+ ;
+ ; boolean
+ ;
+ assume cs:_TEXT
+_jmSamplePlaying proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmSamplePlaying(void)
+ ; {
+ ;
+ mov ax,word ptr DGROUP:sbSamplePlaying
+ jmp short @11@50
+@11@50:
+ ;
+ ; return(sbSamplePlaying);
+ ;
+ pop bp
+ ret
+_jmSamplePlaying endp
+ ;
+ ; void
+ ;
+ assume cs:_TEXT
+_jmSetSamplePtr proc near
+ push bp
+ mov bp,sp
+ ;
+ ; jmSetSamplePtr(s)
+ ; SampledSound huge *s;
+ ; {
+ ;
+ mov ax,word ptr [bp+6]
+ mov dx,word ptr [bp+4]
+ mov word ptr DGROUP:sbSamples+2,ax
+ mov word ptr DGROUP:sbSamples,dx
+ ;
+ ; sbSamples = s;
+ ;
+ pop bp
+ ret
+_jmSetSamplePtr endp
+_TEXT ends
+_BSS segment word public 'BSS'
+sbSamples label dword
+ db 4 dup (?)
+sbNextSegLen label word
+ db 4 dup (?)
+sbOldIntHand label dword
+ db 4 dup (?)
+sbNextSegPtr label dword
+ db 4 dup (?)
+ ?debug C E9
+_BSS ends
+_DATA segment word public 'DATA'
+s@ label byte
+_DATA ends
+_TEXT segment byte public 'CODE'
+_TEXT ends
+_sbIntVec equ sbIntVec
+ public _jmSBService
+_jmPlaySeg equ jmPlaySeg
+ extrn _setvect:near
+_jmCheckSB equ jmCheckSB
+ public _jmStartSB
+ extrn _getvect:near
+_jmDelay equ jmDelay
+ public _jmShutSB
+_sbSamplePlaying equ sbSamplePlaying
+ public _jmDetectSoundBlaster
+ extrn N_SCOPY@:far
+_sbNextSegPtr equ sbNextSegPtr
+_sbOldIntMask equ sbOldIntMask
+_sbIntVectors equ sbIntVectors
+ extrn N_LUDIV@:far
+ public _jmSetSBInterrupt
+_sbOldIntHand equ sbOldIntHand
+ extrn N_LXURSH@:far
+_sbInterrupt equ sbInterrupt
+ extrn N_LXMUL@:far
+_sbNextSegLen equ sbNextSegLen