diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..c05a8b9 --- /dev/null +++ b/INSTALL @@ -0,0 +1,53 @@ + + + INSTALLING FAR HORIZONS + + +Here are the steps needed to install Far Horizons on a Unix or Linux +computer (you will have to make appropriate modifications for other +computers): + + gunzip fh.tar.gz + tar xf fh.tar + +The above command(s) will create a subdirectory in your current +directory called "fh", which in turn will contain five of its own +subdirectories "bash", "bin", "doc", "game", and "src". + +Next, do this: + + cd fh/src + make.all + +The above will create all of the executable binaries and place them in +fh/bin. You may want to add fh/bin to your search path. + +There are a few utility programs that I have not had time to document, +such as Edit, Set, TurnNumber, etc. You can either ignore these or +scrutinize the source code to see what they do. They are not necessary +for running a game, but you may find some of them useful. + +The directory fh/bash contains several scripts that I use to make my job +easier. You will probably have to modify them for your own use. If you +decide to use them, you may want to move them to fh/bin or add fh/bash +to your execution path. Use the following commands to get help for each +one: + +fhclean --help +fhmail --help +fhorders --help +fhreports --help +source fhsave --help +source fhtest --help + +Some of the above scripts use a file named "fh_names" in the fh/game +directory. This file contains the species number, species name, and +email address for each player. A sample is provided with this +distribution that you can use as an example. + +There are a few other files in the fh/game directory that you should +look at as well. + +Finally, the Gamemaster should read file fh/doc/gm_sequence. It +provides a brief description of the steps needed to start and run a +game. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..6757284 --- /dev/null +++ b/LICENSE @@ -0,0 +1,416 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, 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 Library 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 + + + + + + + + + + + + + + + + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + 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., 675 Mass Ave, Cambridge, MA 02139, 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) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/README b/README new file mode 100644 index 0000000..c026356 --- /dev/null +++ b/README @@ -0,0 +1,24 @@ + +THIS SOFTWARE AND THE ACCOMPANYING DOCUMENTATION ARE 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 -- +NOTWITHSTANDING ANY STATEMENTS MADE BELOW IN THIS FILE. + +Far Horizons: + +This directory (fh) and its subdirectories contain the components of Far +Horizons, a role-playing game of galactic exploration and conquest, designed +for play-by-email. + +All the code and documentation in this directory and its subdirectories are +copyrighted by Richard A. Morneau. + +The code in these directories is free software; you can redistribute it and/or +modify it under terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any later +version. Far Horizons 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 +with this distribution (see file COPYING). If not, write to the Free Software +Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. diff --git a/bash/fhclean b/bash/fhclean new file mode 100755 index 0000000..9e5e3a2 --- /dev/null +++ b/bash/fhclean @@ -0,0 +1,61 @@ +#!/bin/sh + +if [ $# -ne 0 -o "$1" = "-h" -o "$1" = "--help" ] +then + + cat - < reports/stats/stats.t$turn + +echo "Deleting temporary files..." +rm -f interspecies.dat +rm -f *.msg +rm -f *.log + +echo "Done"\! diff --git a/bash/fhmail b/bash/fhmail new file mode 100755 index 0000000..7c789c1 --- /dev/null +++ b/bash/fhmail @@ -0,0 +1,35 @@ +#!/bin/bash + +if [ $# -ne 2 -o "$1" = "-h" -o "$1" = "--help" ] +then + + cat - < /tmp/fhorders.temp.$$ +do + + if egrep -iq '^Subject: .*fh.*order' /tmp/fhorders.temp.$$ + then + + head -1 /tmp/fhorders.temp.$$ > /tmp/fhorders.first_line.$$ + read a from_address b < /tmp/fhorders.first_line.$$ + from_address=`echo $from_address | tr 'A-Z' 'a-z'` + + n=1 + found=0 + while [ $n -le $num_species ] + do + if [ $from_address = ${address[$n]} ] + then + echo -n " Created file sp${sp_num[$n]}.ord for SP ${sp_name[$n]}" + echo " from $from_address." + cp /tmp/fhorders.temp.$$ sp${sp_num[$n]}.ord + found=1 + sp_count[$n]=$[ ${sp_count[$n]} + 1 ] + break + fi + n=$[ $n + 1 ] + done + + if [ $found -eq 0 ] + then + echo "WARNING: Unknown email address '$from_address' in message number $message_number"\! + fi + fi + + message_number=$[ $message_number + 1 ] +done + +rm -f /tmp/fhorders.*.$$ + +# +# Check sp_counts and report missing orders and multiple orders from the +# same player. +# +n=1 +while [ $n -le $num_species ] +do + if [ ${sp_count[$n]} -eq 0 ] + then + echo -n "WARNING: No orders were received for species number ${sp_num[$n]}," + echo " SP ${sp_name[$n]}"\! + elif [ ${sp_count[$n]} -gt 1 ] + then + echo -n "WARNING: ${sp_count[$n]} sets of orders were received for" + echo " species number ${sp_num[$n]}, SP ${sp_name[$n]}"\! + fi + n=$[ $n + 1 ] +done diff --git a/bash/fhreports b/bash/fhreports new file mode 100755 index 0000000..4f1f28d --- /dev/null +++ b/bash/fhreports @@ -0,0 +1,29 @@ +#!/bin/sh + +if [ $# -ne 0 -o "$1" = "-h" -o "$1" = "--help" ] +then + + cat - < /tmp/fhtest.dir/original_directory_name + +cd /tmp/fhtest.dir + +echo +echo Running NoOrders... +NoOrders +if [ $? -ne 0 ] ; then echo 'Error detected in program Combat!' ; return 1 ; fi + +echo +echo Running Combat... +Combat -s +if [ $? -ne 0 ] ; then echo 'Error detected in program Combat!' ; return 1 ; fi + +echo Running PreDeparture... +PreDeparture +if [ $? -ne 0 ] ; then echo 'Error detected in program PreDeparture!' ; return 1 ; fi + +echo Running Jump... +Jump +if [ $? -ne 0 ] ; then echo 'Error detected in program Jump!' ; return 1 ; fi + +echo Running Production... +Production +if [ $? -ne 0 ] ; then echo 'Error detected in program Production!' ; return 1 ; fi + +echo Running PostArrival... +PostArrival +if [ $? -ne 0 ] ; then echo 'Error detected in program PostArrival!' ; return 1 ; fi + +echo Running Locations... +Locations +if [ $? -ne 0 ] ; then echo 'Error detected in program Locations!' ; return 1 ; fi + +echo Running Strike... +Strike -s +if [ $? -ne 0 ] ; then echo 'Error detected in program Strike!' ; return 1 ; fi + +echo Running Finish... +Finish +if [ $? -ne 0 ] ; then echo 'Error detected in program Finish!' ; return 1 ; fi + +echo Running Report... +Report +if [ $? -ne 0 ] ; then echo 'Error detected in program Report!' ; return 1 ; fi + +echo +echo Done\! diff --git a/bin/AddSpecies b/bin/AddSpecies new file mode 100755 index 0000000..01cab62 Binary files /dev/null and b/bin/AddSpecies differ diff --git a/bin/AsciiToBinary b/bin/AsciiToBinary new file mode 100755 index 0000000..d671671 Binary files /dev/null and b/bin/AsciiToBinary differ diff --git a/bin/BinaryToAscii b/bin/BinaryToAscii new file mode 100755 index 0000000..e6720de Binary files /dev/null and b/bin/BinaryToAscii differ diff --git a/bin/Combat b/bin/Combat new file mode 100755 index 0000000..4b88474 Binary files /dev/null and b/bin/Combat differ diff --git a/bin/Edit b/bin/Edit new file mode 100755 index 0000000..f73414a Binary files /dev/null and b/bin/Edit differ diff --git a/bin/Finish b/bin/Finish new file mode 100755 index 0000000..82c3f8b Binary files /dev/null and b/bin/Finish differ diff --git a/bin/HomeSystem b/bin/HomeSystem new file mode 100755 index 0000000..71f5ffd Binary files /dev/null and b/bin/HomeSystem differ diff --git a/bin/Jump b/bin/Jump new file mode 100755 index 0000000..be738a0 Binary files /dev/null and b/bin/Jump differ diff --git a/bin/ListGalaxy b/bin/ListGalaxy new file mode 100755 index 0000000..a36b174 Binary files /dev/null and b/bin/ListGalaxy differ diff --git a/bin/Locations b/bin/Locations new file mode 100755 index 0000000..fa1eaee Binary files /dev/null and b/bin/Locations differ diff --git a/bin/MakeHomes b/bin/MakeHomes new file mode 100755 index 0000000..9b852b6 Binary files /dev/null and b/bin/MakeHomes differ diff --git a/bin/MapGalaxy b/bin/MapGalaxy new file mode 100755 index 0000000..1368982 Binary files /dev/null and b/bin/MapGalaxy differ diff --git a/bin/Near b/bin/Near new file mode 100755 index 0000000..8fc1c86 Binary files /dev/null and b/bin/Near differ diff --git a/bin/NewGalaxy b/bin/NewGalaxy new file mode 100755 index 0000000..edd7694 Binary files /dev/null and b/bin/NewGalaxy differ diff --git a/bin/NoOrders b/bin/NoOrders new file mode 100755 index 0000000..01db53f Binary files /dev/null and b/bin/NoOrders differ diff --git a/bin/PostArrival b/bin/PostArrival new file mode 100755 index 0000000..5ea2add Binary files /dev/null and b/bin/PostArrival differ diff --git a/bin/PreDeparture b/bin/PreDeparture new file mode 100755 index 0000000..72ae451 Binary files /dev/null and b/bin/PreDeparture differ diff --git a/bin/Production b/bin/Production new file mode 100755 index 0000000..c97ed3d Binary files /dev/null and b/bin/Production differ diff --git a/bin/Report b/bin/Report new file mode 100755 index 0000000..0bacd28 Binary files /dev/null and b/bin/Report differ diff --git a/bin/ScanSpXYZ b/bin/ScanSpXYZ new file mode 100755 index 0000000..d35be52 Binary files /dev/null and b/bin/ScanSpXYZ differ diff --git a/bin/Set b/bin/Set new file mode 100755 index 0000000..71aab8b Binary files /dev/null and b/bin/Set differ diff --git a/bin/ShowGalaxy b/bin/ShowGalaxy new file mode 100755 index 0000000..e40d3fa Binary files /dev/null and b/bin/ShowGalaxy differ diff --git a/bin/Stats b/bin/Stats new file mode 100755 index 0000000..9b93e75 Binary files /dev/null and b/bin/Stats differ diff --git a/bin/Strike b/bin/Strike new file mode 120000 index 0000000..ebe0adb --- /dev/null +++ b/bin/Strike @@ -0,0 +1 @@ +../bin/Combat \ No newline at end of file diff --git a/bin/TurnNumber b/bin/TurnNumber new file mode 100755 index 0000000..55c9186 Binary files /dev/null and b/bin/TurnNumber differ diff --git a/doc/default_orders b/doc/default_orders new file mode 100644 index 0000000..f0d4750 --- /dev/null +++ b/doc/default_orders @@ -0,0 +1,40 @@ + +Note: this is out-of-date! + + +The computer will automatically generate default orders for you if I do +not receive your orders on time. Thus, if you quit the game, your species +will continue on "auto-pilot" until you return, until I find a replacement +player, or until I give up. In effect, your species will temporarily become +a "non-player" species. Default orders will be generated as follows: + + 1. If a non-self-sufficient colony has CUs and IUs or AUs in its + inventory, appropriate INSTALL orders will be issued. + + 2. If a transport is carrying CUs, if it is orbiting or landed on + a non-self-sufficient colony, and if it is NOT in the home + system, then it will be given an UNLOAD order if doing so + will not exceed the 250.0 base limit. + + 3. If a non-self-sufficient colony has available population units, + they will be converted to colonist units, and an appropriate + number of colonial mining and manufacturing units will be + built. (The computer will not exceed the 250.0 limit.) + + 4. For each ship that is still under construction, as much additional + construction as possible will be done based on available funds. + + 5. For each starbase you own, the size will be increased as much as + possible, limited only by your manufacturing technology and + available funds. + + 6. All remaining funds will be evenly allocated to research. If + a tech level is zero, then it will NOT be researched. + + 7. The gamemaster may intervene if he feels that a player is taking + advantage of a non-player species in a highly unrealistic + manner. This intervention will be extremely subtle, and the + cheater will not even know it's happening. Heh, heh, heh. + + +All of the above is subject to change. Let me know what you think. diff --git a/doc/gm_sequence b/doc/gm_sequence new file mode 100644 index 0000000..946d9bf --- /dev/null +++ b/doc/gm_sequence @@ -0,0 +1,23 @@ + +The following steps apply only to normal turns. For the setup turn, +first create the galaxy using the NewGalaxy and MakeHomes programs. +Then generate the star list (ListGalaxy -p) and map files (MapGalaxy). +Next, for each player run the HomeSystem and AddSpecies programs. After +this has been done for all species, run Finish and Report. Finally, +continue with step 3 below. + + +1. As orders come in, copy them to the appropriate spNN.ord files in the +fh/game directory. (You may want to use script "fhorders" to do this +automatically.) + +2. After all orders have been received, run NoOrders, Combat, +PreDeparture, Jump, Production, PostArrival, Locations, Strike, Finish, +and Report (in that order). Script "fhtest" and "fhsave" were written +to automate this process. + +3. Run the "fhreports" script. It will mail the reports to the players. + +4. Run the "fhclean" script. It will delete all temporary files that +were used during the turn, and copy all data and report files to backup +directories. diff --git a/doc/rules b/doc/rules new file mode 100644 index 0000000..7bf997d --- /dev/null +++ b/doc/rules @@ -0,0 +1,5906 @@ + + + Seventh Edition Rules for + + FAR HORIZONS + + by Rick Morneau + + January 2, 1999 + + Copyright 1999 by Richard A. Morneau + + + +FAR HORIZONS is a strategic role-playing game of galactic exploration, trade, +diplomacy, and conquest. The first and second editions were designed for play +by postal mail. Later editions were designed for play by electronic mail, and +many mistakes were made in the transition. Hopefully, this current edition has +corrected most of those mistakes. + +At the start of a game, each player controls an intelligent species and the +home planet on which it lives. As the game progresses, you can explore nearby +regions of the galaxy and establish colonies. As you range farther and farther +from home, you will encounter other intelligent species. These encounters can +be hostile, neutral, or friendly, depending on the participants. Interstellar +war is a distinct possibility. + +FAR HORIZONS, unlike some similar games, has been designed to make role- +playing as easy and practical as possible. In addition to being a rich and +realistic simulation, there are no true victory conditions - the game is played +solely for enjoyment. However, at the end of the last turn, final statistics +for all species will be sent to all of the players so that they can compare +their relative strengths and weaknesses. Thus, rather than requiring a massive +bloodletting as in some other similar games, it's possible for a peace-loving +species to effectively "win". + +Still, those who enjoy a more aggressive game, or those who wish to role-play +an "evil" or warlike species will not be disappointed. FAR HORIZONS does not +discriminate against anyone - it simply tries to be as realistic as possible. + + + +1.0 GAME BASICS + +The following sections will discuss the basic concepts used throughout the +game. + + +1.1 THE GAME TURN + +A game turn is about five Earth years long. As a result, generations can pass +in a single game. Populations will increase and colonies will grow. Since +quite a lot can happen in five years, FAR HORIZONS is strategic in nature, +rather than tactical. The reason for a five year turn will be explained below. + + +1.2 THE GALAXY + +In FAR HORIZONS, the galaxy is a small open star cluster. It is approximately +spherical, but is projected onto an easy-to-use two-dimensional map. The size +of the galaxy and the actual number of stars in it will depend on the number +of players. As an example, for a game with about 15 players, the galaxy would +have a radius of approximately 18 parsecs and contain about 80 usable star +systems. + +The basic unit of interstellar distance is the PARSEC, which is equal to 3.26 +light-years. Thus, every star system in the galaxy will have an X, Y, and Z +coordinate in parsecs, relative to the reference point at 0,0,0. Furthermore, +all coordinate values are zero or greater. Thus, you can picture the galaxy +as floating in a box whose lower, left, rear corner has the coordinates 0,0,0. +(Negative numbers were used in earlier games, but players sometimes forgot the +minus signs, with disastrous results. Use of only positive numbers will help +prevent mistakes.) + + +1.3 SPACE TRAVEL + +In this universe, scientists have discovered only one way to break the barrier +imposed by the speed of light. The method is inherently risky. Essentially, +a spaceship's engines must "rip" a hole through the space-time fabric in order +to travel from one point to another. A ship does this by creating a temporary, +private "wormhole" that the ship can pass through. A ship does this by +creating and manipulating a small black hole. When a ship travels in this +way, it is said to "jump" to its destination. + +There is no limit to how far a ship can travel in this way, but greater +distances involve greater risks. The technology involved is called +"gravitics", and the more experience a species has in this technology, the +farther a ship can jump without risk of missing its destination or of being +destroyed. + +The time needed for a ship to travel through the wormhole is independent of the +distance being traveled. However, it IS dependent on the mass of the ship, as +shown by the following equation: + + time in years = 5 tanh (mass in grams) + +If you're not mathematically inclined, don't worry! What the equation says is +that it takes almost exactly five years for anything larger than a pea, since +all masses used in the game will be at the extreme asymptotic limit of the +equation. Only extremely small masses (such as the photons that make up radio +waves) can take significantly less than 5 years to travel through a wormhole. + +Note also that no time goes by for the people on the ship. For them, the move +is essentially instantaneous. For the people who remain behind, however, the +ship will appear to "wink out" immediately. Five years later, it will reappear +at its destination. + +Creation of a wormhole is risky business, and there is always a chance that a +ship can be swallowed up by the wormhole it creates. If this happens, then the +ship and everything it carries will be totally destroyed. It is also possible +for a ship to "mis-jump". If this occurs, the ship will not be destroyed, but +will simply arrive at the wrong destination. As a species gains knowledge and +experience in gravitics technology, its ships will become more reliable and +less susceptible to sudden destruction or mis-jumps. + + +1.4 COMMUNICATIONS + +Communications across interstellar distances utilizes the same technology as +space travel, but on a much smaller scale. Any two tranceivers can be "tuned" +to each other (if both sides cooperate), effectively creating a small wormhole +through which radio waves can pass. Also, since radio waves have very close +to zero mass, the transmission time is close to zero. Thus, although ships +require five years to move between star systems, radio communication is +essentially instantaneous, and home planets can always be in instant +communication with their ships and colonies. Note, though, that ships in +transit are incapable of communicating, since, for them, no time is actually +passing. + + +1.5 THE HOME PLANET + +Each player starts the game with a home planet. This is where his species +evolved, acquired intelligence, and eventually learned how to travel among the +stars. + +At the start of the game, the only material resources available to a species +are those of its home planet. These resources can be used to build units +such as mines, factories, spaceships, planetary defenses, etc. As the game +proceeds, a species can colonize other planets and tap them for resources +as well. + + +1.6 TECH LEVELS + +A tech level is a measure of how advanced a species is in a specific field of +technology. Six technologies are defined and used in this game. Each one is +described below: + + MINING Mining tech level is a measure of how proficient + a species is at tapping a planet's natural resources. + It includes functions such as mining and farming, + and basic refining and food processing. As mining tech + level increases, greater quantities of raw materials + can be produced. + + MANUFACTURING Manufacturing tech level is a measure of proficiency + at converting raw materials to usable, final forms. + It is used to determine how many units, such as ships, + can be built each turn. It also places a limit on + the maximum size of ships that a species can build. + + MILITARY Military tech level is a measure of experience in + warfare. It indicates the level of sophistication + in military strategy, tactics, and weaponry. It + is one of the major factors used to determine the + outcome of armed conflict. + + GRAVITICS Gravitics tech level is a measure of a species' + knowledge of gravity control. Gravitics allows + the design of the engines which drive interstellar + ships, since a black hole cannot be created and + controlled without the ability to manipulate + gravitational fields. + + LIFE SUPPORT Life support tech level is a measure of a species' + experience in surviving in hostile environments. + It is used to construct and maintain artificial + shelters on planets with temperatures or atmospheres + that differ from the home planet. It also determines + the effectiveness of defensive shields used on ships. + + BIOLOGY Biology tech level is a measure of a species' + knowledge and experience in the life sciences. Its + most obvious applications are in genetic engineering, + germ warfare, and terraforming (i.e., using specially + designed micro-organisms to modify the atmosphere + and micro-flora of a planet, making it more suitable + for habitation). + +There are many other applications of the six basic technologies in addition to +the ones mentioned above. These will be discussed later. After the start of +the game, tech levels will increase primarily through research. While there is +no limit to how high a tech level can get, in practice it is unlikely that a +tech level will ever exceed 100. + + +1.7 TURN PROCESSING: Sequence of Events + +Each turn is processed in six steps, and the order form that you send to the +gamemaster has six corresponding sections. These sections are: + + 1. Combat orders + 2. Pre-departure orders + 3. Jump orders + 4. Production orders + 5. Post-arrival orders + 6. Strike orders + +When your turn is processed, all combat orders are processed first, then all +pre-departure orders, then all jump orders, and so on. After yur orders have +been processed, a special program is run that handles population growth and +interspecies transactions, and performs several other housekeeping chores. +Finally, a "report" program is run that generates summaries that will be sent +to the players. Thus, several programs are actually used by the gamemaster +to process a turn. + +[The strike phase is a limited-combat phase. Any combat that takes place +in the strike phase generally takes the form of an initial surprise attack. +Combat that requires more time, such as bombardment and siege, will take place +in the combat phase of the following turn, and are thus continuations of the +combat that began in the strike phase.] + +At the end of each report is an order form that you will need to fill out. +This form will contain all six sections, even though not all of them may be +applicable for the current turn. For example, the jump section cannot be used +in the first turn, since you have no ships. Simply delete the sections that +do not apply, and fill out and send in those that do. + +Each section of the orders begins with a START command and ends with an END +command. Each section should only appear ONCE. Thus, each order form will +contain the following sections: + +START COMBAT +;Combat orders belong here. + +END + +START PRE-DEPARTURE +;Pre-departure orders belong here. + +END + +START JUMPS +;Jump orders belong here. + +END + +START PRODUCTION +;Production orders belong here. + +END + +START POST-ARRIVAL +;Post-arrival orders belong here. + +END + +START STRIKES +;Strike orders belong here. + +END + +The production section will be started for you, and will have an appropriate +PRODUCTION order for each planet you control. This will save you a little +time, and will help prevent you from accidentally forgetting to give orders +for a planet. + +The six sections shown above may appear in any sequence. However, it is +recommended that you fill out your orders using the sequence provided, +since that is the sequence in which they will be executed. In other words, +combat orders will be executed before pre-departure orders, pre-departure +orders will be executed before jump orders, and so forth, REGARDLESS of where +each section appears in your order form. + +The orders that you give in each section must be reasonable for that section. +For example, you may not give JUMP orders in any section except the jump +section. BUILD and RESEARCH orders may only be given in the production +section. Combat orders may only be given in the combat and strike sections. +And so on. Here is a complete list: + + Combat section: + + Attack + Battle + Engage + Haven + Hide + Hijack + Summary + Target + Withdraw + + Pre-departure section: + + Ally + Base + Deep + Destroy + Disband + Enemy + Install + Land + Message + Name + Neutral + Orbit + Repair + Scan + Send + Transfer + Unload + Zzz + + Jump section: + + Jump + Move + Pjump + Visited + Wormhole + + Production section: + + Ally + Ambush + Build + Continue + Develop + Enemy + Estimate + Hide + Ibuild + Icontinue + Intercept + Neutral + Production + Recycle + Research + Shipyard + Upgrade + + Post-arrival section: + + Ally + Auto + Deep + Destroy + Enemy + Land + Message + Name + Neutral + Orbit + Repair + Scan + Send + Teach + Telescope + Terraform + Transfer + Zzz + + Strike section: + + same as combat section + + +All of these commands will be explained in later sections of this document. + +[A special note must be made about the TRANSFER command. There is a possible +situation in which colonists and supplies could be transferred to a new colony +immediately after a jump. If the planet is already inhabited by another +species, neither species will know about the new colony until the next turn. +To prevent this very unrealistic kind of incident, a TRANSFER to a planet may +only be made in the post-arrival phase IF the planet is already inhabited by +the species making the transfer. Otherwise, the transfer will have to be +done in the pre-departure phase of the next turn. Once the colony has been +established, you may TRANSFER goods to the planet in either the pre-departure +or post-arrival phases.] + + +1.8 VICTORY CONDITIONS + +There are no final winners or losers in Far Horizons, just as there aren't any +in other role-playing games. The only purpose of the game is to have fun. +However, for those who want to know how well they did relative to the other +players, the following will be done: + + At the end of a game, a final summary report will be sent to all + players, and will contain a list of the total revenue-generating + capacity of each species along with their final tech levels and + other statistics. These values can be used to get a good idea + of who "won" the game. + +A game will last between 20 and 100 turns. The actual final turn number will +be randomly determined by the gamemaster and will be kept secret until the end +of the game is announced. This approach will prevent the unrealistic gameplay +that always results when players know that the game is about to end. The +gamemaster may arbitrarily and secretly extend the game if he feels it would be +inappropriate to interrupt an "interesting" situation, or if he is convinced +that everyone is having a lot of fun. + + + +2.0 STARS AND PLANETS + +As mentioned earlier, the galaxy of FAR HORIZONS is a small open star cluster, +similar to the Pleiades Cluster. + +In a real cluster, many of the stars would be components of binary or trinary +star systems. In fact, such multiple star systems make up about 85% of all +star systems in the Milky Way galaxy. In systems such as these, planets, if +any, are likely to have very odd orbits, and if they have atmospheres, their +climates are likely to be extremely erratic. As a result, multiple star +systems have been totally eliminated from the game. You can assume that they +exist, but they will not be shown on star maps or be made available for use +by players. + + +2.1 STARS + +The location of a star is indicated by its X, Y, and Z coordinates, which are +always positive integers greater than or equal to zero. I assume here that the +reader has sufficient technical background to understand how to work with these +coordinates (called Cartesian Coordinates). Just as a reminder, though, the +distance between any two stars can be calculated using the formula: + + 2 2 2 + distance = square root [ (X2 - X1) + (Y2 - Y1) + (Z2 - Z1) ] + + +Most distances can be estimated by simply looking at the map and counting +squares. Finicky players, however, may want to calculate exact distances using +the above formula. + +Any region of space defined by a set of specific X Y Z coordinates is called a +"sector". Thus, the number of sectors in the galaxy is simply the number of +possible combinations of X, Y, and Z. Most sectors are effectively empty. +Only a relatively small number of sectors contain usable stars and planets. + + +2.1.1 SPECTRAL CLASS + +The information in this section is for "color" only, and does not play an +important role in the game. Feel free to skim through it. Do not let the +technical jargon bother you. + +In addition to its galactic coordinates, a star is identified by its spectral +class, which indicates both its color and its size. In general, stars which +radiate more towards the red end of the spectrum are smaller than those which +radiate more towards the blue end of the spectrum. There are, however, many +exceptions. It is not uncommon to find red giants or blue dwarves. Also, in +general, large stars will have more usable planets than small stars. + +Here is a list of the most common spectral colors: + + O - Blue stars, hottest and largest (eg. Lambda Orionis) + B - Blue-white (eg. Rigel, Spica) + A - White (eg. Sirius, Vega) + F - Yellow-white (eg. Canopus, Procyon) + G - Yellow (eg. Earth's sun, Capella)) + K - Orange (eg. Arcturus, Pollux) + M - Red stars, coolest and smallest (eg. Antares, Betelgeuse) + +Here is a list of the most common spectral types: + + (not marked) - main sequence star + d - ordinary dwarf star + g - ordinary giant star + D - degenerate dwarf star + +Each class contains ten subdivisions numbered 0 through 9. Thus an F5 star is +approximately halfway between F0 and G0. Zero indicates the hottest within the +spectral class, while 9 indicates the coolest with the class. + +Here are some examples: + + O8 Blue + dF1 Yellow-white dwarf + DA5 Degenerate white dwarf + G6 Yellow + gG9 Yellow giant + dM5 red dwarf + DB Degenerate blue-white dwarf + gK7 Orange giant + +(It is customary to drop the number in the designation of degenerate dwarf +stars. Thus, in the astronomical literature, one is more likely to see "DA" +rather than "DA5". I have left them in, however, for consistency.) + +The star map which you will receive from the gamemaster will be two- +dimensional, and will show X and Y coordinates on the axes. If a star exists +at a particular X,Y coordinate, then a number and a spectral type will be +displayed at that location. The number will be the Z coordinate. Thus, +if you see the following: + + 12 + gF6 + +at the position on the map where X=5 and Y=9, it indicates that a giant yellow- +white star is located at coordinates X=5, Y=9, Z=12. + + +2.2 PLANETS + +Planets are real estate, and are the ultimate source of all wealth and power in +the game. As a result, planets are also the most common cause of interstellar +conflict. + +In the following sections, the various terms used to describe a planet's +physical characteristics will be discussed. It is by evaluating these +characteristics that a player can decide if a planet is suitable for +colonization and/or exploitation by his species. For reference, here is +a sample of a star system scan: + + +Coordinates: x = 7 y = 10 z = 18 stellar type = A0 8 planets. + + Temp Press Mining + # Dia Grav Class Class Diff LSN Atmosphere + --------------------------------------------------------------------- + 1 5 0.28 23 3 0.37 42 Cl2(100%) + 2 14 0.80 23 6 0.38 39 F2(33%),H2O(67%) + 3 12 0.91 18 9 0.65 24 HCl(38%),Cl2(32%),F2(30%) + 4 21 2.00 15 6 0.38 24 CO2(29%),HCl(43%),Cl2(17%),F2(11%) + 5 14 0.96 10 9 2.25 0 N2(47%),CO2(23%),O2(30%) + 6 189 2.67 4 18 4.34 33 CH4(49%),NH3(48%),N2(3%) + 7 103 1.94 3 17 0.49 33 H2(58%),CH4(42%) + 8 34 2.46 3 11 0.77 21 He(40%),N2(60%) + + +2.2.1 PLANET NUMBER + +Each planet has a number, indicating its relative position around the sun. +Planet number 1 is closest to the sun. The planet with the largest number is +farthest from the sun. Actual distances are not important for game purposes. +In the above sample, there are eight planets numbered 1 through 8. + + +2.2.2 PLANET DIAMETER + +A planet's diameter is listed under "Dia" and is the diameter of the planet in +thousands of kilometers. Thus, in the above sample, planet #5 has a diameter +of 14,000 kilometers. (For comparison, Earth has a diameter of approximately +13,000 kilometers, and Jupiter has a diameter of about 143,000 kilometers.) + + +2.2.3 PLANET GRAVITY + +A planet's gravity is listed in the "Grav" column, and is given in standard +Earth gravities. Thus, Earth would have a value of 1.00. In the above sample, +a person standing on the surface of planet #4 would weigh twice as much as on +Earth. + + +2.2.4 TEMPERATURE CLASS + +A planet's temperature class is listed in the "Temp Class" column and can have +one of the following values: + + Temp. Deg. Temp. Deg. + Class (C) Examples Class (C) Examples + ---------------------------------------------------------------- + 1 -273 Pluto, absolute zero 16 180 + 2 -240 Mercury (dark side) 17 210 + 3 -210 Neptune 18 240 + 4 -180 Titan (moon of Saturn) 19 270 + 5 -150 Uranus, Saturn 20 300 + 6 -120 Jupiter 21 330 + 7 -90 22 360 + 8 -60 23 390 + 9 -30 Mars 24 420 + 10 0 25 450 Venus + 11 30 Earth 26 480 + 12 60 27 510 Mercury + 13 90 28 540 + 14 120 29 570 + 15 150 30 600 + +The temperatures listed in the table are approximate, average temperatures that +can be experienced on the surface of the planet. Colonies are more likely to +prosper if the temperature class of a planet is as close as possible to that of +the home planet. If this is not the case, life support technology will have to +be applied to produce an artificial environment for the colony. + + +2.2.5 PRESSURE CLASS + +A planet's pressure class is listed in the "Press Class" column and can have +one of the following values: + + Press. Press. + Class Pressure Examples Class Pressure Examples + ------------------------------------------------------------- + 0 0.0000 Mercury,vacuum 15 32 + 1 0.0020 16 64 + 2 0.0039 17 128 + 3 0.0078 Mars 18 256 + 4 0.0156 19 512 + 5 0.0312 20 1024 Saturn + 6 0.0625 21 2048 + 7 0.125 22 4096 + 8 0.25 23 8192 + 9 0.5 24 16384 + 10 1 Earth 25 32768 + 11 2 Uranus 26 65536 Jupiter + 12 4 27 131072 + 13 8 Neptune 28 262144 + 14 16 Venus 29 524288 + +The pressures listed in the above table are multiples of Earth "atmospheres" +and are approximate, average values that can be experienced on the surface of +the planet. Colonies are more likely to prosper if the pressure class of a +planet is as close as possible to that of the home planet. If this is not the +case, life support technology will have to be applied to produce an artificial +environment for the colony. + + +2.2.6 MINING DIFFICULTY + +A planet's mining difficulty is listed under "Mining Diff". Mining difficulty +is a relative figure-of-merit which indicates how difficult it is to extract +or utilize a planet's natural resources. Higher values represent greater +difficulties. This value will be used to determine how much raw materials +can be produced on a planet during each game turn. + + +2.2.7 LIFE SUPPORT NEEDED (LSN) + +The number in the column labeled "LSN" is the amount of Life Support technology +that your species needs to survive on the planet. If your Life Support tech +level is lower than this value, then your species may not safely colonize the +planet, and any attempt to colonize the planet will result in the destruction +of the colony. If your Life Support tech level is equal to or greater than +this value, then your species may safely colonize the planet. We will discuss +later how these values are determined. + +Keep in mind that these values apply only to the species that does the scan. +If you receive a scan from another player, the LSN values will probably not +apply to your species. + + +2.2.8 PLANETARY ATMOSPHERE + +A planetary atmosphere will be described in terms of the gases that are its +major components. Each gas in the atmosphere will have a percentage value +associated with it. The following gases and their symbols are used in this +game: + + H2 Hydrogen + CH4 Methane + He Helium + NH3 Ammonia + N2 Nitrogen + CO2 Carbon Dioxide + O2 Oxygen + HCl Hydrogen Chloride + Cl2 Chlorine + F2 Fluorine + H2O Water Vapor or Steam + SO2 Sulfur Dioxide + H2S Hydrogen Sulfide + +For example, an Earth-type atmosphere would be described as N2(78%), O2(22%). +This means that Earth's atmosphere consists of approximately 78% Nitrogen and +22% Oxygen. + + +2.2.9 FURTHER NOTES ON TEMPERATURE, PRESSURE, AND ATMOSPHERE + +The temperature, pressure, and gaseous components of a planet are the prime +criteria by which you can decide if the planet is suitable for colonization by +your species. Furthermore, there are many possible combinations, and finding +a planet that closely matches your home planet will not be easy. + +For planets with a pressure class greater than about 20, the gases in the +atmosphere will usually condense into liquids, and will often even solidify as +you get closer to the surface. On these planets, there is often no clear +distinction between the atmosphere and the solid surface. These planets are +usually gas giants. Only the most intrepid and advanced species would ever try +to colonize the surface of such a planet since it is so inherently hostile to +life. Because of this, any colonies that you do establish "on" such planets +will actually be on moons orbiting the planet, artificial satellites, etc. + +If you wish to colonize or exploit a planet that is unsuitable for your +species, then some form of life support must be provided. This is where your +Life Support tech level will play an important part. A low value for this +technology will give you few options - you will have to search longer and +farther from home to find a planet that is suitable for colonizing. As your +Life Support tech level increases, you will have a wider range of options. + +Another possibility open to a species is to actually modify or "terraform" the +planet. This can be done by seeding the atmosphere with specially designed +micro-organisms, and by operating large plants on the surface that will convert +the atmosphere to something more suitable. Both temperature and pressure +classes can also be changed in this way. However, terraforming is available +only to species with relatively high Biology tech levels. + + + +3.0 SETTING UP FOR THE GAME + +When a player is ready to enter the game, he must fill out a Set-up Form and +send it to the gamemaster. The form is in Appendix D. The following sections +explain how to fill it out. + + +3.1 TECH LEVEL POINT ALLOCATION + +A starting player has a total of 15 points that can be allocated to Military, +Gravitics, Life Support, and Biology tech levels. Any combination is allowable +as long as they add up to 15. + +A tech level can even be zero if you decide that your species has no knowledge +in that area. If Gravitics tech level is zero, then you may only build sub- +light ships. If your Life Support tech level is zero, then none of your ships +will have defensive shields. If a tech level is zero, then it can only be +raised if another species transfers the knowledge to you. We'll discuss how +to do this later. + +All species start the game with Mining and Manufacturing equal to 10. + + +3.2 SPECIES, HOME PLANET AND GOVERNMENT + +Choose a name for your species. It can be something out of science fiction or +something you make up. Feel free to use your imagination! Examples: Human, +Kenda Jo, Klingon, Graxian, Jubjub Denboy, Ferengi, Mo Ja'adebi, etc. + +Choose a name for your home planet. Examples: Earth, Mars, Barsoom, Dune, +Giver of Life, Korunkorunkoruniman, Toi di Bai, etc. + +Choose a name for your government or political system. Examples: The United +States of America, The Korun Federation, The Holy Alliance of Denadan, The +Jubjub Denboy Empire, etc. + +All of the above names are limited to 31 characters and will be truncated if +they are longer. When referring to them later, case will not be significant. +Names may contain spaces and any printable characters except commas and +semi-colons. ALL characters in a name, including spaces, are included +in the 31-character limit. Names may NOT contain tabs! + +Name the type of government or political system of your species. (In this +game, we assume that all planets owned by a species are run by a single +government.) Be descriptive but limit yourself to 31 characters. Examples: +Libertarian Democracy, Communist Totalitarianism, Constitutional Monarchy, +Absolute Dictatorship, Benevolent Plutocracy, Slaver Republic, Ruthless +Oligarchy, Theocratic Monarchy, Military Republic, etc. + +The political system you choose could have an impact on the game, since species +may react to each other differently, depending on ideology. Also, since Far +Horizons is a role-playing game, the player should always operate within the +limitations imposed by the type of government he chooses. + + +3.3 PROCESSING TURNS + +After the gamemaster has received your set-up information, he will either send +you a map of the galaxy or he'll tell you where you can obtain a copy via ftp. +He will also send you a status report which contains a detailed description of +your home planet and its production capabilities. At the end of the status +report, there will be an order form that you can fill out for your first turn. + +In the following sections, we will discuss these items in more detail. + + +3.4 STAR SYSTEM DATA + +The star system data sent to you for the first turn provides a detailed +description of the home star system. Refer to Chapter 2 if you have any +problem deciphering the information. + +Star system data can be provided to you for every star system that your species +visits. However, you will not receive this information automatically, but must +specifically request a "scan". This can be done in the pre-departure or post- +arrival section of the orders you send to the gamemaster. (We'll have more to +say about the 'scan' command later.) + + +3.5 SPECIES STATUS REPORT + +This section of the information sent to you describes your species' current +situation. At the start of a game, you will not have any planetary defenses, +ships, etc. You start the game with a blank slate. You DO, however, have +mining and manufacturing capability which you can start using immediately +to build ships and other items. + +Names of items that are available for use on a planet will be printed out in +full, along with their class abbreviation, required carrying capacity, and +quantity. For example: + + Raw Material Units (RM,C1) = 17 + +The above example indicates that the planet has 17 unused raw material units, +which require a carrying capacity of 1 each, and have the abbreviation "RM". +(We'll have more to say about raw material units and carrying capacity later.) + +Ages of ships and their orbital status will be indicated as in the following +example: + + CT Derby Dan (A5,O6) + +Here, "CT" is the abbreviation for a corvette. "A5" indicates that the age +of the ship is 5 turns. The letter "O6" indicates that the ship is in orbit +around planet number 6 (as opposed to being landed on the surface). If a ship +is on the surface (i.e., "landed"), then "L" will be used. If a ship is in +deep space, not associated with any planet, the letter "D" will be used. If a +ship voluntarily withdrew from combat during the strike phase, then "WD" will +be used. If a ship was forced to jump using Forced Jump Units during the +strike phase, then "FJ" will be used. If a ship is still under construction, +then the complete designation will be simply "(C)". (We'll have more to say +about landing, orbiting, and combat later.) + +The rest of the status section is intended to be self-explanatory. It +indicates what your current Mining and Manufacturing Bases are and how much +you can produce in the current turn. (Abbreviations MI = Mining Tech Level, +MA = Manufacturing Tech Level, and MD = Mining Difficulty.) How to use this +data will be described later. The atmospheric requirements and the list of +gases poisonous and harmless to your species will be used later in the game +to decide whether or not other planets are suitable for colonization. How +to colonize planets will be described later. + + +3.6 NOMENCLATURE + +In order to make turn-processing as easy as possible for the gamemaster, and to +allow as much processing as possible to be done by the computer, certain naming +conventions have been established. Players should be careful to follow these +conventions carefully. + +All items in the game have a 2-5 letter abbreviation. For example, heavy +cruisers use the designation "CA", while starbases use "BAS". These class +designations should ALWAYS be used when giving orders for the items. + +Ship and planet names are limited to 31 characters and will be truncated if +they are longer. Case is not significant. Thus, the following names for a +heavy cruiser are all the same: + + CA USS Enterprise + ca uss enterprise + CA USS ENTERPRISE + +The particular upper/lower case combination that you use the first time you +name a ship or planet will be used in all subsequent reports. You may use +ANY combination, however, in subsequent orders. + +Names may contain spaces and any printable characters except commas and +semi-colons. ALL characters in a name, including spaces, are included in +the 31 character limit. + + + +4.0 MINING AND MANUFACTURING + +In order to explore the galaxy, you will need spaceships, among other things. +The following sections will discuss how mining and manufacturing are used to +produce the items you will need. + + +4.1 RAW MATERIAL UNITS + +As was mentioned earlier, Mining tech level does not apply strictly to mining, +but also includes such operations as drilling for oil, refining metals, +growing, harvesting, and processing crops, etc. In other words, it is a +generic term that covers all aspects of tapping a planet's natural resources. +This technology is used to produce all of the raw materials that, in turn, are +used for final production. Thus, mining technology produces raw materials and +manufacturing technology consumes them. + +In FAR HORIZONS, quantities of raw materials are measured in RAW MATERIAL +UNITS. The number of raw material units that can be produced on a planet in a +single turn is: + + Mining Tech Level x Mining Base + Raw Material Units = ----------------------------------- + Mining Difficulty + +MINING BASE is a relative measure of the total physical plant, acreage, +infrastructure, etc. that is available on the planet for the production of +raw materials. Thus, it is a measure of how many mines, farms, drilling +facilities, steel mills, etc that can be used by the planet's population. + +For example, if your mining tech level is 4, your mining base is 136 and the +planet's mining difficulty is 1.24, then you can produce + + 4 x 136 + --------- = 438.71 = 438 raw material units + 1.24 + +in the current turn. Note that fractions are always dropped. Since current +values are always shown on status reports that are sent to players, it will +NOT be necessary for players to do these calculations. + +The mining base on all home planets will automatically increase by about 2% per +turn. On colonies, however, the mining base can only be increased by shipping +in colonists and installing colonial mining units (we'll have more to say about +this later). This, in fact, is how colonies are actually started. + +When referring to raw material units in orders which you send to the +gamemaster, use the abbreviation "RM". We'll have more to say about this +later. + +Finally, unused raw material units may be carried over into later turns. In +effect, such carry-over is the equivalent of long term storage and stockpiling. + + +4.2 PRODUCTION CAPACITY + +A species' PRODUCTION CAPACITY is a measure of its ability to convert raw +material units into final products. Specifically, it is a measure of the +number of raw material units that may be converted into usable products in +a single turn. This value is determined as follows: + + + Production Capacity = Manufacturing Tech Level x Manufacturing Base + + +MANUFACTURING BASE is a relative measure of the total physical plant available +on a planet for the conversion of raw material units into final products. +Thus, it is an indication of how many factories, dock yards, processing plants, +etc. that can be used by the planet's population. + +For example, if manufacturing tech level is 6 and manufacturing base is 142, +then + + + Production Capacity = 6 x 142 = 852 + + +in the current turn. Thus, the planet has the production capacity to "consume" +852 raw material units and "purchase" 852 units of final products. Since +current values are always shown on status reports that are sent to players, +it will NOT be necessary for players to do these calculations. + +The manufacturing base on all home planets will automatically increase by +about 2% per turn. On colonies, however, the manufacturing base can only be +increased by shipping in colonists and installing colonial manufacturing units +(we'll have more to say about this later). + +Production capacity can only be utilized at its maximum if sufficient raw +material units are available. You cannot convert what you don't have. +Furthermore, production capacity cannot be carried over into later turns. If +you don't utilize your full production capacity, then it simply means that +your production facilities are not operating at full capacity. + +It is possible to use raw materials in the same turn as they are produced. +They do not have to be stockpiled in earlier turns. Thus, the total number of +raw material units available for manufacturing in the current turn is the sum +of what was carried over from the previous turns plus what will be produced in +the current turn. + + + +5.0 PRODUCTION + +At the end of each status report that you receive, there will be an order form +which you must fill out and send to the gamemaster. In it you will provide +your orders for the current turn. The form has sections for combat orders, +pre-departure orders, jump orders, production orders, post-arrival orders, +and strike orders. + +At the start of a game, you will only be able to provide production orders +for one planet - your home planet. In later turns, you will need to fill +out orders for each planet on which you have production capacity. + +Production for each planet must be preceded by the order: + + PRODUCTION PL name + +where "PL" is the class abbreviation for a planet and "name" is the name of the +planet. This command indicates that the orders that follow apply only to the +indicated planet. Orders for each planet must be preceded by a PRODUCTION +command. + +Each section of the orders is started for you, and you must provide your +specific orders. For example, if your home planet is called "Earth", and you +have a colony called "Mars", the initial production section will look something +like this: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + PRODUCTION PL Mars + ; Enter your production orders for planet Mars here. + +END PRODUCTION + +Note that some lines begin with a semi-colon. The semi-colon indicates that +the line is actually a comment and that the computer should ignore it. You may +add comments of your own. Comments may appear anywhere and always start with a +semi-colon. Everything on a line that follows a semi-colon is ignored by the +computer. Completely blank lines are also ignored. + +Each order begins with a command word, such as "TRANSFER", "RESEARCH", etc. +These command words are not case sensitive and may be truncated to just the +first THREE letters. Any letters after the first three are ignored. Thus, all +of the following are equivalent to "RESEARCH": "reS", "RESEA", "REsoQQQ", etc. + +When a name (such as the name of a ship or planet) is not the last item on a +line, it should be terminated by a comma. This is necessary because names can +contain spaces. Thus, in the following example, the name "Laughing Dog" is +immediately followed by a comma: + + JUMP CT Laughing Dog, PL Shangri La + +Note though that "Shangri La" is NOT followed by a comma, since it is the last +item on the line. + + + WARNING! Omitting a required comma is one of the most common + mistakes made by players. It is also one of the most frustrating, + since the computer will reject the order. + + +You may use as many tabs and/or spaces as you wish to separate items in a +command to make it more readable. Tabs and spaces at the very beginning of a +command line are ignored. For example, the following are valid orders: + + Orbit FF Thomas Edison, PL Mars + JUMP PB Benjamin Franklin, 12 7 18 + +Tabs, like commas, will terminate a name. However, use of commas is +recommended because tabs are not always easily visible. Any spaces that +appear in a name will become part of the name. + +If a comment appears after an order on the same line, spaces and tabs that +precede the semi-colon are ignored. Thus, there is no need to terminate a name +with a comma if the name is immediately followed by a comment. For example: + + Jump TR7 Love Dove, PL Mars ;Deliver new colonists. + +Note that "Mars" is not followed by a comma, and that the spaces between "Mars" +and the semi-colon will not be considered as part of the name "Mars". + +Any items that you may wish to build, such as ships, planetary defenses, etc. +will have a "cost" of equal amounts of raw material units and production +capacity. Thus, if you wish to build a spaceship with a cost of 200, then +a total of 200 raw material units will be used in its construction, and a +total production capacity of 200 will be needed to actually build it. + +Except for ships, all items must be built in a single turn. You can take as +many turns as you like to build ships. Thus, if we continue the above example, +you could build the ship in, say, 4 turns. You could allocate 100 raw material +units and production capacity in the first turn, 70 in the second turn, 0 in +the third turn, and 30 in the fourth turn. + +Finally, keep in mind that raw material units and production capacity must +always be spent in equal amounts. Thus, for example, if your production +capacity is greater than the number of raw material units, then the excess may +not be used. Also keep in mind that unused raw material units MAY be carried +over into later turns, but that unused production capacity may NOT. + + +5.1 SPACESHIPS + +Spaceships come in all sizes as can be seen in the following table: + + Minimum Carrying Cost + MA Abbr Class Tonnage Capacity FTL Sub-light + --------------------------------------------------------------------------- + 2 PB Picketboat 10,000 1 100 75 + 4 CT Corvette 20,000 2 200 150 + 10 ES Escort 50,000 5 500 375 + 20 FF Frigate 100,000 10 1000 750 + 30 DD Destroyer 150,000 15 1500 1125 + 40 CL Light Cruiser 200,000 20 2000 1500 + 50 CS Strike Cruiser 250,000 25 2500 1875 + 60 CA Heavy Cruiser 300,000 30 3000 2250 + 70 CC Command Cruiser 350,000 35 3500 2625 + 80 BC Battlecruiser 400,000 40 4000 3000 + 90 BS Battleship 450,000 45 4500 3375 + 100 DN Dreadnought 500,000 50 5000 3750 + 110 SD Super Dreadnought 550,000 55 5500 4125 + 120 BM Battlemoon 600,000 60 6000 4500 + 130 BW Battleworld 650,000 65 6500 4875 + 140 BR Battlestar 700,000 70 7000 5250 + +"Minimum MA" is the minimum Manufacturing tech level that a species must have +before it is capable of building a ship of the corresponding tonnage. For +example, a species must have a Manufacturing tech level of 40 or higher in +order to be able to build a light cruiser. + +"Abbr" is the abbreviation that will be used for the corresponding class of +ship. The correct abbreviation must ALWAYS be used when making reference to +a specific ship. Thus, if you build a battleship named "USS Iowa", you must +always refer to it as BS USS Iowa. You are free to give your ships whatever +names you wish, as long as you conform to some simple naming conventions that +will be discussed later. + +"Tonnage" is the ship's fully loaded deadweight in long tons in standard +gravity. (Note that the maximum tonnage that a species can handle is equal +to 5000 times the Manufacturing tech level.) + +"Carrying Capacity" is the amount of cargo units or colonist units units that +a ship can carry. More will be said about this later. (Note that carrying +capacity is equal to the tonnage divided by 10,000.) + +"FTL Cost" is the number of raw material units and production capacity needed +to build a ship capable of interstellar travel (FTL stands for "Faster-than- +light"). (Note that the FTL cost is equal to the tonnage divided by 100.) + +"Sub-light Cost" is the number of raw material units and production capacity +needed to build a ship that is NOT capable of interstellar travel. These ships +have all of the capabilities of the equivalent FTL ship, except that they must +either remain in the star system in which they were constructed, or move very +slowly from one sector to the next. (Note that the sub-light ship cost is +equal to the FTL cost minus 25%.) + +To build ships, use the BUILD command, and be careful to use the correct class +abbreviation. For example: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + ;Build sub-light frigate and pay for all of it now. Cost is 750. + BUILD FFS Farragut + + ;Build light cruiser. Pay one-quarter now (500) and the rest (1500) + ; later... + BUILD CL Guardian, 500 + +END PRODUCTION + +Note that if a payment amount is not specified, then the ship will be +completely built. The computer will calculate the needed cost. You will, of +course, have to keep track of the costs yourself to make sure that you don't +try to spend more than what you have. + +To continue construction on a ship, use the CONTINUE command, as in the +following examples: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + ;Pay 1250 more on the dreadnought we started a while back... + CONTINUE DN Dynamite Dan, 1250 + + ;Finish the light cruiser we started last turn... + CONTIN CL Guardian + +END PRODUCTION + +If you do not specify the amount to spend, then the computer will calculate +the cost needed to finish construction. + +NEVER use the same name for two different ships, even if their classes are +different. For example, if corvette "CT Danny Boy" already exists, then an +order to build frigate "FF Danny Boy" will fail. + + +5.2 COMBAT EFFECTIVENESS + +In this section, we will digress slighlty and consider just how effective the +above-listed ships would be in combat situations. + +In a game where each turn is five years long, any rules regarding combat must, +of necessity, be highly abstract. Furthermore, FAR HORIZONS is a strategic +game, as opposed to a tactical game. And since the game must be played by +mail, it is not possible for players to be directly involved in the details of +space combat. As a result, the outcome of all battles must be determined by +the gamemaster's computer. + +Whenever combat does occur, the computer will assign probabilities defining +each side's offensive and defensive potentials. Offensive potentials will +depend most heavily on the numbers and sizes of the ships (i.e. how much +firepower is available) and their Military tech levels (i.e. how effective +their weaponry and tactics are). Defensive potentials will depend most heavily +on the sizes of the ships (i.e. how much armor and defensive shield generators +can be carried) and their Life Support tech level (since the design of shields +is an application of life support technology). + +MOST IMPORTANTLY, a single, large ship has MUCH more offensive and defensive +capability than several smaller ships of the same total tonnage. For example, +a single frigate (100,000 tons) could EASILY destroy a fleet of five corvettes +(20,000 tons each) or ten picketboats (10,000 tons each) if tech levels are +about the same. + +Each battle will consist of one or more "rounds", during which ships on either +side may be damaged or destroyed. The battle will proceed until one side is +destroyed or forced to leave. + +Thus, the players will not be directly involved in determining the outcome +of a battle. Only the results of a battle will be reported to them, on their +status reports. + + +5.3 PLANETARY DEFENSES + +Planetary defenses are intended to protect a planet from attack by enemy ships. +They can attack and be attacked by ships in space near the planet. A planet +may not be controlled by an invading force until all planetary defenses have +been destroyed. Planetary defenses can also be used in besieging a planet if +they are on the planet that is under siege. + +In this game, we will not be concerned with the number, location or strength of +the individual bases and facilities that make up a planet's planetary defenses. +If a planet is attacked, only the total planetary defense strength is +important. + +Specifically, each planetary defense unit will have a cost of 1, and will have +the combat "value" of a 50 ton FTL warship. For example, if a planet has +produced 2000 planetary defense units (at a total cost of 2000), then it will +have the same combat effectiveness as a 100,000 ton frigate. + +At first glance, it might seem that planetary defenses are not very effective +for the amount spent in their construction. Keep in mind, though, that +planetary defenses can grow without limit, becoming more and more powerful at +each step in their growth. Also, planetary defenses are not limited in size +by the species' Manufacturing tech level, as ships are. And, as we will see +later, planetary defenses don't suffer from aging effects. + +When referring to planetary defenses in orders, use the abbreviation "PD". +Each planetary defense unit requires a cargo capacity of 3. + +To construct planetary defenses, use the BUILD command, as in the following +examples: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + Build 102 PD ; Build 102 planetary defense units. Total cost = 102. + + PRODUCTION PL Vega VI + ; Enter your production orders for planet Vega VI here. + + BUI 55 pd ; Build 55 planetary defense units. Total cost = 55. + +END PRODUCTION + +The units produced will remain on the producing planet unless they are +transferred elsewhere. + + +5.4 TRANSPORTS + +Transports are ships that are specially designed to carry colonists and cargo. +They CAN take part in combat, but their offensive and defensive capabilities +are about one-tenth that of warships. (As indicated in the warship list above, +warships also have carrying capacity, but it is much less than a transport of +the same tonnage.) + +Transports can be built in any multiple of 10,000 tons. The maximum tonnage, +as for other ships, is 5000 times the Manufacturing tech level. + +The carrying capacity of a transport is the total number of colonist units or +cargo units (or combination thereof) that a transport can carry at any one +time. Colonist units will be discussed later. A cargo unit is the equivalent +of one raw material unit. For example, a transport with a carrying capacity +of 200 could carry 90 colonist units and 110 raw material units. Transports +should use the class abbreviation "TRn", where "n" is the tonnage divided by +10,000. + +The carrying capacity of a transport is calculated as follows: + + + Transport Carrying Capacity = (10 + n/2) x n + + +For example, a TR7 (i.e. a 70,000 ton transport) has a carrying capacity of +(10 + 7/2) x 7 = (10 + 3) x 7 = 91. Note that fractions are dropped in the +division. + +Here are some more examples: + + Minimum Carrying Cost + MA Abbr Tonnage Capacity FTL Sub-light + ------------------------------------------------------------ + 2 TR1 10,000 10 100 75 + 4 TR2 20,000 22 200 150 + 10 TR5 50,000 60 500 375 + 12 TR6 60,000 78 600 450 + 20 TR10 100,000 150 1000 750 + 30 TR15 150,000 255 1500 1125 + 40 TR20 200,000 400 2000 1500 + 100 TR50 500,000 1750 5000 3750 + 120 TR60 600,000 2400 6000 4500 + +You may build a transport of any tonnage as long as it is a multiple of 10,000, +and as long as your Manufacturing tech level is high enough. Note that you do +NOT have to calculate the carrying capacity of ships each time you give orders +for the ships, since all capacities are listed on your status reports. + +To build transports, use the BUILD command, and be careful to use the correct +class abbreviation. For example: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + ;Build sub-light transport and pay for all of it now. Cost is 750. + BUILD TR10S Barrel of Monkeys + + ;Build 40,000 ton transport. Pay one-quarter now (100) and the + ; rest (300) later... + BUILD TR4 Tummy Tunes, 100 + +END PRODUCTION + +Note that if a payment amount is not specified, then the ship will be +completely built. The computer will calculate the needed cost. You will, of +course, have to keep track of the costs yourself to make sure that you don't +try to spend more than what you have. + +To continue construction on a transport, use the CONTINUE command, as in the +following example: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + ;Finish the 40,000 ton transport we started in the last turn. + ; Since we only paid 100 then, we must now pay 300. + Cont TR4 Tummy Tunes + + ; Pay an additional 500 on the 200,000 ton transport we started a + ; few turns ago. + CON TR20 Tunnel of Love, 500 + +END PRODUCTION + +NEVER use the same name for two different ships/transports, even if their +classes are different. For example, if frigate "FF Danny Boy" already +exists, then an order to build transport "TR8 Danny Boy" will fail. + + +5.5 MORE ON SUB-LIGHT SHIPS + +As mentioned above, sub-light ships have all of the capabilities of FTL ships +of the same tonnage. However, their cost is 25% less because they do not +have the engines that allow them to make interstellar jumps. Thus, they +are primarily intended for local use. + +Sub-light ships should add the letter "S" to their class abbreviations. For +example, a sub-light frigate would have the class designator "FFS", a sub-light +40,000 ton transport would use "TR4S", etc. + + +5.6 STARBASES + +Starbases are essentially floating fortresses. Unless towed, they cannot +move under their own power, but must remain in orbit around a planet. + +Once construction has started, a starbase may be added to indefinitely. +However, the total tonnage cannot exceed the maximum tonnage allowed by +a species' Manufacturing tech level. This limit is exactly the same as +for ships; i.e., the maximum tonnage of a starbase is 5000 times the +Manufacturing tech level. + +Starbases are constructed in the same way as ships. The player simply places +an order for a starbase of a specific tonnage, or for additional tonnage to +be added to an existing starbase. The cost is the same as the equivalent FTL +ship tonnage; i.e., tonnage divided by 100. Starbases must always be built +or incremented in multiples of 10,000 tons. For example, it would cost +20,000/100 = 200 to built a starbase of 20,000 tons. To increase its tonnage +to 50,000 tons would require an additional cost of (50,000-20,000)/100=300. +Thus, the amount spent must always be an exact multiple of 100. + +A starbase built using the normal production capacity of a planet must be +built in orbit around that planet. (We will discuss another way of building +starbases later.) + +The carrying capacity of a starbase is determined as follows: + + Tonnage + Starbase Carrying Capacity = ----------- + 1000 + +Overall, the combat effectiveness of a starbase is exactly the same as a +warship of the same tonnage. Thus, a 150,000 ton starbase and a 150,000 ton +destroyer would fight as equals. + +[A starbase is not maneuverable and is thus a sitting duck. It is also limited +in its choice of targets. This, however, is compensated for by more powerful +shield generators and weaponry. Thus, it is probably best to think of the +tonnage of a starbase as an 'effective' tonnage rather than an actual tonnage. +The actual tonnage will almost certainly be much higher. By using an effective +tonnage in the game, we can easily compare the combat effectiveness of +starbases relative to other ships.] + +Starbases in orbit around a planet may be towed into orbit around another +planet in the SAME star system. It is not necessary to allocate individual +ships to do this - it is assumed that the starbase itself has sufficient +shuttlecraft to do it. In the same way, starbases may also be towed up to one +parsec per turn at sub-light speeds; i.e. to an immediately adjacent sector. +We'll discuss how to do this later. + +The class abbreviation "BAS" should always be used for starbases. For example, +you could refer to a starbase as BAS Deep Space 9 or BAS High Guardian. + +To build starbases, also use the BUILD command. Since starbases must be built +in increments of 10,000 tons (which has a cost of 100), anything spent on +building a starbase must be an exact multiple of 100. For example: + +START PRODUCTION + PRODUCTION PL Bakupa + ; Enter your production orders for planet Bakupa here. + + ;Build a new 20,000 ton starbase... + BUILD BAS Misty Na Goba, 200 + +END PRODUCTION + +Note that a payment amount must ALWAYS be specified when constructing +starbases, and the amount must always be an exact multiple of 100. + +To increase the size of an existing starbase, use the CONTINUE command, as in +the following examples: + +START PRODUCTION + PRODUCTION PL Bakupa + ; Enter your production orders for planet Bakupa here. + + ; Increase size of starbase by 40,000 tons... + CONT BAS Misty Na Goba, 400 + +END PRODUCTION + +NEVER use the same name for two different ships/starbases, even if their +classes are different. For example, if frigate "FF Danny Boy" already +exists, then an order to build starbase "BAS Danny Boy" will fail. + + +5.7 RESEARCH + +Tech levels may be increased by spending equal amounts of raw material units +and production capacity on research. You may spend any amount you wish on any +or all tech levels. For example, you could spend 25 on Military tech level and +433 on Biology tech level in a particular turn. + +There is no guarantee, however, that research will result in an increase in +a tech level. The results of scientific research are never predictable. + +When a tech level increases, the increased knowledge is available for use on +all of the planets owned by the species. Thus, even though research may be +done on just one planet, its benefits are available to the entire species. + +There is no limit on how high a tech level can be, but in practice tech levels +are unlikely to exceed 100. + +You may spend any amount on any tech level. The command to allocate resources +to research is RESEARCH. For example: + +START PRODUCTION + PRODUCTION PL Deneb VII + ; Enter your production orders for planet Deneb VII here. + + ; Spend 27 on Biology research... + RESEARCH 27 BI + + Res 1255 LS ; Spend 1255 on Life Support research. + +END PRODUCTION + +Use the following abbreviations for tech levels: + + MI - Mining + MA - Manufacturing + ML - Military + GV - Gravitics + LS - Life Support + BI - Biology + +Spending on research does not guarantee success. In general, the more you +spend, the greater your chance of success will be, and the greater the increase +is likely to be. Keep in mind, though, that the process is very unpredictable. +Do not be disappointed if you spend a lot on research but experience no +increase in tech level, and do not be surprised if you spend very little +and experience a large increase. + +It is also possible for a tech level to rise without spending funds on +research. This increase comes from research done by the private sector. +In effect, the government gets some technology for free, just as the private +sector gets technology for free as a result of government research. In +general, tech increases from the private sector will not be very large, +so you should not depend too much on them. + + + IMPORTANT !!! + + You may not raise a tech level using research, nor will you + receive free tech increases from the private sector, if your + initial tech level is zero. If a tech level is zero, you + must first have the basics of the technology taught to you + by another species using the TEACH command. + + +We'll have more to say about the TEACH command later. + + +5.8 ECONOMIC UNITS + +It is expected that there will eventually be a thriving galactic economy, with +lots of trade taking place between species. This trade is transparent to +the player, who is primarily concerned with government and military matters. +Still, there must be a way to transfer wealth between planets owned by one +species and between different species, as, for example, when one nation on +Earth sends "aid" to another. In FAR HORIZONS, this type of transfer is +done using a special type of item called an "Economic Unit". + +Unlike other items, however, economic units are more like money or bank +balances, and may be transferred freely between planets without the need for +ships or cargo capacity. Economic units may even be transferred between +species. + +In Far Horizons, each species has the equivalent of a bank account which +contains zero or more economic units. + +If a species has economic units, they may be spent just as if each unit were +the equivalent of 1 raw material unit and a production capacity of 1. During +production on a planet, economic units owned by the species will be used +automatically (if available) if orders are given which require more than the +available production capacity of the planet. For example, if a planet can +spend 500 using normal production, plus the species has 150 economic units, +then the planet can spend a total of 650 for construction of ships and other +items. In other words, normal production capacity will be used up first, and +economic units will only be spent if there is insufficient normal capacity. + +However, there has to be a limit on how many economic units a colony can spend. +For example, it makes no sense to try to spend a large sum of 'money' on a +small colony. A small colony simply does not have an economy that is robust +enough to deal with large sums of 'money'. + +So, in Far Horizons, the amount of economic units that a colony can spend in +addition to its normal production will be limited to what it can produce on its +own. For example, if a colony can spend 850 using normal production, then it +may ALSO spend up to 850 economic units from the species' treasury, for a total +of 1700. Thus, the robustness of the economy, measured by the amount of +economic units it can spend, will grow as the colony grows. + +There is no limit to how much may be spent on a home planet. + +Economic units may NOT be produced like other items using the BUILD command. +Instead, they are "produced" automatically on any planet that has unused raw +material units and an equal amount of unused production capacity. The "cost" +of one economic unit is 1 raw material unit and a production capacity of 1. +Thus, for example, if you need economic units to give to another species, then +simply do NOT spend an appropriate amount on one or more planets. + +Note that there is no need to explicitly transfer economic units between +planets that you control. Economic units owned by a species are available for +any planet that needs to spend them. Later, we'll discuss how to transfer +economic units to another species. + + +5.9 UPGRADES + +The successful operation of ships and other items often depends on the value of +a particular tech level. For example, the effectiveness of a ship in combat +will depend heavily on its Military tech level. For game purposes, everything +will function at the current tech levels for the species. This is unrealistic, +but it makes bookkeeping much easier. + +As a way of compensating for this lack of realism, ships and starbases will +also have an "age" associated with them. This age will be equal to the number +of turns that have passed since construction finished. For a starbase, the +effective age will be the weighted average of all of its contributions. All +other items, including planetary defenses, will not experience any aging +effects. + +The age of a ship will affect its operation as follows: whenever an operation +has a certain probability of success, that probability will be reduced by +a percentage equal to 2 times the effective age. For example, if a newly +constructed ship has a 98.17% chance of hitting an enemy target, then at the +age of 9 turns, its chance of success for the same shot would be 98.17 - (18% +of 98.17) = 80.50%. When a ship reaches the ripe old age of 49, it will remain +at that age, apparently held together by spit and glue. Obviously, a ship that +has reached the age of 49 will have a difficult time doing ANYTHING right! + +In a similar way, the age will also affect the firepower of weapons and the +absorption power of shields. + +Ages of ships and starbases will be listed in the status reports for the +species. + +An item's age may be reduced by having it upgraded (i.e., it will undergo a +retrofit). The amount of age reduction can be calculated with the following +formula: + + 40 x Amount Spent + Age Reduction = ------------------------------ + Original Cost + +Fractions will be dropped. + +Or, if you'd rather start with the age reduction, then the corresponding cost +can be determined using the following formula: + + Desired Age Reduction x Original Cost + Cost of Upgrade = ---------------------------------------------- + 40 + +If the result has a fraction, it should be rounded UP to the next whole number. +For a starbase, the original cost is considered to be the current tonnage +divided by 100. + +For example, to completely upgrade an 80,000 ton transport that has an +effective age of 17 turns would cost (17 x 800) / 40 = 340, and would reduce +its effective "age" to zero. To reduce the age of a 70,000 ton starbase +from 34 to 10 would cost (34 - 10) x 700 / 40 = 420. + +To upgrade a ship or starbase, use the UPGRADE command, as in the following +examples: + +START PRODUCTION + PRODUCTION PL Nushki Pata Pata + ; Enter your production orders for planet Nushki Pata Pata here. + + ; + ; Let's keep that old light cruiser a little longer. If we spend 700, + ; we will reduce its age by 40 * 700 / 2000 = 14 turns. + ; + UPG CL Mighty Mouse, 700 + + ; Rejuvenate that old destroyer from age 23 to age 0. + upgr DD Dawson ; cost will be (23 x 1500)/40 = 863. + +END PRODUCTION + +If you do not specify the amount you wish to spend in the upgrade command, then +the age will be set to zero and the cost will be determined accordingly. + +There is never a need to upgrade planetary defense units since they do not +experience aging effects. + +A ship or starbase that is to be upgraded must be in the same sector as the +planet doing the upgrade, and the upgrade order must appear in the production +section for that planet. A ship cannot jump and be upgraded in the same turn, +since both jumping and upgrading require a complete turn. + +Finally, keep in mind that an upgraded ship will still get one year older +during the turn in which the upgrade is done. Thus, when you receive the +status report for the turn, the age of the above destroyer will be 1, NOT 0. + + +5.10 RECYCLING + +Most items may be recycled. When this is done, the item is effectively sold on +the open market, and an appropriate amount of 'money' is added to the treasury +of the species. The amount received will depend on the item that is recycled. +Ships and starbases will have values that depend on their age, while most +other items can be cashed in for half of their original cost. + +Mining and manufacturing bases may NOT be recycled. + +Recycling will add economic units to the balance for the species. For items +that do NOT suffer aging effects, the number of economic units gained will be +half the original cost (fractions will be dropped). The only exception to +this is for raw material units, which will be cashed in at the rate 1:5 (for +example, recycling 29 RMs will generate 5 economic units). + +For ships and starbases, the amount of economic units generated will be: + + + 3 x original cost (60 - age) + ------------------- x ---------- + 4 50 + + +If a ship is still under construction, it may be recycled for half of what has +already been spent on it. If a ship is carrying cargo, the cargo will first be +transferred to the planet before the ship is recycled (cargo, if any, is NOT +automatically recycled). + +To recycle ships, starbases and other items, use the RECYCLE command, as in the +following examples: + +START PRODUCTION + PRODUCTION PL Knock Out + ; Enter your production orders for planet Knock Out here. + + ; Let's recycle some stuff we don't need... + ; + ; Get rid of those old corvettes. + ; + RECYCLE CT Dragon + recycle CT Princess + ; + ;Next, I don't need so many planetary defense units... + ; + rec 20 pd + +END PRODUCTION + +If colonist units or planetary defense units are recycled, the available +population for the planet will be increased by the number of units recycled. +This will allow you to convert CUs to PDs or vice-versa. + +Recycling is a good way to get rid of old, unreliable ships and starbases. It +is also good for getting rid of excessive amounts of raw material units. + +An item, ship, or starbase that is to be recycled must be on the planet or in +orbit around the planet, and the recycle order must appear in the production +section for that planet. Economic units generated by a RECYCLE command may be +spent in the same turn. Make sure, though, that the recycle command precedes +any other commands that will spend the money obtained by recycling. + +A ship cannot jump and be recycled in the same turn, since both jumping and +recycling require a complete turn. + + +5.11 RECYCLE OR UPGRADE - WHICH IS BEST? + +An important decision that players will have to make is whether to upgrade a +ship or to recycle it. There are several things to keep in mind when making +this decision: + + a. A large warship is much more effective in combat than several + smaller warships of the same total tonnage. This is a strong + incentive to recycle smaller warships, and use the proceeds to + build larger ones. + + b. Recycling is more cost effective as a ship gets older, but + the aging effects could have a serious negative impact on the + ship's operation. In purely financial terms, the crossover age + is about 15 turns; i.e., the fractional financial return from + recycling is the same as the fractional remaining useful lifetime + when the age of the ship is about 15 turns. + + c. Starbases require such a long time investment, that it is + never worthwhile to recycle them. In general, they should always + be upgraded. The only time you can justify recycling a starbase + is if you are forced to do so by an enemy, or if it was intended + originally for only temporary use. + + d. You may want to keep smaller, non-intimidating ships (such as + small transports) for exploration or spying. Thus, upgrading a + small number of these could be advantageous. + +So, as a general rule-of-thumb, it's a good idea to recycle warships and +transports of 40,000 tons or more when they reach the age of about 15. If +you're willing to sacrifice a small amount of the financial return for a little +more security, then recycle when the ship is slightly younger, say 10 or 12 +turns old. + +Starbases should almost always be upgraded. Recycle them only when you have +no choice or when you no longer need them. + +Small warships and transports (less than 40,000 tons) are great for exploration +and spying, and you may want to continually upgrade a few of them. Recycle +only if you have more than you need. If you explore or spy with anything +bigger (especially large warships), the aliens you visit may consider it a +hostile act. + +Another thing to keep in mind is player tedium. Providing orders for lots of +small ships can be a real pain in the neck. Also, the more ships you have, the +more likely it will be that you'll make mistakes. + +Finally, keep in mind that the above are just guidelines. The "personality" +of the species that you are role-playing can definitely impact your strategy. +And, as in any role-playing game, you should always role-play your species +correctly, even if "correct" means "less efficient" or "less practical". + + +5.12 BUILDING OTHER ITEMS + +To build items other than ships and starbases, also use the BUILD command, but +specify the number of items you want and their class abbreviation. Here are +some examples: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + build 7 PD ;Add seven planetary defense units... + BUI 50 CU ;Train and equip 50 colonist units... + + Build 3 jp ; Build 3 jump portal units. + +END PRODUCTION + +We'll have more to say later about "colonist units" and "jump portal units". +Always be careful to use the correct class abbreviations in ANY orders. + + +5.13 FLEET MAINTENANCE COST + +Manning and maintaining ships and starbases is not free, and costs can be +especially high for military vessels. To reflect this reality, each species +will be required to pay a "fleet maintenance cost". + +The fleet maintanance cost will be calculated by the computer and listed on +your status report. The base cost for all military ships will be the tonnage +divided by 500, the base cost for starbases will be the tonnage divided by +1000, and the base cost for transports will be the tonnage divided by 2,500. +Sub-light ships will receive a 25% discount. For example, it will cost 400 +per turn to maintain a 200,000 ton light cruiser, 60 per turn to maintain a +150,000 ton TR15, and 750 per turn to maintain a 500,000 ton sub-light +dreadnought. The full cost must also be paid for ships that are still under +construction. After calculation of the total base cost, a discount will be +applied equal to the current military tech level divided by 2, used as a +percentage (drop fractions). For example, if your military tech level is 27, +then you will receive a 13% discount. In this way, those species that +"specialize" more heavily in military technology will be able to operate their +fleets more efficiently. + +The computer will calculate the percentage of the total production of all +planets that is needed to pay the fleet maintenance cost, and will subtract +that percentage from the total amount available for spending on each planet. +Thus, the player will NOT have to do any calculations at all - the cost will be +automatically deducted from the production of each planet. Here is an example +of how the cost and deductions will appear on your status reports: + + For the entire species, you will see a line like this: + + Fleet maintenance cost = 926 (7.34% of total production) + + For each planet, you will see a line like this: + + Total available for spending this turn = 2278 - 167 = 2111 + +where the portion of the fleet maintenance cost that is being paid by this +planet is 167 (i.e. 7.34% of 2278). + +If the fleet maintenance cost is greater than the total production of all of +your planets, then the percentage will be greater than 100. If this occurs, +then as much of the cost as possible will be paid using any economic units in +the treasury. If the remaining cost is still greater than total production, +the amount over 100% will be the percent chance of civil unrest, riots, and +destruction of infrastructure. In other words, the population will get very +upset if the military budget becomes too excessive. + + + +6.0 MOVEMENT + +As soon as you have finished constructing at least one ship, you will be able +to give movement orders in the movement sections of the order form. Jump +orders can be given only for ships and items that are listed in the status +report for the current turn. You may not give jump orders for items that +will be produced in the current turn. Other movement orders for newly +constructed ships may be given immediately after production, in the post- +arrival section of the order form. + +Movement orders are of four types: jump orders, transfer orders, landing and +orbiting orders, and sub-light move orders. These orders are described below. + + +6.1 JUMP ORDERS + +Jump orders are given when a ship must be moved to a different star system. +These orders should use the JUMP command. Here are some examples: + +START JUMPS +; Place jump orders here. + + jump PB Benjamin Franklin, 12 7 18 + JUMP FF Thomas Edison, PL Mars + +END + +For the destination, use the name of a planet in the destination star system +whenever possible. If you mistype a planet name, the computer will report an +error which the gamemaster may be able to fix. However, if you mistype "x y z" +coordinates, the ship will arrive at the wrong destination, if it arrives at +all. + +If a planet name is used, then the ship will automatically go into orbit around +the planet when it arrives. If X Y Z coordinates are used, the ship will +remain in the deep space part of the sector, even if the sector has planets. + +If a ship or starbase is located at a terminus of a natural wormhole, then it +may use the wormhole to travel to the other terminus. To do this, use the +WORMHOLE command, as in the following examples: + +START JUMPS +; Place jump orders here. + + Wormhole TR10 Praying Mantis + WORM BAS Deep Space 3, PL Danbury + Wor FFS Farragut + Worm BC Tanid's Sword, PL Vega III + +END + +Note that this is the only way that a starbase can "jump" to a different +sector at FTL speeds. + +If an optional planet name is specified, then the ship or starbase will enter +orbit around the planet when it arrives at the other end of the wormhole. +Otherwise, it will remain in deep space. (Obviously, if a planet is specified, +then it must be located at the same X Y Z coordinates as the other end of the +wormhole.) + +When a location is scanned (discussed later), the scan will indicate if a +wormhole is present, but it will not indicate the coordinates of the other end +of the wormhole. The only way to determine the other endpoint is to actually +use the wormhole, as described above. + +Natural wormholes are absolutely stable. There is no chance of a mis-jump or +self-destruction when using one, regardless of the distance traveled. + + +6.2 TRANSFER ORDERS + +Transfer orders use the TRANSFER command, and are used to move items to and +from ships and planets in the same sector. They must be given in the pre- +departure or post-arrival sections of your orders. + +Transfers between planets in the same sector do not require the use of specific +ships. It is assumed that there are sufficient shuttlecraft available. For +example: + +START POST-ARRIVAL +; Place post-arrival orders here. + + TRANSFER 100 RM PL Earth, PL Mars + +END + +In effect, the TRANSFER command is used to transfer goods between any two +entities that are capable of holding them, as long as the transfer occurs +within a sector. Here are some more examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + TRAN 50 RM PL Earth, BAS Earth Orbit 3 + tra 2 RM FF Gibbon, CA Embassy + TRANSFER 100 RM BAS Earth Orbit 2, BAS Mars Orbit 1 + Tran 50 PD PL Earth, Pl Mars + +END + +If a planet is the source or destination in a transfer, the planet name MUST +be used - coordinates may NOT be used! + +There is no limit to the number of TRANSFER commands that a ship or planet can +be given in a single turn. + +A special note must be made about the TRANSFER command. There is a possible +situation in which colonists and supplies could be transferred to a new colony +immediately after a jump. If the planet is already inhabited by another +species, neither species will know about the new colony until the next turn. +To prevent this very unrealistic kind of incident, a TRANSFER to a planet may +only be made in the post-arrival phase IF the planet is already inhabited by +the species making the transfer. Otherwise, the transfer will have to be +done in the pre-departure phase of the next turn. Once the colony has been +established, you may TRANSFER goods to the planet in either the pre-departure +or post-arrival phases. + +An optional feature of the BUILD command that was not discussed earlier allows +the player to provide a destination for the items that are built. Here are +some examples: + +START PRODUCTION + PRODUCTION PL Earth + ; Enter your production orders for planet Earth here. + + ; Build 120 colonist units and transfer them to a transport. + Build 120 CU TR6 Belly Laugh + + ; Build 150 planetary defense units and transfer them to the colony + ; on Mars. + Bui 150 PD PL Mars + +END PRODUCTION + +If the optional destination is a planet, then it must be in the same star +system as the producing planet. If the optional destination is a ship, then +the ship must be in the system BY THE END OF THE TURN. In other words, a BUILD +command with an optional destination is exactly equivalent to a BUILD command +in the production section of the orders, followed by a TRANSFER order in the +post-arrival section. If the destination does not have sufficient cargo +capacity, then only items for which there is sufficient capacity will be +transferred. All item transfers will be logged on the status report. And +since this optional feature cannot have any destructive or irreversible +consequences, no error message will be posted if the transfer fails or is +incomplete. If the transfer cannot be made, then the produced items will +simply remain on the planet. + + + IMPORTANT! + + If you attempt to auto-transfer items to another planet in the + same sector, and at least one of the planets is under siege, then + the transfer will be ignored. If a planet is under siege, you + MUST use a separate TRANSFER command. Also, keep in mind that + post-arrival TRANSFERs will only work if the destination planet + is already populated. + + +6.3 THE "LAND", "ORBIT", AND "DEEP" COMMANDS + +The LAND, ORBIT, and DEEP commands are used for moving ships within a star +system. The LAND command indicates that the ship should land on the surface of +a planet. The ORBIT command indicates that the ship should enter orbit around +a planet. The ORBIT command can also be used to have a starbase towed from +orbit around one planet into an orbit around another planet in the same star +system. The DEEP command may be used to move a ship that is currently landed +or orbiting into deep space. A DEEP order may NOT be given for a starbase. +LAND, ORBIT, and DEEP orders may be given in either the pre-departure or post- +arrival section of your orders. + +Examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Land FF Don Quixote, PL Mars + ORB BAS Hurdy Gurdy, PL Jupiter + DEEP DD Jeopardy +END + +The destination in a LAND or ORBIT can be a planet number or a planet name. +(We will discuss how to name planets later.) + +In FAR HORIZONS, ships that are given JUMP commands of the form "JUMP X Y Z" +do not actually land on a planet or go into orbit around a planet. Instead, +they are simply located somewhere in the star system, and we refer to this +"somewhere" as 'deep space'. Also, movement within a star system is considered +to be trivially easy in FAR HORIZONS. Thus, there is no movement penalty or +advantage to being in deep space, in orbit around a particular planet, or +landed on a particular planet. + +However, there is one circumstance where being landed on a planet can provide +an advantage. If a ship owned by another species visits the system, it will +detect ships in orbit or in deep space, but NOT ships that have landed on a +planet that is populated by your species. In effect, the population of your +colony or home planet can "hide" your ships from prying eyes. Ships that are +under construction are always automatically hidden in this way. However, if +another species also has a colony on the same planet, then your ships cannot be +hidden from them. + +The LAND command will allow you to land a ship on one of your populated +planets, thus hiding it from alien view. The ORBIT command will allow you to +place a landed ship in orbit, thus intentionally making it visible to others. +Here are some more examples: + +START POST-ARRIVAL +; Place post-arrival orders here. + +; Move the little corvette from the surface of Mars to Earth orbit for the +; Klingons to see. + orb CTS Jiminy Cricket, PL Earth +; But, don't let them see our big ships... + LAND DN Faragut, PL Earth + Lan BS Wellington, PL Mars + +END + +A LAND or ORBIT command may only be issued to a ship that is in the same star +system as the planet. A ship does not already have to be at the planet when a +LAND or ORBIT command is given - it just has to be in the same sector. + +When you give a JUMP order of the form "JUMP ship, PL name", the ship will +automatically go into orbit around the planet. + +For the purposes of this game, a ship cannot land on uninhabited planets. +[Actually, it is certainly possible for ships to land on uninhabited planets, +but it does not perform a useful game function, and so it is not allowed.] +Also, in general, you may not land your ships on a planet that is not inhabited +by your species, even if it IS inhabited by one or more other species. The +only exception to this is if a species that inhabits the planet has declared +you as an ALLY. (We'll have more to say about the ALLY command later.) + +If you want to land your ship on a planet that is inhabited by another species +that has declared you as an ALLY, you must use a planet number rather than a +planet name in the LAND order, even if you have given a name to the planet. +Here are some examples: + + Land TR5 Jabberwocky, 5 ; One of our allies has a colony on + ; planet 5. + + LAN FF Kharsh Dukh, 3. ; Let's see if they coinsider us an + ; ally. + +If there is at least one species that has population on the planet and that has +declared your species as an ALLY, then your ship will be allowed to land. If +you are allowed to land by one or more species, then all of those species will +be notified that they granted you permission to land. If you are not allowed +to land by ANY species, then all species that have population on the planet +will be notified that they denied you permission to land. + +If your star system is attacked, ships on the surface of a planet will react +just as quickly as ships in orbit or in deep space. In other words, there is +no advantage or disadvantage to being on the surface, in orbit, or in deep +space. A ship does not have to be in orbit or on the surface to load or +unload goods. A newly constructed ship will remain on the surface until told +otherwise. If you land a ship on a planet that is populated by both your +species AND by one or more other species, then the other species WILL detect +your ship, even though it has landed. In other words, if a planet is colonized +by more than one species, then ALL ships on the planet will be detected by ALL +species that populate the planet, even ships that are still under construction. +The same is true for planetary defenses. + +Finally, if you do not specify a planet name or number in a LAND or ORBIT +command, the computer will check if the ship is already orbiting or landed +on a planet. If so, it will use that planet. For example: + +START JUMPS +; Place jump orders here. + + Jump DD Defiant, PL Earth +END + +START POST-ARRIVAL +; Place post-arrival orders here. + + Land DD Defiant +END + +The above LAND command will land the ship on PL Earth. + + +6.4 MISHAP PROBABILITIES + +Whenever a ship jumps from one star system to another, there is always a chance +of a mishap. This section is provided for those players who would like to know +the actual probabilities involved. + +The percentage probability that something will go wrong is: + + 2 + Distance + Mishap Probability = ---------------------- + Gravitics Tech Level + +The result is in percent. For example, if the distance is 7 parsecs and the +Gravitics tech level is 4, then the mishap probability is (7 x 7)/4 = 12.25%. +Note that the result is significant to two places after the decimal point. + +If a mishap does occur, then the result will be either a mis-jump or self- +destruction. When a mishap does occur, a second check is made using the same +probability. If the second mishap also occurs, then the ship self-destructs. + +Finally, don't forget that all success/failure probabilities are further +affected by the age of a ship. The probability calculated above is for a ship +whose effective age is zero. + + +6.5 THE MOVE COMMAND + +It is possible for a ship or a starbase to travel up to one parsec per turn at +sub-light speeds. The ship can be either sub-light or FTL. It is assumed that +a starbase is towed by its own shuttlecraft. + +To do this, use the MOVE command. MOVE orders may only be issued in the +jump section of your orders. Here are some examples: + +START JUMPS +; Place jump orders here. + + Move BAS Sneakers, 5 12 17 + MOV CC Ornery, 17 16 11 + mov DDS Victory, 22 31 15 + +END + +Only one coordinate (X, Y, or Z) may change, and it may not change by more than ++/-1. Here are some examples: + + Okay: from 15 16 21 to 15 16 22 Z increased by 1 + from 21 5 7 to 20 5 7 X decreased by 1 + from 31 15 15 to 31 16 15 Y increased by 1 + + Wrong: from 15 16 21 to 15 17 22 Y and Z both increased by 1 + from 21 5 7 to 19 5 7 X decreased by 2 + from 31 15 15 to 30 16 15 X decreased by 1 and Y + increased by 1 + +The move requires a full turn. Thus, a ship or starbase can only be given one +MOVE order per turn. + +Since sub-light travel does not involve use of a wormhole, there is no danger +of mis-jumps or self-destruction. + + + +7.0 COLONIZATION + +One of the goals of most players will be to create colonies in other star +systems as well as in their home system. How this is done will be explained +in this chapter. + + +7.1 GENERAL CONSIDERATIONS + +Before a colony can be established, a suitable planet must be found. The +three major criteria used to determine the suitability of a prospective planet +are its temperature class, its pressure class and the constituents of its +atmosphere. If any of these three criteria differ considerably from those of +the home planet, then a considerable amount of life support expertise will be +required if the colony is to survive. + +Once a suitable planet has been found, the colony can be started by shipping in +colonists and the supplies and equipment they will need to set up the colony. +In its early stages, a colony will grow mainly by constant infusions from the +home planet or other larger colonies, since its population will be too low to +grow much on its own. Eventually, though, the colony's population will become +large enough that additional people and materials will no longer have to be +shipped in from elsewhere. + + + !!! IMPORTANT !!! + + In general, you may NOT set up a colony on your own home planet + or on the home planet of another species. However, you MAY + colonize the home planet of another species after you have + completely destroyed the population by means of germ warfare or + orbital bombardment (discussed later). You may also re-colonize + your home planet up to its former highest economic base if it + was reduced by bombardment of germ warfare. + + +This rule is designed to prevent three unrealistic situations: 1. Building +a colony on your own home planet so that you can increase your mining and +manufacturing bases above the 2% limit per turn; 2. Doing the same on someone +else's home planet; 3. Sneaking onto someone else's home planet and installing +a colony before they can stop you. + +I doubt if anyone would ever want to do number 3, unless it was an act of pure +mischief, but numbers 1 and 2 are ways of getting around the 2% growth limit, +and might appeal to players who like to 'cheat' by taking advantage of +loopholes in the rules. + + +7.2 DETERMINING A PLANET'S SUITABILITY FOR COLONIZATION + +A colony may only be started if the Life Support tech level of the species is +high enough to handle the prevailing conditions at the planet. If the Life +Support tech level is not high enough, then a colony may not be started. Use +the following guidelines to determine how much life support is actually needed: + + a. If the single gas required by the species is not present in + the required range, 3 points of life support will be needed. + + b. If the atmosphere has any gases poisonous to the species, + 3 points of life support will be needed for EACH poisonous gas. + + c. For every point of difference between the home planet's temperature + class and the colony's temperature class, 3 points of life support + will be needed. + + d. For every point of difference between the home planet's pressure + class and the colony's pressure class, 3 points of life support + will be needed. + +The minimum Life Support tech level needed to allow creation of the colony is +the sum of all the above contributions. For example, consider the following +data: + + Home: tc=10 pc=10 NH3(29%),N2(47%),O2(24%) + Colony: tc=9 pc=12 H2S(46%),O2(54%) + + Atmospheric Requirement: 14%-54% O2 + Gases Poisonous to Species: HCl,Cl2,SO2,H2S,Fl2,CH4 + Gases Harmless to Species: He,H2,H2O,NH3,N2,CO2 + +The requirement for O2 is just barely met, so no life support is needed for it. +However, the colony has one poisonous gas, H2S, so 3 points of life support +will be needed. The temperature class difference is 1, so 3 points of life +support are needed. Finally, the pressure class difference is 2, so 6 points +of life support will be needed. Thus, a total of 0+3+3+6 = 12 points of life +support are needed. If the Life Support tech level of the species is 12 or +higher, then the colony may be started. + +Finally, extremely large planets, such as gas giants, are so hostile to life +that nothing can survive on the surface. However, these planets typically have +large numbers of satellites (i.e. "moons") which can be colonized instead. +Thus, for planets such as these, we can think of the life support requirements +as 'averages' for the entire planet and its system of satellites. It is for +this reason also that the gravity of a planet is not a consideration. + + +7.3 STARTING THE COLONY + +In order for a colony to be of any use, it must have people, raw materials, +and production capacity. In FAR HORIZONS, these needs have been met by +implementing the following items: + + Carrying + Abbr Name Cost Capacity + ----------------------------------------------------------- + CU Colonist Units 1 1 + IU Colonial Mining Units 1 1 + AU Colonial Manufacturing Units 1 1 + +A colonist unit is the approximate equivalent of 1000 humans. + +Colonist units, colonial mining units, and colonial manufacturing units are +used to establish the initial mining and manufacturing bases on a colony +planet. Units are installed as follows: + + 1 colonist unit + 1 colonial mining unit = 0.1 mining base + + 1 colonist unit + 1 colonial manufacturing unit = 0.1 manufacturing base + +In other words, a colonist unit consists of trained people, ready and willing +to work. A colonial mining unit or a colonial manufacturing unit contains the +supplies and equipment they will need to do the particular job. + +After colonial mining and manufacturing units have been transported to a new +colony, they must be installed; i.e., they are used to create new mining and +manufacturing bases, or to increase existing bases. The installation is +started in the pre-departure section of the orders, but requires the entire +turn to complete. + +Note that colonist units, mining units, and manufacturing units must be ON the +planet before they can be installed. Thus, they must be transferred from the +ships that brought them to the planet's surface before they can be installed. +Furthermore, items may only be transferred to a planet that has a name. For +this, use the NAME command. For example: + + NAME 12 3 9 4 PL Epsilon Eridani IV + +The above example will give the name "Epsilon Eridani IV" to the fourth planet +of the star system at coordinates X=12, Y=3, Z=9. Note that the abbreviation +for planet "PL" is required. (In FAR HORIZONS, names ALWAYS require use of +the appropriate class abbreviation. There are no exceptions.) + + + WARNING! One of the most common player mistakes is to accidentally + omit a required abbreviation. In Far Horizons, ALL ships and items + have abbreviations, and ALL orders that refer to them must use the + required abbreviation. If not, the computer will reject the order. + + +After colonial units have been transferred to the planet using the TRANSFER +command, they may be installed with the INSTALL command. Here's a complete +example involving the NAME, TRANSFER, and INSTALL commands: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Name 13 24 7 3 PL Dickory Dock + + Tra 50 cu TR5 No-one Here, PL Dickory Dock + Tra 22 iu TR5 No-one Here, PL Dickory Dock + Tra 28 au TR5 No-one Here, PL Dickory Dock + Inst 22 iu PL Dickory Dock ; Mining base will be 2.2 + INst 28 au PL Dickory Dock ; Manufacturing base will be 2.8 +END + +Make sure that sufficient colonist units (CUs) are present on the planet before +installing the mining units (IUs) and manufacturing units (AUs) that will need +them. Also, orders to transfer units to the planet will NOT automatically +install them. If you do not give specific installation orders, the units +will simply sit on the planet's surface. + +In other words, when you give an order to install 22 IUs, you are telling the +computer to combine 22 CUs and 22 IUs and increase the mining base of the +planet by exactly 2.2. When the order is executed, the computer will reduce +the number of CUs and IUs by 22 each, and will increase the mining base by +exactly 2.2. + +Alternatively, you can use the UNLOAD command, as in the following example: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Name 13 24 7 3 PL Dickory Dock + + Orbit TR5 No-one Here, PL Dickory Dock + + Unload TR5 No-one Here +END + +This command will transfer all CUs, IUs, and AUs on the ship to whatever planet +it is located at (orbiting or landed). After the transfer, it will then +automatically install as many mining and manufacturing units as it can, +starting with mining units, and including any colonist units, mining units, +and manufacturing units that were already on the planet. + +The ORBIT command was required in the above example because the planet was just +named, and there was no way that the transport could have already been in orbit +around the planet. If the planet had been named in an earlier turn, and if the +transport had jumped directly to the planet, then it would have automatically +orbited the planet and the above ORBIT command would not have been necessary. + +A special note must be made about the TRANSFER command. There is a possible +situation in which colonists and supplies could be transferred to a new colony +immediately after a jump. If the planet is already inhabited by another +species, neither species will know about the new colony until the next turn. +To prevent this very unrealistic kind of incident, a TRANSFER to a planet may +only be made in the post-arrival phase IF the planet is already inhabited by +the species making the transfer. Otherwise, the transfer will have to be +done in the pre-departure phase of the next turn. Once the colony has been +established, you may TRANSFER people and goods to the planet in either the pre- +departure or post-arrival phases. + + +7.4 AVAILABLE POPULATION + +As a colony grows, its population will increase by normal means. This +population will be listed on status reports as a number of 'available +population units'. This population can then be used as follows: + + If a colony builds planetary defense units or additional colonist + units, they will also have an equivalent cost in 'available + population units'. For example, to create 17 planetary defense + units on a colony will reduce the number of available population + units by 17. + +In other words, before you can "build" colonist units or planetary defense +units, you must first have enough people to hire and train for the job. +Thus, you can think of 'available population' as equivalent to the number of +population units that are available for hire. This number will be relatively +low on colonies, but will be much higher on the home planet. + +The number of available population units that are currently 'for hire' on each +planet will be listed in your status reports. + +Note that the above rules do NOT apply to ships or other items built on a +colony planet. In other words, building ships does not have an equivalent +"cost" in colonist units. (Crewing requirements are considered to be +insignificant. Very large ships may require large crews, but small colonies +will not have the resources and production capacity to build such ships.) + + +7.5 POPULATION GROWTH ON COLONY PLANETS + +In general, colonial populations increase at a much higher rate than on the +home planet. In this game, we will use a base figure of 10% per turn. This +value will be modified downwards depending on how hostile the planet is to +your species. + +If your Life Support tech level is exactly equal to the Life Support needed to +colonize the planet, then the colony will experience no growth. + +At the opposite extreme, if no life support is needed, then population growth +will be 10% (plus or minus small random fluctuations). + +Any new growth is converted to 'available population units', which you can then +use to BUILD colonist units (CUs) or planetary defense units (PDs). + +The actual growth will be calculated by the gamemaster's computer, and the +current total population and available population will be listed in the status +report for each planet. + +Finally, unused available population will NOT carry over into later turns if +they are not used to BUILD CUs or PDs. Instead, the people will either find +other jobs locally, or will give up in disgust (because they can't find jobs) +and will look for better opportunities off-planet. This approach will prevent +unrealistic accumulations of "idle" population. + + +7.6 MINING COLONIES + +If a colony has a mining base that is greater than zero, but its manufacturing +base is exactly zero, then it will be considered a 'mining colony'. A mining +colony has the following special features: + + 1. A mining colony will never produce 'available population'. The + only way to increase the population is by bringing in colonists and + installing colonial mining units. + + 2. Raw material units produced each turn on the mining colony will be + automatically "sold" and converted to economic units (3 raw material + units = 2 economic units, fractions dropped). In other words, the + number of economic units generated will be two-thirds of the number + of raw material units that are "mined". + + 3. As raw materials are extracted from a mining colony, the mining + difficulty of the planet will gradually rise. The rise in mining + difficulty will be proportional to the amount of material mined. + Note that this increase in mining difficulty occurs ONLY on mining + colonies. + +Economic units generated by a mining colony cannot be spent on the mining +colony itself (except for the HIDE command, discussed later). Instead, they +are automatically added to the balance for the species. They may be spent in +the same turn on other planets only if the PRODUCTION order for the mining +colony appears before PRODUCTION orders for the planets where the economic +units will be spent. + +Thus, mining colonies allow a species to take advantage of planets that are +rich in resources but which are not suitable for normal life. The raw material +units that they generate are automatically converted to cash which can then be +spent on producing planets. + +A mining colony is a better investment than a normal colony as long as the +mining difficulty is less than 1.50. When the mining difficulty becomes +greater than 1.50, the return on investment becomes less than for a normal +colony. Thus, it's a good idea to convert a mining colony to a normal colony +(by installing colonial manufacturing units) when the mining difficulty +approaches 1.50. + + +7.7 RESORT COLONIES + +If a colony has a manufacturing base that is greater than zero, a mining base +that is exactly zero, a gravity less than or equal to the home planet, and +requires less than 6 points of life support technology, then it will be +considered a 'resort colony'. A resort colony has the following special +features: + + 1. A resort colony will never produce 'available population'. The + only way to increase the population is by bringing in colonists + and installing colonial manufacturing units. + + 2. Each turn, the production capacity of a resort colony will be + automatically converted to economic units at a rate of three-to-two. + In other words, the number of economic units generated will be two- + thirds of the production capacity. For example, if the production + capacity is 40, then it will be automatically converted to 26 + economic units. + +Economic units generated by a resort colony cannot be spent on the resort +colony itself. Instead, they are automatically added to the balance for the +species. They may be spent in the same turn on other planets only if the +PRODUCTION order for the resort colony appears before PRODUCTION orders for +the planets where the economic units will be spent. + +Thus, resort colonies allow a species to take advantage of planets that are +especially suitable for life but which may have a high mining difficulty. +Their effective production capacity is automatically converted to cash which +can then be spent on producing planets. + + + !!! IMPORTANT !!! + + One of the most common mistakes that players make is to + ignore the gravity of a planet when trying to create a + resort colony. The gravity MUST be less than or equal + to the gravity of the home planet. + + +7.8 HIDDEN COLONIES + +It is possible to hide a colony from detection by aliens. This is done by +using special shielding, conducting as much activity as possible underground, +delaying or reducing activity when aliens are in the system, using evasive +tactics, and so on. However, hiding a colony is expensive and it reduces the +overall efficiency of the colony. + +In Far Horizons, you may indicate that a colony is to be hidden by placing a +HIDE order in the production section of your orders, as follows: + + Hide + +The command takes no arguments. + +The HIDE command will last only for the current turn. If you wish to +permanently hide a colony, then you must issue the HIDE command each turn. + +The cost of hiding is the sum of the mining and manufacturing bases of the +colony at the beginning of the turn. For example, if the most recent status +report shows that a colony has a mining base of 25.7 and a manufacturing base +of 29.2, then the cost of hiding the colony will be: + + 25.7 + 29.2 = 54.9 = 54 + +Note that fractions are dropped. + +You may not hide a resort colony or a home planet. You may only hide normal +colonies and mining colonies. (In fact, a HIDE order is the only production +order that may be given to a mining colony.) Also, you may not hide a planet +that is under siege (discussed later). + +When a colony is hidden, it will not be listed on the status reports of other +species that are in the same star system. Ships under construction and any +ships that have landed on the planet will also be undetected. However, +starbases and ships in orbit WILL be detected. Also, the colony WILL be +detected by a species that has population on the same planet. + +If you suspect that a planet has a hidden colony, you can detect the colony by +transferring planetary defense units or colonist units to the surface during +the pre-departure phase of the turn. However, they must remain on the surface +until at least the next turn in order to detect the hidden colony. + +You MAY hide a colony that has population on it (i.e. colonist units and/or +planetary defense units) but which does not have any installed mining or +manufacturing bases. Since the total installed base is zero, the cost is also +zero. However, you will have to provide your own PRODUCTION order for the +planet. + + +7.9 COLONY ATTRITION AND LOSSES + +When a new colony is started, it is normal to expect losses to be relatively +heavy compared to later in its development. This higher-than-normal casualty +rate will have several causes: unfamiliar flora and fauna, unpredictable +climate, unexpected geological phenomena such as earthquakes and volcanoes, and +so on. In addition, very small colonies cannot replace these losses through +new births because their population is too small. For example, extremely small +colonies must avoid the potentially harmful effects of inbreeding, which can +greatly restrict their growth rate. + +In Far Horizons, we will simulate the losses that can be expected in very small +colonies as follows: + + If the total population of a colony is less than 50 population + units (about 50,000 people), then there will be a fixed loss of + exactly 1 population unit (about 1000 people) per turn. If the + total population is at least 50 population units, then no loss + will occur. + +This reduction in population will occur at the end of every turn, immediately +after normal population growth. Thus, if the colony experiences a natural +increase in population, there will be no net loss. + +The reduction will take place as follows: + + If the number of available population units is greater than zero, + then it will be reduced by one; + otherwise, if the number of colonist units on the planet is + greater than zero, then it will be reduced by one; + otherwise, if the number of planetary defense units on the planet + is greater than zero, then it will be reduced by one; + otherwise, if the manufacturing base of the planet is greater than + zero, then it will be reduced by 0.1; + otherwise, the mining base of the planet will be reduced by 0.1. + +Obviously, if a planet has no population at all, then it will not experience +any reduction. + +A reduction in colonist units, planetary defense units, mining base, or +manufacturing base will be indicated on the status report. Reduction in +available population units will not be mentioned. + + +7.10 THE PRODUCTION PENALTY + +A colony that has a Life Support tech level that is barely sufficient to +survive will not be useful for much else. If, for example, the tech level +needed to survive is 27 and the actual tech level is also 27, then the colony +is on the borderline between extinction and survival. We certainly cannot +expect such a colony to be very productive, no matter how large its mining and +manufacturing bases. Instead, the entire output of the planet's mining and +manufacturing bases would be needed just to survive. If, however, the tech +level needed is much less than the actual tech level, then the colony would +be able to thrive and be very productive. + +In Far Horizons, we simulate this reality with what is called a "production +penalty" that will apply to all planets. The penalty will depend on the actual +Life Support tech level of the species (LS) and the tech level needed to +survive on the planet (LSN). The production penalty is calculated as follows: + + + 100 x Life support tech level needed + Production Penalty = ---------------------------------------- percent + Life support tech level + + +For example, if the LSN value for the planet is 9 and the LS value for the +species is 36, then production capacity and raw material production will each +be reduced by 25%. If LS equals LSN, then the production penalty is 100%, +and nothing at all will be available for spending - the entire output of the +planet's mining and manufacturing bases will be needed just to survive. + +The penalty will apply to all planets, including mining colonies, manufacturing +colonies, and even the home planet. However, since the life support tech level +needed on the home planet is zero, the penalty will also be zero. (The only +way this could change is if the home planet is terraformed by another species. +We'll have more to say about terraforming later.) + +The penalty will be calculated by the computer and printed on your status +reports, along with the net production values. Although you will not have to +do any additional calculations, you should always keep the penalty in mind when +deciding on which planets to colonize. + + + +8.0 WARFARE + +Since FAR HORIZONS is a role-playing game, it is quite possible for a species +to choose to be peaceful, and to live harmoniously with all of its neighbors. +Unfortunately, its neighbors may not be similarly inclined... + + +8.1 PREPARING FOR BATTLE + +Before a battle can begin, you must specify its location. This is done with +the BATTLE command. For example: + +START COMBAT +; Place combat orders here. + + ;The following combat orders will be for the attack on the Romulan home + ; planet in their star system at 12 4 3... + BATTLE 12 4 3 + + additional combat orders follow the BATTLE order + +END + +Note that only the X, Y and Z coordinates are given. Any planets that are to +be involved will depend on later commands. A BATTLE command MUST be specified +before any other combat orders that will apply to the specified location. In +effect, a BATTLE command states that a battle MAY take place at the specified +location, and that all of your forces at that location are on alert. A single +BATTLE command may be followed by other combat commands, and all such commands +will apply to the location specified in the most recently executed BATTLE +command. Thus, if you are attacking more than one star system in a turn, then +each set of combat orders will be preceded by an appropriate BATTLE order. + + +8.2 COMBAT + +To indicate your intentions at a battle, use one or more ENGAGE commands. Each +ENGAGE command requires an "option" argument to indicate the nature of the +engagement you are willing to take part in. Some also require an additional +argument which specifies the planet where the option will apply. You may +specify more than one ENGAGE command per battle. Here are your options: + + + 0 - Defense in-place. Do not attack anyone unless they are + clearly hostile. If fighting does start, fight only if + the battle moves to your current location. If battle + moves to a new location, do not move with it. This + is the default option if you do not provide any ENGAGE + orders. + + 1 - Deep space defense. Do not fight unless the opponent is + clearly hostile. If a fight is inevitable, try to keep the + battle away from your planets. This option should be used + if you have planets you wish to defend and you wish to keep + the battle away from them to avoid damage to civilians and + civilian structures. (Remember, "deep space" is anywhere in + a star system that is not within fighting range of a planet.) + + 2 - Planet defense. This option requires an additional argument + indicating the planet you are willing to defend. This + command should be given for each planet you wish to defend. + + 3 - Deep space fight. Attack the enemy in deep space and destroy + as many ships as possible. If the enemy is not willing to meet + you in deep space, then no battle will take place. (Remember, + "deep space" is anywhere in a star system that is not within + fighting range of a planet.) + + 4 - Planet attack. This option requires a second argument to + indicate the number of the planet that you wish to attack. + This type of attack will do as much damage as possible to + military targets, while minimizing damage to civilians and + infrastructure. With this option, an attacker will have + to contend with starbases, planetary defenses, and ships + on the ground or in orbit. + + 5 - Planet bombardment. This option requires an additional + argument to indicate the number of the planet that you wish + to attack. Start with a planetary attack. After you have + successfully destroyed all of the enemy's ships, starbases, + and planetary defenses, bombard the specified planet doing as + much damage as possible to the population and infrastructure. + + 6 - Germ warfare. This option requires an additional argument to + indicate the number of the planet that you wish to attack. + Start with a planetary attack. After you have successfully + destroyed all of the enemy's ships, starbases, and planetary + defenses, attempt to destroy all enemy life on the planet + using germ warfare. + + 7 - Besiege planet. This option requires an additional argument + to indicate the number of the planet that you wish to attack. + Start with a planetary attack. After you have successfully + destroyed all of the enemy's ships, starbases, and planetary + defenses, besiege the planet and extort 'taxes'. + + +If you give an ENGAGE order whose option is 3 or greater, you must also specify +the name or names of the enemy you want to fight with. For this, use the +ATTACK command. For example: + + Attack SP Klingon + ATT SP Romulan + +The above says that you will attack two species: the Klingons and the Romulans. +Note that you must issue a separate ATTACK command for each species that you +wish to attack. + +You also have the option of attacking all species that you have declared as +enemies using the ENEMY command (discussed later). To do this, give the ATTACK +command a zero argument, as in the following example: + + ATTACK 0 ; Attack all declared enemies at this battle location. + +If you want to attack both enemies and non-enemies, then give the above order +plus specific ATTACK orders for the non-enemies. + +If you do not give specific orders to attack other species, then you will not +attack them unless they attack you. + + + IMPORTANT!!! + + It is not possible for a battle to take place if only transports are being + engaged. In order for a battle to occur, at least one participant must + have at least one warship, starbase, or planetary defense unit at the + engagement location. + + +Now, if there are other species at the battle location that you are NOT +attacking, but they have declared as ALLY a species that you ARE attacking, +then they will fight in the battle on the side of their ALLY. In other +words, the effect will be the same as if you had given ATTACK orders for +them and they for you. + +EXAMPLE #1: Several Romulan ships appear in sector 4 12 3 where you (the +Humans) have two colonies (planet #4 and #7). You're not sure if they will +attack, and you would prefer not to fight. Also, if they do attack, you want +to keep them away from your colonies to avoid civilian deaths and destruction +of mining and manufacturing capacity. Here are the combat orders you should +give: + +START COMBAT +; Place combat orders here. + + BATTLE 4 12 3 + ENGAGE 1 ;Try to keep fight, if any, away from + ; colonies. + ENGAGE 2 4 ;Protect planet #4. + ENGAGE 2 7 ;Protect planet #7. + +END + +EXAMPLE #2: You are the Romulan visitors of the preceding example. Your goal +is to attack the Humans at planet 4 and destroy all defenses there. If this +succeeds, you then want to attack planet 7, and destroy its defenses. Finally, +if everything goes well up to this point, bombard planet 7 (but NOT planet 4). +Here are the orders you should give: + +START COMBAT +; Place combat orders here. + + Battle 4 12 3 + + Attack SP Human + + Engage 4 4 ;Attack planet #4 and destroy its defenses, + ; but do NOT try to destroy civilians and + ; infrastructure. + + Engage 5 7 ;Attack planet #7 and destroy its defenses, + ; then try to wipe out the population and + ; infrastructure by bombarding the planet. +END + +If you want to attack the enemy in deep space and still protect your planets, +then provide an "ENGAGE 2" command for each planet you wish to defend, and also +provide an "ENGAGE 3" command. In other words, you definitely want to fight, +but you also want to keep the battle away from your planets for as long as +possible. + +If a defending species provides orders to engage an attacker in deep space, but +the attacker has orders to attack a planet, then the following will apply: + + If the defender has a higher military tech level than the attacker, + then N rounds of combat will occur in deep space before the battle + moves to the planet, where N is the difference in Military tech + levels. Otherwise, only one round will occur in deep space. + +For example, if the Fizians (Military tech level = 22) wish to attack the Jubwa +(Military tech level = 27) home planet, but the Jubwas want to keep the battle +away from the planet for as long as possible, then 27-22 = 5 rounds of combat +will occur in deep space. Starting with the 6th round, the battle will be at +the Jubwa home planet (assuming the Fizians can still fight). + +When a planet is attacked, considerable damage can also be done to non- +combatants and to surface structures. This damage will be indicated on +status reports by reductions in mining and manufacturing bases. + +In the following sections, we will discuss some of the above options in more +detail. + + +8.3 ANNIHILATION + +After an attacker has destroyed all of the defender's ships, starbases, and +planetary defenses, he may choose to attempt to annihilate the population. +This can be accomplished in two ways: by heavy bombardment from space, or +by the use of germ warfare. + +When attacking a planet by bombarding it from orbit, the actual damage done +will depend on the number and combat capability of the attacking ships, and on +the population and infrastructure of the now-defenseless planet. If sufficient +power is applied, then the defenders can be completely destroyed. As a rough +rule-of-thumb, a fleet of ten unenhanced Strike Cruisers (250,000 tons each) +with a military tech level of 50 will have sufficient firepower to wipe out +the entire population and infrastructure of a heavily populated planet. + +Germ warfare is used when the attacker wishes to ensure complete annihilation +of the defender. It is most useful if the attacker does not have or may not +have sufficient firepower to annihilate the population and infrastructure by +means of bombardment. It is also useful if the planet is rich and the attacker +wants to loot it after destroying the inhabitants. + +Germ warfare is carried out by the use of high tech devices called "Germ +Warfare Bombs", and the results will depend on the relative Biology tech levels +of the attacker and defender. Germ warfare bombs will be discussed in more +detail later. + +If germ warfare is used to successfully wipe out the population of a planet, +then the planet may be colonized by someone else (such as the attacker) in +the next turn. However, the original mining and manufacturing bases are lost. +Instead, the planet is looted by the attackers and the resulting economic units +are added automatically to the balance for the attacking species. (It is +assumed that the direct transfer of the planet itself from the defender to the +attacker is impractical because they are completely different species; that +is, mining and manufacturing bases for the two species are not compatible. +However, some of the original wealth of the defenders is obtained by looting.) + +Note that germ warfare may not be successful, and the outcome will depend on +the relative Biology tech levels of the two species. Bombardment, however, +will always do some damage. + +If a home planet is bombed, it may be recolonized by the original inhabitants, +even if the damage was only minor. However, the final economic base that +results from any installations cannot exceed the original base. (In the case +of multiple bombings, the highest base at any time during the bombings will be +considered the original base.) When the base eventually reaches its original +value, the home planet will be considered fully recovered. During recovery, +the amount that may be spent on a bombed home planet will be limited, and the +available population will be less than normal. + + +8.4 SIEGE + +After an attacker has destroyed all of the defender's ships, starbases, +and planetary defenses, he may choose to besiege the planet and make the +inhabitants pay 'protection money' or 'taxes'. In effect, the attacker is +blackmailing the planet, saying "give us money or we will destroy you". + +The effectiveness of a siege will depend on the size of the planet's economy +and the number and sizes of ships that take part in the siege. And since siege +is an inherently military operation, it will also depend on the relative +Military tech levels of the opponents. An effectiveness rating will be +calculated as follows: + + + Total ship tonnage x ML of attackers + Effectiveness = ------------------------------------------- + Production base x (ML of defenders + 1) + + Production base = (MI x Mining Base) + (MA x Manufacturing Base) + + +If a ship besieges more than one planet in a sector, then its effectiveness +will be divided by the number of planets that it is besieging. + +Since a starbase does not have the maneuverability of a normal ship, it +will have an effective tonnage that is one quarter of its actual tonnage. +Transports will have NO effectiveness at all in a siege. Also, if the +besieging species has planetary defense units on the planet that is being +besieged, then they will contribute to the effectiveness of the siege in +proportion to the equivalent 'tonnage' of the defenses. However, planetary +defense units on the surface of a planet are MUCH more effective against a +defeated population than against attacking enemy ships above the planet. To +reflect this, each planetary defense unit will have an equivalent tonnage of +2000 tons FOR SIEGE PURPOSES ONLY; i.e. forty times more effective than when +attacking enemy ships. Finally, planetary defenses may not conduct a siege +by themselves. The besiegers must also have at least one warship or starbase +taking part in the siege to provide orbital support. + +The effectiveness will be used as a percentage to determine the amount of +production lost by the besieged planet. The maximum effectiveness is 95%. +Also, 25% of the lost production will be converted to economic units and +transferred to the besieging species. (The remaining 75% is considered lost +due to inefficiency, civil unrest, sabotage, reduced interplanetary and +interstellar trade, the cost of maintaining the siege, etc.) + +For example, if the effectiveness is 37 and the planet can spend 1205 in +production for the turn that it is under siege, then the planet will only be +able to spend 1205 - 37% of 1205 = 760. In addition, 25% of the amount lost +will be automatically transferred to the species that is conducting the siege. +In the above example, 37% of 1205 is 445, and 25% of 445 is 111. Thus, the +besieger will receive 111 economic units. If more than one species besieges +the planet, then the amount will be divided among them according to the +relative effectiveness of each species. + +The effectiveness will also be used to determine if the besieger detects and +prevents the construction of ships and planetary defense units by the besieged +species. For example, if the effectiveness is 37%, then there is a 37% chance +that the besieger will detect if any ship construction occurs. If so, the ship +will be destroyed. Similarly for planetary defense units. + +A species that is under siege maintains complete control of his planet, and may +give any orders that make sense. However, some orders may not succeed because +of the siege. Here are the basic rules that apply to sieges: + + 1. Any attempt to build a starbase on a beseiged planet will ALWAYS + be detected, and the starbase WILL be destroyed. + + 2. Any construction on a ship, even partial construction, MAY be + detected as described above. If so, the ship will be destroyed + before it can be used. + + 3. Any construction of planetary defense units MAY be detected as + described above. If so, all units on the planet will be destroyed + before they can be used. + + 4. Any items other than ships, starbases, and planetary defense units + can be built without fear of detection. + + 5. Any attempt to transfer items between the planet under siege and a + different planet in the same star system MAY be detected as described + above. If so, the items will be destroyed. + + 6. Besiegers will not detect transfers of economic units to other + species. + + 7. Any attempt to secretly land a ship on a besieged planet MAY + be detected as described above. If a landing is detected, the + besiegers will be notified of the landing, but will not otherwise + see the ship on their status reports. The player that owns the + ship will be told one of the following: a. the landing WAS detected; + b. the landing was NOT detected; or c. the landing MAY have been + detected. + +Besieging ships must remain in the system for the entire turn. Any ships that +jump out of the system voluntarily or which are forced to jump away during +combat will not take part in the siege. + + + IMPORTANT REMINDER! + + Keep in mind that you may not BUILD and auto-transfer items + to another planet in the same sector if either planet is under + siege. Instead, you must use the TRANSFER command. Also keep + in mind that post-arrival TRANSFERs will only work if the + destination planet is already populated. + + +A player that controls a planet that is under siege or which may be placed +under siege should keep in mind that some of his production may be stolen by +the enemy. Thus, production orders should be listed in order of importance. +Items will not be built if there are insufficient funds. For example, if your +planet is successfully attacked and besieged at the beginning of the turn, +then a percentage of your production will be lost. Only the remainder will be +available for you to spend. Keep this in mind if your system is 'visited' by +a potential enemy. + +A player that wishes to maintain a siege for more than one turn MUST provide +appropriate battle orders EVERY turn, just as if the siege were being attempted +each turn. At the beginning of each combat phase, the gamemaster's computer +effectively 'forgets' about any previous sieges. + + +8.4.1 OCCUPATION + +Even though Far Horizons does not have any special rules that deal exclusively +with 'occupying' a planet of another species, it IS possible to achieve a very +realistic kind of occupation using the existing rules. Consider the following +scenario: + + SP Good Guys and SP Bad Guys each have a colony on the 2nd planet + of the star system at 7 14 23. At the beginning of the turn, + the Bad Guys have several warships in the system, plus planetary + defense units at their colony. If the Bad Guys want to 'occupy' + the colony of the Good Guys, they could give the following orders: + + START COMBAT + ; Place combat orders here. + Battle 7 14 23 + Attack SP Good Guys + Engage 7 2 ; Attack and attempt to besiege + ; planet 2. + END + +If the Bad Guys are successful at eliminating the ships and defenses of the +Good Guys, then the siege will commence. Furthermore, the planetary defense +units in the Bad Guy colony will add to the overall effectiveness the siege. +This is especially important since planetary defense units are much more +effective at siege than at fighting ships above the planet. + +Now, since at least one ship or starbase is needed to maintain a siege, the +Bad Guys can build a small starbase at the colony during the production phase +of the turn (if they do not already have one). They can also build lots of +additional planetary defense units to help maintain the siege. In effect, they +have 'occupied' the colony of the Good Guys. Still another option would be to +build sub-light warships. This approach will release the FTL warships for duty +in other star systems. + +Note that it's perfectably acceptable for the Bad Guys to specify planet #2 +in an ATTACK order, even though there is a Bad Guy colony on the planet. The +computer will never allow a species to attack itself (unless, of course, you +decide to commit suicide and give an ATTACK order against your own species). + +Now, consider another scenario: + + SP Good Guys have a colony on the second planet of the star system + at 7 14 23. SP Bad Guys do NOT have a colony on the planet, but + they would like to conquer and 'occupy' the Good Guy colony. So, + in the previous turn, several warships AND TRANSPORTS jumped to the + colony. The transports contain colonist units, mining units, and + manufacturing units. The Bad Guys can now give the following orders: + + START COMBAT + ; Place combat orders here. + Battle 7 14 23 + Attack SP Good Guys + Engage 7 2 ; Attack and attempt to besiege + ; planet 2. + END + + START PRE-DEPARTURE + ; Place pre-departure orders here. + Name 7 14 23 2 PL Revenge + Transfer CUs, IUs, and AUs from transports to PL Revenge + Install IUs and AUs on PL Revenge + END + +The above orders will start a new Bad Guy colony if the Bad Guys win the +battle. If the bad guys lose, then the TRANSFER and INSTALL orders will be +ignored by the computer, since the transports will have been destroyed. + +Now, consider a third scenario: + + SP Good Guys have a colony on the second planet of the star system + at 7 14 23. SP Bad Guys do NOT have a colony on the planet, but + they would like to conquer and 'occupy' the Good Guy colony. So, + in the previous turn, several warships AND TRANSPORTS jumped to the + colony. The transports contain lots of planetary defense units. + The Bad Guys can now give the following orders: + + START COMBAT + ; Place combat orders here. + Battle 7 14 23 + Attack SP Good Guys + Engage 7 2 ; Attack and attempt to besiege + ; planet 2. + END + + START PRE-DEPARTURE + ; Place pre-departure orders here. + Name 7 14 23 2 PL Revenge + Transfer PDs from transports to PL Revenge + END + +If the Bad Guys win the battle, the above orders will start a new Bad Guy +colony that contains ONLY planetary defense units. If the Bad Guys bring +enough PDs, then the PDs can contribute significantly during the subsequent +siege. + +The above approaches are very realistic ways of effectively 'occupying' a +planet inhabited by another species. The planetary defenses of the besieger +play the role of an occupying army, while at the same time defending the colony +of the occupier. If the siege has a high effectiveness rating, then the +besieged species is in a quandry, especially if it has no hope of outside help. +Also, keep in mind that it's very difficult to hide a partially constructed +ship from the besieger. Since the besieger has people on the same planet, the +chance of detecting ship and PD construction will be 95%, regardless of the +actual siege effectiveness. + + +8.4.2 ASSIMILATION + +Another very real kind of occupation can occur if the besieger actually lives +on the besieged planet, shipping more and more of their own colonists there as +time goes on. Eventually, the original population becomes 'assimilated'. + +It is not realistic for a species to assimilate an entire home planet, since +the population to be assimilated is simply too large. (Consider the failed +Cardassian occupation of the Bajoran home world in the Star Trek stories.) +However, it should be possible to assimilate the population of a colony. +Something similar is actually happening today, here on Earth. For example, the +Indonesians have essentially occupied and are now assimilating the people of +East Timor, while the Chinese are doing the same in Tibet. In situations such +as these, a relatively small occupying population is in complete control of a +much larger native population because the occupiers control all of the weapons, +the government, industry, communications, the economy, and so on, while +continually shipping in more and more of their own people. + +In Far Horizons, a colony will be considered 'assimilated' if the besieging +species has a colony on the same planet, if the total population of the +besieging species is more than 20 percent of the population of the besieged +colony, and if the effectiveness of the siege is exactly 95 percent (i.e. the +highest possible value). Also, only population due to the installed mining and +manufacturing bases will be counted. (Population due to available population +units, planetary defense units and uninstalled colonist units will NOT be +counted, since they can be removed from the planet after assimilation takes +place.) Also, only the effective economic bases will be used; i.e., any base +over 200.0 will have only 5% of its actual value. (The purpose of this rule +is to prevent the unrealistic situation in which a besieged colony artificially +pumps up its economic base to prevent assimilation.) + +When these conditions have been met, HALF of the mining and manufacturing +base of the besieged colony will simply be transferred to the colony of the +besieger, and the besieged colony will, in effect, cease to exist. (The +remaining half is considered lost due to conversion inefficiency, low morale, +guerrilla resistance, costs of dealing with a hostile population, etc.) + +For example, the Human colony on Vega III is besieged by the Klingons, and the +overall effectiveness of the siege is 95 percent. On Vega III, the installed +population is 1,180,000 (mining base is 61.8 and the manufacturing base is +56.2). The Klingons also have a colony on the same planet, named Kitomer, with +a total installed population of 250,000. Since the conditions for assimilation +have been met, the computer will increase the mining base of Kitomer by 30.9 +and the manufacturing base by 28.1. In addition, any inventory on Vega III +will be transferred to Kitomer. The Human colony Vega III will effectively +disappear. From that point on, the Klingon player has complete control of +the Human population on the planet. In effect, the Humans have become +'assimilated'. + +If the siege is being conducted by more than one species that have colonies +on the planet, then the mining and manufacturing base will be allocated in +proportion to the relative siege effectiveness of each species. + +Some players may object to the 20% population ratio, saying that 20% is too +large, and that a value such as 10% or even smaller would be more realistic. +Keep in mind, though, that here on Earth we are all humans on our home planet. +Assimilating an alien species on an alien planet should be much more difficult. + + +8.5 SURPRISE + +In some situations, it may be possible for one species to take another +completely by surprise. For example, an ally that has ships in your system +may attack unexpectedly. If surprise occurs, the attacker will be given one +free round of attacks. Also, the defender's shields will be down during the +surprise round. (In Far Horizons, it is assumed that shields are never in use +unless absolutely necessary. Thus, when a ship is taken by surprise, it will +always be assumed that the shields are down. Note that this is similar to the +way shields are used in the Star Trek stories.) + +Surprise can only occur if you are attacked by a species that you have declared +to be an ALLY. + +If you suspect potential treachery, then give a BATTLE order for the location, +and also give any appropriate defensive ENGAGE orders. When this is done, +it will be assumed that you are on full alert, and will not allow any allies +to have a free round of surprise. Everyone at the location, however, will +definitely be aware of your heightened state of alert. + + +8.6 BETRAYAL + +If you are attacked by a species that you have declared ALLY, the status of +the attacker will automatically change to ENEMY after the combat or strike +phase in which the betrayal occurred. In effect, an "ENEMY SP Attacker" order +will be issued for you. + +If an ALLY is attacked by another ALLY, the status of the attacker will +automatically change from ALLY to ENEMY. In effect, an "ENEMY SP Attacker" +order will be issued for you. + +[We'll discuss how to declare enmity or alliance towards other species later.] + + +8.7 COMBAT LOG + +A complete log of the the fighting that takes place during a battle will be +sent to the players of the species involved. The log describes who fires on +whom, and whether or not the shot was successful. Since a battle contains +many misses, these logs can become very long and very boring. If you want to +receive only a brief summary of the results, then provide a SUMMARY command +after the BATTLE command. The SUMMARY command has no arguments. Here is an +example: + +START COMBAT +; Place combat orders here. + + BATTLE 4 12 3 + SUMMARY ;Log only the important stuff. + ENGAGE 1 ;Try to keep fight, if any, away from + ; colonies. + ENGAGE 2 4 ;Protect planet #4. + etc. + +END + +If a SUMMARY command is used, then only the important combat news will be sent +to the player. Various failures, misses, and hits that do not completely +destroy a ship or planetary defenses will not be reported. + +The gamemaster always has the option of turning on summary mode if he feels +that the logs are too long. + +During a battle, it's possible for cargo to be destroyed if damage passes +through the shields of a ship. Since this happens quite frequently, it is +NEVER reported in the combat log. You will only know about it after the battle +when you notice that some or all of the cargo is missing. + + +8.8 DAMAGE + +In FAR HORIZONS, damage done in combat is indicated by increasing a ship's age. +Thus, when a ship's age reaches 50, it is considered destroyed, since this is +the age at which a ship becomes 100% disfunctional. + +Ships which survive a battle, but which are badly damaged, can be repaired by +using the UPGRADE command, or can be "cashed in" by using the RECYCLE command. +Keep in mind, though, that these commands can only be used on planets that have +production capacity. If the ships are badly damaged and are not in the same +system as a producing planet that you control, they may have to jump to such +a planet, and may self-destruct in the process. + + +8.9 WITHDRAWING FROM COMBAT + +During the battle, your ships will have the option of withdrawing based on +conditions that you set using the WITHDRAW command. If ships do withdraw, they +will jump out of the sector to safety. You can also specify a rendezvous +point using the HAVEN command. The HAVEN command has the following format: + + Haven x y z + +where "x", "y", and "z" are coordinates where a ship should jump to if it +decides to withdraw from battle. If no HAVEN order is given, then the ship +will jump to a randomly selected location very close to the battle sector. +If a ship withdraws, then any explicit JUMP orders that appear in the jump +section of your orders will be ignored. (It is assumed that a ship that +withdraws from combat is likely to be damaged and that a normal, longer jump +will be too dangerous.) + +You may specify the conditions of withdrawal using the WITHDRAW command. Here +is the format: + + Withdraw n1 n2 n3 + + n1 = maximum acceptable transport age + n2 = maximum acceptable warship age + n3 = maximum acceptable fleet loss percentage + +The "fleet loss percentage" includes ships that have been destroyed or that +have already withdrawn. + +Here's an example: + +START COMBAT +; Place combat orders here. + + ;The following combat orders will be for the attack on the Romulan home + ; planet in their star system at 12 4 3... + + Battle 12 4 3 + Haven 10 3 3 + Withdraw 10 25 50 + +END + +In the above example, any ships that decide to withdraw will attempt to jump to +sector 10 3 3. An individual transport will withdraw if its age is greater +than 10. An individual warship will withdraw if its age is greater than 25. +The entire fleet will withdraw if at least 50% of the ships in the fleet have +either been destroyed or have already withdrawn. + +For the special case where the transport value is EXACTLY zero, transports will +only withdraw if the entire fleet withdraws. For the special case where the +fleet value is EXACTLY zero, the fleet will attempt to withdraw as soon as +possible after ANY battle begins. + +If no WITHDRAW order is given, the default will be: + + Withdraw 0 50 50 + +Thus, the default is to fight to the death. + +If a ship withdraws during the strike phase, then the ship name will contain +the designation "WD" in the status report. These ships will jump automatically +in the jump phase of the next turn, and any explicit jump orders will be +ignored. + + +8.10 AMBUSH + +If you suspect that one or more other species may jump into your system to do +battle, you may make advance preparations to 'ambush' them. You can do this by +providing an AMBUSH order. However, unlike other combat commands, the AMBUSH +command is given in the PRODUCTION phase of your orders - NOT in the combat +phase. The AMBUSH command takes a single argument which indicates how much you +will spend to prepare for the ambush. For example, if you suspect that the +Cardassians and their allies will jump to your Vega IV colony system during the +current turn in order to attack you in either the strike phase of the current +turn or in the combat phase of the next turn, you can issue the following order +in the production section for PL Vega IV: + +START PRODUCTION + PRODUCTION PL Vega IV + ; Place production orders here for planet Vega IV. + + Ambush 250 + +END + +This indicates that you expect enemies to arrive in your sector before the end +of the turn. + +To carry out the ambush, you should give appropriate combat orders in the +strike phase of the turn, as in the following example: + +START STRIKES + ; Place strike orders here. + + Battle 12 9 23 + Attack 0 ; Attack any declared enemies that arrive. +END + +You may also give appropriate ENGAGE orders if you wish to continue fighting +after the initial ambush. + +An ambush will provide your species with a number of 'free' attacks that will +damage and perhaps destroy enemy ships before any battle even begins. These +attacks will take place in deep space as the enemy ships arrive in your system. +The amount of damage done to the enemy will depend on how much you spent for +the ambush; that is, how well you prepared. + +Damage to the enemy will be measured in 'Effective Aging', which is calculated +as follows: + + 10,000 x Amount Spent + Effective Aging = ------------------------- + WT + TT/10 + +where WT = The total enemy warship tonnage in the star system immediately + before combat begins. + TT = The total enemy transport tonnage in the star system immediately + before combat begins. + +The 'Effective Aging' value will be added to the actual age of each enemy ship +immediately before any battle begins. If the resulting age is greater than 49, +then the ship is destroyed. + + Example: You expect that the Klingons will jump to the Earth system + during the current turn. In your production orders for PL Earth, you + provide the order AMBUSH 710. The Klingons arrive with three warships: + an FF (100,000 tons), a DD (150,000 tons), and a TR7 (70,000 tons). + Thus, the 'Effective Aging' value will be: + + + 10,000 x 710 + --------------------------------- = 27.63 = 27 + 100,000 + 150,000 + 70,000/10 + + +Note that fractions are dropped. + +Thus, the age of each enemy ship will be increased by 27 turns immediately +before the battle, if any, begins. In a situation such as the above, the +ambush could be absolutely crippling. + +In order for the ambush to take effect, you must issue an appropriate BATTLE +order and one or more ATTACK orders during the strike phase, so that the +computer will know who you consider an enemy. You may also provide any +appropriate offensive and/or defensive ENGAGE options. Any normal combat +will occur AFTER the ambush. + +If the enemy does not arrive or if you do not issue any ATTACK orders, then the +amount spent for the ambush will have been wasted. + +A planet that is under siege may NOT issue an AMBUSH order. + +Amounts spent on an ambush are cumulative. Thus, if two or more planets in the +same star system issue AMBUSH orders, the effectiveness will be based on the +total amount spent. Results are also cumulative if two or more species +collaborate in an ambush. + +The actual details of the ambush are not important, since Far Horizons is a +strategic game - not a tactical one. However, an ambush could involve ships +waiting in hiding among asteroids, use of space mines, subterfuge, and so on. + +Since an ambush is essentially a way to 'purchase victory', there must be a +realistic limitation on how much can be achieved. It makes no sense, for +example, for a rich but poorly defended colony to be able to wipe out a +powerful invasion force. In Far Horizons, we will simulate this reality as +follows: + + The amount of effective aging that results from an ambush will + be limited by the ratio of the warship tonnages present at the + ambush. + +For example, if the warship tonnage of the ambushing forces is on par with +the warship tonnage of the ambushed forces, then the full ambushing effect +described above will take place. If, however, the ambushing forces are +considerably weaker than the ambushed forces, then the net effective aging +will be reduced. And if the ambushing forces are considerably stronger than +the ambushed forces, then the effective aging will be increased. + +Finally, it is much easier to ambush enemy ships if they enter the sector via a +natural wormhole, since the ambushing species knows the precise exit point and +can concentrate more of its forces at that point. + +To simulate this reality, a ship that is ambushed as it exits a natural +wormhole will experience DOUBLE the calculated age increase. Thus, if any of +the ships in the above example had arrived via a natural wormhole, then their +ages would have been increased by 2 x 27 = 54, which would have immediately +destroyed them. + + +8.11 INTERCEPTION + +There may be times when you wish to intercept and destroy a ship that jumps +into one of your star systems before it can scan or learn anything about your +inhabited planets. For this purpose, use the INTERCEPT command. + +The intercept command is like the AMBUSH command because it appears in the +production section of your orders and because you must specify the amount you +are willing to spend for the interception. However, it is different because +the results are applied immediately - you will attempt to destroy any enemy +ship that jumps into your system the moment it arrives, rather than wait until +the combat phase of the next turn. + +It is also different because an ambush implies advance knowledge of who is +coming and when they are coming. Interception implies a general state of alert +without any advance knowledge. Thus, interception is inherently more difficult +than ambushing, and has a higher cost for the same results. + +When an INTERCEPT order is given in the production phase of your orders, it +will apply immediately to any enemy ships that enter the system during the +current turn. You can specify which species are enemies using the ENEMY +command. The ENEMY command can appear in either the pre-departure, production, +or post-arrival section of your orders. Here are some examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Enemy SP Klingon + ENEMY SP Romulan + enem 999 ; ALL species are my enemies. + +END + +The ENEMY command takes a single argument, either a name of a species or a +number. If it is a number, it states that all species in the game (even those +you have not yet met) are your enemies. Otherwise it states that the indicated +species is your enemy. You may specify an enemy command for as many species as +you want. When the argument is a number, any number may be used - the actual +value is not important. + +An ENEMY command remains in effect until cancelled. You can cancel an ENEMY +command with either the NEUTRAL or ALLY commands. These also can appear in +either the pre-departure, production, or post-arrival phase of the turn: + +START POST-ARRIVAL +; Place pre-departure orders here. + + Neutral SP Klingon + Neutral 7 ; I am neutral towards everyone. + Ally sp klingon ; The Klingons are now my allies. + +END + +Again, a numeric argument (regardless of value) may be used to indicate +neutrality towards ALL species in the game, even those you have not yet met. +However, a numeric argument may NOT be used with the ALLY command. You can +name one and only one species in an ALLY command, and you must have already +met the species before you may declare alliance. + +If you wish to declare that everyone in the game is an enemy EXCEPT one or +more other species, declare everyone an enemy and then use the NEUTRAL or +ALLY commands for the non-enemies. For example: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Enem 111 ; Everyone is my enemy... + Ally SP Vulcan ; ...except the Vulcans (our allies) + NEUTRAL SP Bajoran ; ...and the Bajorans (who I'm not sure of yet) + +END + +ENEMY, ALLY, and NEUTRAL orders will remain in effect until cancelled. + +Unless you specify otherwise, the computer will assume that you are neutral +towards all species in the game. When you meet a species for the first time, +the computer will assume that you are neutral towards it, unless you have +previously issued an ENEMY order with a numeric argument. + +When an INTERCEPT order is executed, the computer will check if any enemy +ships have successfully jumped into the star system of the producing planet +during the current turn. If so, the total amount spent for interception on +all planets in the star system will be applied to the enemy ships that just +arrived, one at a time, until all ships are destroyed or until funds run out, +whichever comes first. Ships will be chosen in random order, so as not to +bias the results against any one enemy species. + +The amount needed to destroy an enemy ship can be calculated as follows: + + + 100 x warship tonnage + Cost = -------------------------- + 10,000 + + +The cost needed to intercept and destroy a transport will be one-tenth of the +cost for a warship of the same tonnage. + +Note that, unlike an ambush, the ships are not aged - they are either +completely destroyed or completely unharmed. If there are not enough funds +to destroy the current randomly selected ship, then the interception process +ends, and all remaining funds, if any, are wasted. + +For example, let's say that three enemy ships successfully jump into the Earth +solar system. The first is a 150,000 ton Klingon destroyer, the second is a +50,000 ton Romulan escort, and the third is a 50,000 ton Romulan transport. +In the same turn, the production orders for Earth and Mars (in the same star +system) contain the orders: + +START PRODUCTION + PRODUCTION PL Earth + ; Place production orders here for planet Earth. + + Intercept 450 + + PRODUCTION PL Mars + ; Place production orders here for planet Mars. + + Int 100 + +END + +Thus, the total amount spent on interception is 550. + +At the end of production for your species, the computer randomly selects the +50,000 ton Romulan escort as the first ship for interception. The cost is: + + 100 x 50,000 + ------------- = 500 + 10,000 + +Since the current balance is 550, the escort is destroyed and the new balance +is 550 - 500 = 50. If the computer then randomly selects the destroyer for +destruction, the interception process immediately ends because the balance of +50 is not enough to destroy the destroyer (1500 needed), EVEN THOUGH IT IS +ENOUGH TO DESTROY THE TRANSPORT! Thus, both the destroyer and the transport +will be unharmed. If the computer had randomly selected the transport before +the destroyer, then the transport would have been destroyed. + +This element of chance is intentional, since an interception is inherently less +reliable and more 'chancy' than an ambush. + +Note that the three enemy ships do not have to be owned by the same species. + +All species involved in an intercept will be notified of the results in their +status reports. The species that owns the ships that were destroyed will only +be informed that the ships disappeared without a trace, cause unknown. Thus, +the intercepted species will not know if the ship was destroyed by an enemy, +or if it self-destructed on its own. + +You may give both INTERCEPT and AMBUSH orders in your production orders. +Obviously, INTERCEPT orders will apply immediately, while AMBUSH orders will +take effect at the very beginning of the combat phase of the next turn. + +Anything spent on interception is wasted if no enemy ships jump into the +system; i.e., the amount spent does NOT carry over into the next turn. A +planet that is under siege cannot issue INTERCEPT orders. Interceptions by +more than one species in the same star system are NOT combined - they are +each handled separately. + +If an interception fails completely, the intended victim will not be told that +an interception had been planned, and will remain completely in the dark. + +Interception will only be used against ships that enter the sector via a JUMP, +PJUMP, or WORMHOLE command. Interception cannot be used against ships that +MOVE into a sector. + +[A ship that MOVEs into a system is moving at sub-light speeds and will have +telemetry of the space ahead, as well as the time to analyze the telemetry. +An INTERCEPT takes advantage of the "timelessness" of the jump and the complete +lack of data about the destination until the moment of emergence from the +wormhole.] + +The main purpose of an interception is to prevent exploratory vessels from +learning about the inhabitants of a star system. It is NOT intended as +a replacement for normal combat. To reflect this reality, the INTERCEPT +command will be limited as follows: + + The maximum size of a ship that may be successfully intercepted + is 50,000 tons for warships and 200,000 tons for transports. If + the random selection process described above selects a larger + ship, then the selection process will abruptly end. + +For example, if three ships are randomly selected in the order , then only the first picketboat will be destroyed, +even if there were sufficient funds allocated to destroy all three ships. + +There is one major exception to the above rules regarding interception. +Interception of a ship is much easier when the ship is exiting a natural +wormhole, since the intercepting species knows the precise exit point and +can concentrate more of its forces at that point. + +To simulate this reality, the above tonnage limitations will NOT apply if the +intercepted ship entered the sector via a natural wormhole. In other words, +any ship can be intercepted and destroyed, REGARDLESS OF SIZE, if it enters the +sector via a natural wormhole and if sufficient funds have been allocated for +the interception. + + +8.12 STRATEGIC TARGETS + +In general, an attacker will try to concentrate fire on the most powerful +targets in order to eliminate them as quickly as possible. Smaller targets +will generally be ignored until all of the more dangerous opponents are +eliminated. Thus, if you have a large number of small ships (i.e. "cannon +fodder") and hope that they'll draw the fire of more powerful opponents, you'll +be disappointed. Attackers will rarely waste shots on puny targets as long as +larger prey are available. + +In some battles, however, you may want to concentrate your fire on targets of a +specific type. For example, if you suspect that enemy transports are carrying +germ warfare bombs, you may want to concentrate your fire on transports as long +as they are within range. To specify a favorite target for a battle, use the +TARGET command, as follows: + + Target 1 ; Concentrate fire on warships. + Target 2 ; Concentrate fire on transports. + Target 3 ; Concentrate fire on starbases. + Target 4 ; Concentrate fire on planetary defense units. + +Only one TARGET order may be given per battle. If more than one is given then +only the last one will be effective. + +The TARGET command simply indicates that you want to concentrate fire on units +of the selected type. However, it does not guarantee that you will ONLY fire +on the selected targets. The tactical situation may either prevent you from +firing on a selected target or may force you to attack a different target. For +example, if there are no more enemy units of the selected type, then your units +will fire on any available enemy units. + + +8.13 THE STRIKE PHASE + +Combat can take place either in the combat phase or in the strike phase. + +All combat orders and engagement options are allowed in the combat phase. + +All combat orders are allowed in the strike phase. However, engagement options +for planet bombardment, germ warfare, and sieges are not allowed in the strike +phase. + +In effect, the strike phase is a limited-combat phase, And any combat that does +take place in the strike phase generally takes the form of an initial surprise +attack. Combat that requires more time, such as bombardment and siege, +will take place in the combat phase of the following turn, and is thus +a continuation of the combat that began in the strike phase. + +Note that, even though a turn break occurs between the strike phase of one turn +and the combat phase of the following turn, no actual game time passes. + + +8.14 PICKET DUTY + +There may be times when you need to intercept enemy ships, but the INTERCEPT +command will not work. For example, the ships may be too large, or they may be +entering the sector via the MOVE command. In situations like these, you can +effectively intercept enemy ships in the strike phase - IF you have the +firepower. Here's how to do it: + +START STRIKES +; Place strike orders here. + + Battle x y z + Attack SP name + Engage 3 ; Deep space attack. +END + +If you win the battle, the intruding ships will be destroyed before they can +learn much about the sector. + +Note that the above battle will not prevent the intruder from doing a scan +during the post-arrival phase, but it WILL keep it from learning about who has +colonies in the sector, what their economic bases are, and which non-attacking +species, ships, and starbases are also in the sector. The intruder will only +know that the attacker probably (but not necessarily!) inhabits the sector. + +However, there is still one potential problem. If the intruder MOVEs to your +sector and then ORBITs a planet, the above orders would not have the desired +effect. This is because an "ENGAGE 3" order only tells your ships to attack +enemy ships that are in deep space. You can, of course, give "ENGAGE 4 n" +orders for all of the planets in the system, but this is a nuisance. + +Instead, a special rule will apply in this kind of situation: the computer will +reject a post-arrival ORBIT order for a ship that has just MOVEd into a sector. +If necessary, the ORBIT order can be given in the pre-departure phase of the +next turn. + + +8.15 HIDING YOUR STRENGTH + +There may be times when you wish to engage in combat with an enemy, but you do +not want to show your full strength. For example, let's say that you have a +large fleet landed on a planet where the enemy cannot detect it. If you want +to attack a single, small, enemy ship, you can do so using the commands +described earlier. However, ALL of your ships will take part in the battle, +and the enemy will learn your total strength in that sector. + +To deal with this problem, you can use the HIDE command to tell the computer +that specific ships are NOT to take part in combat unless absolutely necessary. +Here's an example: + +START COMBAT +; Place combat orders here. + + Battle 23 17 3 + Attack SP Klingon + Attack SP Romulan + Engage 3 ; Deep space attack. + Hide DN Omigosh ; These ships should not fight unless we're + Hide BS Thunderclap ; losing the battle. + Hide BCS Whopper + +END + +In the above example, all of your warships in the sector will take part in the +deep space attack except DN Omigosh, BS Thunderclap, and BCS Whopper. They +will only join the battle if you are losing. + +You may only give a HIDE order to ships that are landed on the surface of a +planet. HIDE orders given to ships in orbit or in deep space will be ignored. + +If you give a HIDE order to a transport, the enemy will only be allowed to +attack it if you start losing the battle. + +A ship that is given a HIDE order will not take part in any subsequent +bombardment or siege, unless it also took part in the battle. + +Keep in mind that there may be a risk in using the HIDE command. If you +misjudge the enemy's strength, they may be able to destroy your front guard +before the reserves join the fight. On the other hand, if all ships had been +in the battle from the beginning, enemy fire could have been spread so thin +that none of them would have been damaged. + + +8.16 HIJACKING + +The HIJACK command should be used if you do NOT want to destroy enemy ships, +but instead want to capture them. The captured ships and cargo can then be +sold for profit, and the crew and passengers can then be ransomed or sold into +slavery. The HIJACK command should be used instead of the ATTACK command, as +in the following example: + +START COMBAT +; Place combat orders here. + + Battle 10 25 12 + Attack SP Klingon ; Attack the Klingons and attempt to destroy + ; their ships. + Hijack SP Romulan ; Attack the Romulans and attempt to capture + ; their ships. + Engage 3 ; Attack them in deep space... + Engage 5 2 ; and at planet 2, and bombard the planet if + ; possible afterwards, ... + Engage 7 3 ; and at planet 3, and besiege the planet if + ; possible afterwards. +END + +Hijacking may also be attempted in the strike phase. + +When attempting to HIJACK the ships of another species, combat will occur in +the usual way, but the hijacking ships will have only 25% of their normal +offensive and defensive combat capabilities. If an enemy ship is then +"destroyed", it will be considered effectively "hijacked". If you ATTACK one +or more species while HIJACKing one or more other species in the same battle, +then your ships will have the reduced combat capabilities whether they are +ATTACKing or HIJACKing. Because of this, it may not be a good idea to do both +unless you have vastly superior forces. + +Hijacked ships and cargo will be automatically sold, and economic units will be +added to the treasury of the hijacking species. The number of economic units +received will be equal to the normal recycle value of the hijacked ships and +their cargo. + +You may NOT hijack planetary defense units. If successfully attacked, they +will be destroyed. + +If additional combat operations take place after the hijacking (such as +bombardment or siege), the attacking ships will have their full, normal +combat capability. + + + +9.0 MISCELLANEOUS OPERATIONS + +Commands and other operations that do not belong in any of the previous +chapters will be discussed here. + + +9.1 SCAN ORDERS + +If you wish to receive information about a star system, you must order a ship +to do a sensor scan. Use the SCAN command to do this. For example: + +START POST-ARRIVAL +; Place post-arrival orders here. + + SCAN TR1 Intrepid + +END + +The SCAN command may only be issued in the pre-departure or post-arrival +sections of your orders. + +If the ship mis-jumped to the scan location during the jump phase, then a scan +order issued in the post-arrival phase will still be executed, but it won't +detect anything unless it mis-jumped to coordinates that contain a star system, +which is highly unlikely. + +A scan only tells you about the physical characteristics of the planets in +the sector. It does NOT tell you which planets are populated, or if there are +other ships in the sector. This additional information is always automatically +provided on your status report, whether or not you give a SCAN order. +Remember, though, that you will never be able to detect ships that have landed +on a populated planet unless you also have population on the same planet. + +If you have a ship or a populated planet in a star system that has one or more +alien inhabited planets, your status report will also provide an approximate +indication of the amount of commercial and industrial activity on those +planets. The activity will be indicated as in the following example: + + Colony planet PL Dizzy (planet #2) SP Goofballs + (Economic base is approximately 210.) + +This simply indicates that a planet named "Dizzy" is colonized by a species +named "Goofballs", and that the sum of mining base plus manufacturing base +on the planet is approximately 210. Again, this information is provided +automatically on your status report - there is no need to provide a SCAN +order. + + +9.2 MESSAGES + +You can send a message to any species you know of with the MESSAGE command. +Messages may be sent in either the pre-departure or post-arrival phase of +the turn. Here are some examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + MESSAGE SP Klingons + + My email address is goofy@bubblegum.gov. Please contact me ASAP! + + ZZZ + +END + +START POST-ARRIVAL +; Place post-arrival orders here. + +Mes SP Romulans +Please do not be alarmed at the size of the fleet in your home system. We're +simply using your home system as a rest stop on our way to another location. +Rest assured that we have no ill intentions towards you. +zzz + +END + +Messages can be as long as you wish. Make sure to end the message with a line +containing the command ZZZ. Also make sure that none of the lines in the +message itself start with the letters "zzz". + + +9.3 TRANSFERRING ECONOMIC UNITS + +To transfer economic units to another species, use the "SEND" command. For +example, if you wish to transfer 250 economic units to the Klingons, you +should give the following order: + + Send 250 SP Klingon + +You may not SEND economic units to a species that you have declared to be an +ENEMY. If you wish to SEND economic units to an ENEMY, make a temporary +declaration of neutrality, as in the following example: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Neutral SP Tholian + Send 500 SP Tholian + Enemy SP Tholian +END + +A SEND order must appear in the pre-departure or post-arrival section of your +orders - NOT during production! + + +9.4 KNOWLEDGE TRANSFERS + +In Far Horizons, a donor species may transfer knowledge to a recipient species +using the TEACH command, as in the following examples: + + Teach GV SP Klingon + + Teach BI 17 SP Klingon + +where the maximum tech level to be taught is optional. If not specified, then +the actual tech level of the teacher will be used. + +TEACH orders may only appear in the post-arrival section of your orders. + +You may not TEACH a species you haven't yet met. + +When a TEACH order is executed, the computer simply notes that you have +obtained knowledge associated with a tech level. If you then RESEARCH the +technology in a later turn, there will be no randomness in achieving the new +tech level, since you already have the needed knowledge. Instead, the funds +will be used to perform the necessary engineering and to spread the new +technology throughout the species. In effect, the research funds will be +used directly to 'purchase' the new tech level. + +Since the basic research is eliminated, the randomness is also eliminated +and the cost is reduced. However, the recipient must still do the initial +engineering and development work. Thus, the cost of a tech increase will be +less than the cost of solitary research. + +On average, if you wish to increase a tech level by one point using normal, +unaided research, then the average cost will be the current tech level times +itself. For example, if the current Biology tech level is 9, then the basic +cost to increase the tech level from 9 to 10 is 9x9 = 81. Keep in mind, +though, that this is an AVERAGE value. Basic research is highly random. + +Now, if another species first transfers the knowledge to you via the TEACH +command, then there will be a 25% discount on the basic cost of research, and +there will be no randomness at all. + +For example, SP Human gives the following post-arrival order: + + Teach GV 20 SP Klingon + +In the next turn, the Klingons have a gravitics tech level of 18 and give the +following production order: + + Research 750 GV + +When this order is processed, the Klingon gravitics tech level will immediately +rise as follows: + + cost for 18 to 19 = 18 x 18 - 25% discount = 324 - 81 = 243 + cost for 19 to 20 = 19 x 19 - 25% discount = 361 - 90 = 271 + + total cost using transferred knowledge = 243 + 271 = 514 + +The remaining funds (750 - 514 = 236) will be allocated to additional, normal +research in gravitics. + +If knowledge has been transferred to you but has not yet been applied, the +usable knowledge level will appear in your status report as in the following +example: + +Tech Levels: + Mining = 17/21 + Manufacturing = 17 + Military = 9 + Gravitics = 8 + Life Support = 13/14 + Biology = 4 + +The above indicates that your mining tech level is 17, but that you have +knowledge up to 21. Similarly for life support. + +There is no limit to how much technical knowledge may be transferred in a +single turn. As long as the donor's tech level is high enough, the transfer +will take place. + +You may NOT transfer knowledge to a species that you have declared to be +an ENEMY. If you wish to transfer knowledge to an ENEMY, make a temporary +declaration of neutrality, as in the following example: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Neutral SP Klingon + Teach GV 20 SP Klingon + Enemy SP Klingon +END + +TEACH orders will not be logged in the donor's status report. They will be +logged in the recipient's report ONLY if they succeed in raising the knowledge +level of the recipient. + + + IMPORTANT!!! + + It is strictly forbidden to attempt to transfer knowledge to + a species that does not want it or which is not expecting it. + This is necessary because some species may not want certain + types of knowledge for role-playing reasons. Any player that + intentionally breaks this rule will be evicted from the game. + + +9.5 ESTIMATING THE TECH LEVELS OF OTHER SPECIES + +At any time after meeting another species, you many analyze all of the +information you have about the species and estimate their tech levels. To do +this, issue the ESTIMATE command in the production section of your orders for +a planet. Here is an example: + +START PRODUCTION + PRODUCTION PL Dagwood + ; Place production orders here for planet Dagwood. + + Estimate SP Klingon + +END + +Each estimate has a cost of 25. You will receive an estimate of all six tech +levels for the species. + +The accuracy of your estimate will depend on how high your tech level is +compared to the same technology for the other species. If your tech level is +significantly higher than the level for the other species, then the estimate +will be very accurate. At the opposite extreme, if your tech level is much +lower than the level of the other species, then the estimate may not be very +accurate. + + +9.6 DISBANDING A COLONY + +There may be situations when it is desirable to disband a colony. For example, +you may be ordered to leave by a more powerful enemy who will destroy the +colony if you don't obey. In this case, it would be better to remove the +colony peacefully, and perhaps salvage some of your investment, than to fight +a battle that you know you cannot win. + +If you decide to disband a colony, for whatever reason, you should use the +DISBAND command in the pre-departure section of your orders. For example, + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Disband PL Vega III + +END + +You may NOT disband your home planet. + +You may NOT disband a colony that is under siege. + +When processing a DISBAND order, the computer will do the following: + + 1. Any mining base and manufacturing base will be converted + to Colonist Units, Colonial Mining Units, and Colonial + Manufacturing Units; i.e. exactly the reverse of the INSTALL + command. However, IUs and AUs will only be converted at 50% + efficiency. For example, a mining base of 21.3 will produce + 213 CUs, but only 106 IUs. + + 2. The computer will mark the colony as "disbanded". + + 3. At the end of the turn (after the post-arrival phase) the + computer will convert anything of value that is left on the + "disbanded" planet to economic units, and will automatically + transfer the economic units to the balance for the species. Any + ships that are landed on the planet and any starbases orbiting + the planet plus any cargo that they carry will be salvaged, even + ships that were under construction. The amount of economic units + obtained by salvaging will be ONE-HALF of their total RECYCLE + value (see section 5.10 for information about recycling). + +When a colony is marked as "disbanded", any ships on the surface, including +ships that are still under construction, and any starbases in orbit are marked +as "salvage". If you LAND a ship on the planet after the DISBAND order, it +will also be marked as "salvage". If you ORBIT a starbase around the colony +after the DISBAND order, it will also be marked as "salvage". You may not give +any MOVE, ORBIT, JUMP, PJUMP, or WORMHOLE orders to a ship or starbase that has +been marked as "salvage". Thus, it is important to issue any LAND or ORBIT +orders BEFORE giving the DISBAND order. + +In the pre-departure section of your orders, immediately after the DISBAND +order, you can fill up any other ships and transports with the CUs, IUs, AUs, +and anything else that is on the planet, and give these ships orders to leave +in the jump section of your orders. In other words, the "disbanded" colony and +"salvage" ships and starbases may still take part in TRANSFER commands after +the DISBAND order has been given. In this way, you can TRANFSER any items of +value that are on the planet or on the "salvage" ships to other ships or even +to other planets in the star system. If you have any jump portals in the star +system, you may use them as well, including any jump portal starbases that have +been marked as "salvage" (see section on high tech items for more information +about jump portals). + +After the post-arrival phase, any items and ships that are on a "disbanded" +planet and starbases that are in orbit around the planet will be salvaged, +even if they were not there when the DISBAND order was executed. If these +ships or starbases have cargo, then the cargo will also be salvaged. The +actual details of the salvaging operation are not important. (Possible +scenarios: 1. The people on the planet commandeer all commercial vessals in the +system, load them up, and escape. 2. The people on the planet negotiate with +the enemy for a little more time to disband. 3. If there is time, the people +and the government can hire commercial spacelines, or even professional +salvaging companies to disband the colony. And so on.) + +The DISBAND command will completely delete all information about the planet, +even its name. Thus, you may also use this command to delete a planet that +you have named but have not yet colonized. + + +9.7 DESTROYING SHIPS AND STARBASES + +If you want to destroy a ship or starbase (for whatever reason), use the +DESTROY command, as in the following examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Destroy BAS One Shot + DES CTS Billy Joe Bob + dest TR4 Lollipop +END + +When the DESTROY order is executed, the ship or starbase and all of its +contents are blown to smithereens. Nothing is salvaged. + +The DESTROY command may be used in either the pre-departure or the post-arrival +phase of the turn. + +Unlike the RECYCLE command, the DESTROY command may be used anywhere - the ship +or starbase does not have to be at a planet or in a star system. + +The fate of the crew of the destroyed ship or starbase depends on the species. +Some will commit suicide, some will choose to die with the ship, others may +escape in lifeboats, and so on. It's entirely up to the player. + + +9.8 THE "DEVELOP" COMMAND + +It's easy to make mistakes when calculating the number of IUs and AUs needed +for a colony. If the number of units is not properly balanced (based on the +mining difficulty), then you'll either have excessive production capacity or +excessive raw material units. + +The DEVELOP command was implemented to do these calculations for you, and to +save you some time in other ways as well. + +The DEVELOP command has three modes of operation. In the first mode, the +command has two arguments: the name of the colony and the name of the transport +that will carry the CUs, IUs, and AUs. Here is an example: + +START PRODUCTION + PRODUCTION PL Earth + ; Place production orders here for planet Earth. + + Develop PL Orion 7, TR20 Tubby + +END + +For the above order, the computer will first determine the current cargo +capacity of the transport. If the colony is a normal colony (as opposed to a +resort or mining colony) and has the resources to build its own IUs and AUs, +then the computer will build only CUs to fill the transport; otherwise it will +build the correct balance of CUs, IUs, and AUs based on the mining difficulty +of the planet. If the colony is a resort colony, then only CUs and AUs will be +built. If the colony is a mining colony, then only CUs and IUs will be built. +If only CUs are being sent to the colony, then the computer will also generate +orders for the colony to build the correct amount of IUs and AUs based on the +mining difficulty. (Why waste cargo space for IUs and AUs? Let the colony +build them!) These orders will be placed in the orders section at the end +of the status report. + +[Incidentally, when the DEVELOP command is processed, the computer can not +predict exactly what the production will be on the colony during the next turn. +For example, the computer does not know what the fleet maintenance cost will +be, and cannot predict if the player will be doing other production on the +colony. Because of this, it makes a very conservative estimate of the next +turn's production. The result may be that the transport carries IUs and AUs +that the colony is capable of building itself. However, this will not be a +serious problem because it will only occur once or twice, when the colony is +still relatively small.] + +If the colony is not yet colonized, or if it does not have sufficient +production capacity to build its own IUs and AUs, then the computer will fill +the remaining cargo space of the transport with a correct balance of CUs, IUs, +and AUs based on the planet's mining difficulty. Note that this will only work +for normal colonies. If you want to start a mining or resort colony, do not +use the DEVELOP command. However, the DEVELOP command may be used AFTER the +mining or resort colony has been started. + +At the end of production, any CUs, IUs, and AUs will be loaded onto the +transport. Also, an order will be automatically generated for the transport to +jump to the colony. This order will be placed in the order section at the end +of your status report. This assumes, of course, that the ship is in the same +sector as the producing planet. If not, the items will remain on the surface +of the planet and no JUMP order will be given for the ship. + +If you want to load other cargo onto the transport, make sure to do so BEFORE +issuing a DEVELOP order. A DEVELOP order will use all remaining unused cargo +space. + +Note that the DEVELOP order must be given in the production phase of your +orders. + +In the second mode of operation, no transport is mentioned. Instead, it is +assumed that the colony is in the same sector as the producing planet. Here +is an example: + +START PRODUCTION + PRODUCTION PL Earth + ; Place production orders here for planet Earth. + + Dev PL Venus + +END + +The above order is similar to the previous one, except that the remaining +available population of the PRODUCING planet will be used, and the items will +be automatically transferred to the colony instead of to a transport. In +addition, an order will be automatically generated for the next turn to +install the units on the colony. + +Since this mode uses the available population of the PRODUCING planet, this +order should be placed after any other orders are given to build CUs or PDs. + +In the third mode of operation, the command should be given on the colony +itself and has no arguments. Here is an example: + +START PRODUCTION + PRODUCTION PL Venus + ; Place production orders here for planet Venus. + + DEV + +END + +For the above order, the computer will build X CUs, where X is equal to the +remaining available population, and a correct balance of IUs and AUs based on +the mining difficulty of the planet. It will also automatically generate +INSTALL orders for the next turn to install the units. Note that this command +cannot be given on a mining or resort colony, since it has no production +capability. + +If you do not have sufficient funds to utilize all of the available population +or transport cargo capacity, then the computer will use the available funds as +the limiting factor. Note that the computer WILL spend economic units from the +treasury, if needed. + +In all of the above modes, you may optionally specify a spending limit. Here's +an example: + +START PRODUCTION + PRODUCTION PL Earth + ; Place production orders here for planet Earth. + + Dev 450 PL Venus + +END + +In the above example, no more than 450 will be spent to develop the planet +Venus even if you have more available funds or available population. + +Normally, you may not DEVELOP a home planet. However, if the home planet has +been bombed, then you may use the DEVELOP command to bring it back to its +original value. + + +9.9 THE "AUTO" COMMAND + +Far Horizons is a complicated simulation, and providing orders for all of your +ships and planets can be both tedious and time-consuming, especially in later +stages of the game when empires become very large. The AUTO command is +intended to reduce the tedium and make it less likely that mistakes or +omissions will occur. + +The AUTO command should be given in the post-arrival phase of your orders. It +has no arguments: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Auto + +END + +The AUTO command instructs the computer to automatically generate reasonable +orders for your ships and planets FOR THE NEXT TURN and to place these orders +in the appropriate places in the orders section of the status report. The +AUTO command will generate orders to accomplish the following: + + 1. If a transport has colonist units in it, is not in the home + sector, and is orbiting or landed on a planet whose economic + base is less than 200, then an UNLOAD order will be generated + for the transport, and it will be given an order to JUMP to the + planet where it was most recently loaded with CUs (typically the + homeworld). Also, a DEVELOP command will be generated for the + destination planet to prepare colonists for the same colony + using the same transport. + + 2. Since TR1s are normally used for scouting, JUMP orders will + be started for all TR1s. The destination will be the closest star + that has not yet been visited by your species. If you've already + visited all stars in the galaxy, then the destination will be "???". + The order will be commented with the age and current location of + the ship, plus the mishap chance for the jump. + + 3. All other ships will be issued JUMP orders with the destination + "???". The order will be commented with the age and current + location of the ship. + + 4. If a planet will have excess raw material units in the next + turn, an order will be generated to recycle them. + + 5. If a colony has an economic base less than 200 and if it has + an available population greater than zero, then a DEVELOP order + will be generated for it. + + 6. For the home planet and any colonies that have an economic + base of 200 or more, a check will be made to see if any other + colonies in the same sector have an economic base less than 200. + If so, then orders will be generated to DEVELOP those colonies. + + 7. Starbases will be given orders to increase their sizes up + to the MA tech limit. A comment will indicate the current size. + + 8. Ships that are still under construction will be given orders + to complete their construction. A comment will indicate the amount + left to pay. + + 9. If a TR1 is in a sector that you do not inhabit, the computer + will assume that it is a scouting vessel and will generate a + SCAN order for it in the post-arrival phase. + + 10. An AUTO command will be generated for the next turn. + +Obviously, if you do not agree with a particular order, you can simply delete +it or change it to something more desirable. For example, if an order is +automatically generated to develop your Rigel colony, you can manually change +it to develop your Arcturus colony instead. + + +9.10 THE "VISITED" COMMAND + +The AUTO command generates orders for TR1s to JUMP to the nearest sector that +your species has not yet visited. However, the computer has no way of knowing +if another player gives you a scan of an unvisited sector. The VISITED command +tells the computer that you already have a scan of a sector and that you do not +want it to generate JUMP orders to go there for your TR1s. Here are some +examples: + +START JUMPS +; Place jump orders here. + + Vis 31 12 18 ; We just received scans of these sectors + VISIT 33 9 10 ; from our allies. + +END + +A VISITED order must appear in the JUMP section of your orders, and the x, y, +and z coordinates must apply to a sector that has a star. If the sector does +not have a star, then the order will be ignored. + +Also, whenever you NAME a planet, the sector will me marked as visited by your +species even if you have not actually been there. + + + +10.0 MISCELLANY + +This chapter will cover those aspects of the game that do not quite belong +in any of the other chapters. Since it is also the last chapter, it is an +ideal place to make additions, corrections, threats, etc. without throwing +everything else out of kilter. Thus, this chapter is probably the most +important one in the rules. + + +10.1 HIGH-TECH ITEMS + +Appendix A of this manual contains a list of high-tech items that your species +will be able to build when it achieves certain minimum tech levels. You will +be notified on your status report whenever this occurs. The descriptions of +the high-tech items are self-explanatory. + +All high-tech items must be built in a single turn, unless specified otherwise. + + +10.2 COMMUNICATION BETWEEN PLAYERS + +Players who wish to keep their real identities anonymous may do so. You may +send a message to another species via the MESSAGE command. The recipient +will only know the name of the species who sent the message. If you wish to +communicate directly with other players, you can send them your email address +with the MESSAGE command. + +In addition, some gamemasters may provide a list server at their email site +that will allow players to send messages to other players using species names +rather than player addresses. It will also allow you to broadcast messages to +all other players, anonymously or non-anonymously. + + +10.3 INTERSPECIES TRANSFERS + +It is not practical or realistic to allow items or ships to be transferred from +one species to another. Items built for one species are not likely to be +suitable for use by a different species. The easiest and least expensive way +to give something to another species is to give them economic units, discussed +earlier. You may also build items and ships SPECIFICALLY for another species. +This will be discussed later in the section on 'interspecies construction'. + + +10.4 QUESTIONS + +Questions for the gamemaster should NOT be sent with your orders for the turn. +You should send any questions to the gamemaster in a separate email message. +It is quite possible that the gamemaster will never even see your orders, but +will simply feed them to the computer. + + +10.5 USE PLANET NAMES, NOT NUMBERS! + +The precise designation for a planet is "X Y Z N", where "N" is the number of +the planet in the star system. This complete designation is only allowed in +the NAME command, discussed earlier. Planet numbers are also needed in some +combat commands, and may be used in the LAND and ORBIT commands. In all other +commands, planet names MUST be used if you need to refer to a specific planet, +such as "PL Earth". You may NEVER use planet names assigned by other species. +When processing YOUR orders, the computer is only aware of names that YOU have +assigned. (There is one exception to this - the PJUMP command - which will be +discussed later in the section on Jump Portals.) + +If a star system has one or more planets with names, you may still refer to the +star system by using the X, Y, and Z coordinates, but this is not recommended. +If you mis-type a planet name, the gamemaster will be notified by the computer +and can correct the mis-spelling. If you mis-type a coordinate, however, the +gamemaster is not likely to know your intentions, even if an error is reported +by the computer. Furthermore, if it is a JUMP order, your ship may mis-jump or +even self-destruct. However, you should avoid giving names to planets that you +have not colonized, unless you travel there frequently. + +When jumping to meet another species, there is never any need to specify a +particular planet. As long as members of two species are in the same sector, +they may interact. There are no combat advantages or disadvantages to being +on or near a particular planet in an encounter. + +Finally, it is possible to NAME planets in a sector that you have not yet +visited. If you name a planet that does not exist, then the computer will +simply reject the order. Unfortunately, this allows cheaters to attempt to +name up to nine planets in a sector that they know nothing about and, thus, to +find out how many planets are in the sector. To protect against this kind of +cheating, the computer will notify the gamemaster of any such attempts. Also, +if your gamemaster is running the Far Horizons list server, then this will also +occur when using the FHTest feature of the list server. + + +10.6 SPECIFYING ZERO QUANTITY + +Whenever it makes sense, you can specify "0" quantity in an order to indicate +that ALL available quantity should be used. Here are some examples: + + Build 0 PD ; Spend all remaining funds on planetary defenses. + + CONT BAS Deep Space 9, 0 ; Increase size of starbase as much as + ; remaining funds allow, but do not + ; exceed tonnage limit. + + Cont DD Dagger, 0 ; Spend all remaining funds (up to what is + ; actually needed) on DD. + + Recy 0 RM ; Recycle all excess RMs. + + Install 0 IU, PL Mars ; Install all IUs that are on Mars. + + SEN 0 SP Klingon ; Send all economic units we have to the + ; Klingons. + + UPGRADE BAS Wobbly, 0 ; Spend all remaining production (or as much + ; as is needed) upgrading the starbase. + + +A zero argument used in a production command will NOT automatically spend +economic units owned by the species. It will only spend what is available from +production capacity and raw material units. If you wish to spend economic +units, you must provide a non-zero argument. For the DEVELOP command, a zero +argument will work as expected. Thus, if you specify "0", it will spend the +remaining balance for the planet, and it will not spend any economic units +(e.g. DEV 0 PL Mars). However, if you do NOT specify a spending limit (e.g. +DEV PL Mars), then the entire balance, if needed, including economic units, +will be used. + + +10.7 THE EFFECT OF COMBAT ON THE RELIABILITY OF STATUS REPORTS + +A status report provides information about the status of your species IF COMBAT +DOES NOT OCCUR AT THE VERY BEGINNING OF THE NEXT TURN. + +If combat DOES occur during the combat phase, then the information on the +status report may be unreliable. Here are a few examples: + + a. If combat destroys some or all of the mining and manufacturing + bases on a planet, then production for the planet will be less + than indicated on the status report, and some production orders + may be rejected by the computer. + + b. If ships are destroyed during combat, then commands that involve + these ships (e.g. JUMP, ORBIT, TRANSFER, etc.) will be rejected by + the computer. + + c. Ships that jumped into the star system in the previous turn and + LANDed or ORBITed a planet will not actually be able to LAND or ORBIT + if they are destroyed in combat. + +In other words, the information in your status report assumes that combat at +the very beginning of the next turn will not change the situation. It is +important to keep this in mind when reading and interpreting your status +reports. For example, if your status report shows that a large enemy fleet +has just entered orbit around your home planet, IT MAY NOT BE TRUE. If you +issue combat orders to fight the enemy in deep space, you may be able to +prevent them from reaching your home world. + +Thus, in effect, the status report shows you what the situation will be if +combat does not occur at the very beginning of the next turn. If combat DOES +occur, then the status report may be wrong. + + +10.8 SHIPYARD CAPACITY + +Each producing planet will have a shipyard capacity which will limit how many +ships can be built in a single turn. The shipyard capacity of the home planet +will be one when the game begins. The shipyard capacity of a normal colony +will start at zero. + +The number of production orders that you issue to BUILD, CONTINUE, IBUILD, or +ICONTINUE ships or starbases may not exceed the shipyard capacity. (The IBUILD +and ICONTINUE commands will be discussed later.) For example, if you wish +to issue three BUILD commands for new warships, a CONTINUE command for a +transport, and a CONTINUE command for a starbase, then the planet must have a +shipyard capacity of at least five. Orders that exceed the shipyard capacity +will be ignored. Orders to build other items such as colonist units, planetary +defense units, and so on, do NOT require shipyard capacity. Only construction +of warships, transports, and starbases requires shipyard capacity. + +If you wish to increase the shipyard capacity of a planet, you must issue a +SHIPYARD command during the production phase. This command will increase the +number of shipyards on the planet by one. You may only issue one SHIPYARD +order per planet per turn. The cost to build a shipyard is ten times the +current manufacturing tech level. You may not build shipyards on mining or +resort colonies. + + +10.9 LIMITATIONS ON COLONY SIZE + +In Far Horizons, colonies grow mainly by installing mining and manufacturing +units, and there is no limit to how many units may be installed. In fact, it's +even possible for a colony to eventually produce more spendable income than the +home planet. While this is not necessarily unrealistic, there must be a limit +to how large and productive a colony can become. Otherwise, runaway growth +would make the game unplayable. + +We will deal with this potential problem by defining a new concept called +"economic efficiency" which will apply to colonies, but not to the home planet. +The economic efficiency of a colony will be 100% if its economic base (i.e., +the sum of its mining and manufacturing bases) is not more than 200.0. If the +sum is greater than 200.0, then the economic efficiency will be a percentage +smaller than 100%. + +When the computer calculates the production for a colony it will multiply the +result by the economic efficiency to determine the actual amount that will be +available for spending. For example, if the original amount is 2107, and the +economic efficiency is 82%, then the actual amount available to spend will +be 82% of 2107 = 1727. (Note that fractions are dropped. This calculation +will be done after the calculation of the production penalty but before the +calculation of the fleet maintenance cost.) + +Here is how the economic efficiency (EE) will be calculated: + + 200.0 + (total economic base - 200.0) / 20 + EE = 100 x -------------------------------------------- percent + total economic base + +In effect, any installation of IUs and AUs beyond the 200.0 value will have +only 5% of its normal effect. + +[Keep in mind that the above applies only to colonies, since it is not +possible to install IUs and AUs on a home planet, and since it is not +possible to colonize the home planet of another species.] + +Note that players NEVER have to do any of the above calculations! All of the +calculations will be done by the computer and the results will be printed on +your status reports. It is very important, though, that you keep the 200.0 +limit in mind, since installation of mining and manufacturing units after the +200.0 limit has been reached will not be very effective. + +In Far Horizons, it's also possible for more than one species to colonize the +same planet. Thus, when doing the above calculation, the computer will use +the total economic base for ALL species on the planet. In other words, the +economic efficiency will apply to an entire planet, NOT just to a single colony +on the planet, and will be the same for all colonies on the planet. + +Now, even with the above rules, you will discover that many colonies generate +more income than the homeworld, even though the homeworld has a much greater +population. + +There's nothing unrealistic about this if you keep in mind that homeworld +production is the result of taxation. A colony (at least in its earlier +stages) is completely owned by the government. In other words, the government +owns all the resources, employs all of the population, keeps all the profits, +and does not pay taxes. It can even tax the colonists (what one hand gives, +the other takes away :-). Also, the total production on the home planet that +is available for the player to use is only a small fraction of the total taxes +actually collected by the government. Most taxes will be spent on other +things, such as schools, police, health care, social security, boondoggles, +and so on, and will not be available to the player. + +In time, the same thing will happen to colonies, although not to the same +extent as on the home planet, and definitely not within the course of a game. +As the colony becomes more and more self-sufficient, a smaller and smaller +fraction of its TOTAL production is owned directly by the government while a +larger and larger fraction is due to taxes on the private sector. The 200.0 +base limit is simply a game device that allows us to simulate the transition +from a government-owned corporation to a more normal economy. + +So, keep the 200.0 limit in mind. You may continue to install IUs and AUs +beyond the limit, but it will take much longer to pay off the investment, and, +in general, you will be much better off if you install the units elsewhere. + + + + + +APPENDIX A: HIGH-TECH ITEMS AND CAPABILITIES + +A high-tech item is different from other items already discussed in that it has +a "critical" technology that is needed in its construction. For example, if a +species wants to build Starbase Units, it must have a Manufacturing tech level +of at least 20. Whenever your species achieves a tech level needed to build +one of these special items, you will be notified on the status report. Unless +stated otherwise, all items can be built using the BUILD or IBUILD command +(the IBUILD command is described later). + + +******************** + + +STARBASE UNITS + +A species with a Manufacturing tech level of at least 20 may build Starbase +Units. These units are modular units that can be transported to remote +locations where there is no production capability, and used to build starbases. +For example, using starbase units, you can build a starbase at a resort or +mining colony, or even at a location where there is no star system. + +Starbase units have a cost of 110 each, and require a cargo capacity of 20 +each. Use the abbreviation "SU" for starbase units. When installed, each +unit will contribute 10,000 tons to the total mass of the starbase. + +Starbase units are installed using the BASE command, which has the same format +as the TRANSFER command. The first argument of the command is the number of +starbase units that are to be installed. The second argument is the name of +the ship or planet that will provide the starbase units. The third argument +is the name of the starbase that is to be built or increased in size. + +The first argument is optional. If it is missing or zero, then all available +starbase units will be used. The BASE command may only be used in the pre- +departure section of your orders. Here are some examples: + +1. The Human transport TR16 Barrel of Monkeys jumps to the location x = 7, +y = 12, z = 14. There is no star system at this location. The transport is +carrying 7 starbase units. The order: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Base TR16 Barrel of Monkeys, BAS Deep Space 3 + +END + +will unload all seven starbase units and construct the 70,000 ton starbase +named BAS Deep Space 3. + +In the next turn, the Human transport TR20 Tub of Lard jumps to coordinates +7 12 14 carrying 10 more starbase units. The order: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + BAS 4 TR20 Tub of Lard, BAS Deep Space 3 + +END + +will install 4 of the units, increasing the size of the starbase from 70,000 to +110,000 tons. The six unused starbase units will remain onboard the transport. + +A starbase built using the BASE command will always be built at the same +location as the ship or planet that provides the units. For example, if a +transport carrying the starbase units is in orbit or landed on a planet, then +the starbase will be built in orbit around the same planet. If the transport +is at an X Y Z location that does not contain a star system, then the starbase +will be in 'deep space' at that location. However, if an X Y Z location +contains a star system, then the starbase MUST be built in orbit around one of +the planets in the star system. It is not practical (for game purposes) to +allow a starbase to be located in the 'deep space' section of a star system. + +If an existing starbase is being increased in size, it will remain in its +original location. Obviously, the ship or planet providing the units must be +at the same X Y Z coordinates as the starbase, although they do not have to be +at the same planet, if any. + +Since starbases built using starbase units are not likely to be near a planet +where they can be upgraded, a normal upgrade is not possible. However, an +effective upgrade can be accomplished by using Damage Repair Units, which are +discussed in the next section. + + +******************** + + +DAMAGE REPAIR UNITS + +A species with a Manufacturing tech level of at least 30 may build Damage +Repair Units. These units are used to repair or upgrade ships in the field, +where it is not possible to do a normal upgrade using the UPGRADE command. + +Damage repair units are not simply spare parts that can be used to repair a +ship. Instead, they are a combination of special 'matrix' materials that +undergo mass/energy/mass conversion to produce the needed replacement parts +(similar to the 'replicator' technology of Star Trek). + +Damage repair units cost 50 each and require a cargo capacity of 1. Use the +abbreviation "DR" for damage repair units. + +Damage repair units effectively repair or upgrade a ship by reducing the age +of the ship. The age reduction is determined as follows: + + + 160,000 x N + Age reduction = ----------------- + ship tonnage + + +where N is the number of damage repair units that are used to do the repair +or upgrade. For example, if 7 damage repair units are used on a 60,000 ton +transport, then the age reduction will be (160,000 x 7)/60,000 = 18.67 = 18. +Note that fractions are dropped. + +The age reduction will never reduce the age to less than zero. The damage +repair units must be carried as cargo by the ship that is being repaired or +upgraded, and will be consumed by the operation. + +The repair/upgrade may be done in either the pre-departure or post-arrival +phase of the turn using the REPAIR command. Here are some examples: + +START PRE-DEPARTURE +; Place pre-departure orders here. + + Repair BC Big Bend, 25 ; Use 25 damage repair units to reduce + ; the age of the battlecruiser by 10. + + REP BAS Strong Arm, 17 ; Use 17 damage repair units + ; to reduce the age of the + ; 90,000 ton starbase by 30. + + repa FF Gorby Too, 0 ; Use all 5 units onboard to reduce the + ; age of the frigate by 8. + + rep DD Dagger ; Use as many units as are needed to reduce + ; the age to zero. + +END + +If N is zero, then all units that are onboard the ship will be used (but not +more than are necessary to reduce the age to zero). If N is not specified, +then as many units as are needed to reduce the age to zero will be used and +MUST be onboard. + +It is also possible to have all ships at a particular location (including +starbases and transports) pool their damage repair units, using them on the +ships that need them the most. To do this, the REPAIR command should be given +only the X Y Z coordinates of the location where the repairs are to be done, +as in the following example: + + +START POST-ARRIVAL +; Place post-arrival orders here. + + Repair 23 12 9 ; Have all ships in the sector pool their DRs + ; and do as much repair work as possible. +END + + +In the above example, all of the ships in the sector will pool their damage +repair units and repair only those ships that need repairing, starting with the +most heavily damaged, and continuing until all ships are completely repaired or +until you run out of DRs. + +You may also specify a "desired age" as in the following example: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Repair 23 12 9 7 ; Have all ships in the sector pool their DRs + ; and do as much repair work as possible down + ; to age 7 but no lower. Do not repair ships + ; if their age is already 7 or less. +END + +In the above example, all of the ships in the sector will pool their damage +repair units and repair only those ships that need repairing, starting with the +most heavily damaged, and continuing until all ships are completely repaired to +age 7 or until you run out of DRs. + +If there are still DRs left after all repairs have been made, there is no way +to predict which ships will be carrying them. + + + !!! IMPORTANT !!! + + When a ship is damaged in combat, it is possible that some or + all of its cargo will be destroyed, including damage repair + units. Since this happens quite often, it is not logged. Thus, + it's possible for REPAIR commands to fail or to not have the + desired or expected result. + + +******************** + + +INTERSPECIES CONSTRUCTION + +A species with a Manufacturing tech level of at least 25 may build items, +ships, and starbases for other species. This type of construction will be +referred to as 'interspecies construction'. + +You may construct things for another species using the IBUILD and ICONTINUE +commands. These commands are similar to the BUILD and CONTINUE commands with +the following exceptions: + + a. An additional argument indicating the name of the recipient + species must appear immediately after the IBUILD or ICONTINUE + command word. + + b. The IBUILD and ICONTINUE commands must always complete + construction of the item in the current turn. Thus, they must + NOT indicate an amount to spend unless the item is a starbase. + Obviously, they must have a final argument indicating the amount + to spend if the item IS a starbase. + +If you wish, you may use "zero" arguments if the item being built is a starbase +or anything other than a ship. + +When ships or starbases are built, they will be put in orbit around the planet +which produced them, and ownership will then be transferred to the new owner. + +Items other than ships and starbases will be added to the inventory of the +colony of the new owner that is on the same planet as the planet that built +them. Thus, the species that will receive the items must have a colony on the +same planet. If not, the computer will automatically execute a NAME command +for the recipient species using the same name as the producing planet. + +If you want to build a ship or starbase over more than one turn, use the normal +BUILD and CONTINUE commands for the initial stages of construction, and use the +ICONTINUE command for the final stage of construction. If the item is to be +built in one turn, use the IBUILD command. In other words, the IBUILD and +ICONTINUE commands always terminate construction and transfer the result to +the recipient species. + +When building something for another species, a premium of ten percent will be +added to the cost. (If the premium is not a whole number, it will be rounded +UP to the next whole number.) When the ICONTINUE command is used for the final +stage of construction, the premium will be based on the TOTAL cost of the ship +or starbase - NOT on just the remaining cost. + +You may only use the ICONTINUE command on a ship or starbase that YOU own. You +may not use the ICONTINUE command on a ship or starbase that is already owned +by another species. + +You MAY use the ICONTINUE command to increase the size of a starbase that you +received earlier from someone else and transfer it back to the original species +or even to a third species (or fourth, or fifth, etc). In each case, however, +the premium will be based on the TOTAL value of the starbase - not just on what +was added. + +Here are some examples: + + The Humans and Klingons both have colonies on the same planet. + The Human colony is called PL Big Deal and the Klingon colony is + called PL Khaarsh Dukh. The Humans give the production order: + + Ibuild SP Klingon, 21 IU + + When the order is executed, 21 colonial mining units will be added + to the inventory of PL Khaarsh Dukh. The total cost to the Humans + will be 21 + 10% (rounded up) = 21 + 3 = 24. If the Klingons did + not already have a name for the planet, then the name "PL Big Deal" + would have been created for them and would appear on the Klingon + status report. + + Later, the Klingons issue the following orders during the production + phases of turns 16, 17, and 18: + + Turn 16: Build BAS Dagger, 200 + + Turn 17: Continue BAS Dagger, 300 + Build DD Hammer, 250 + + Turn 18: Icontinue SP Human, BAS Dagger, 200 + Icontinue SP Human, DD Hammer + + At the end of turn 18, the Humans would be the new owners of a + destroyer and a 70,000 ton starbase. The Klingons would have paid + the normal costs of 200 during turn 16, and 550 during turn 17. + However, the amount paid during turn 18 would be the normal cost, + plus a premium based on the TOTAL value of the items, as follows: + + Destroyer: (1500 - 250) + (10% of 1500) = 1250 + 150 = 1400 + + Starbase: 200 + (10% of 700) = 200 + 70 = 270 + +The IBUILD command may not be used to build colonist units or planetary defense +units. + +You may not build something for a species you haven't met. + +You may not build items for a species that you have declared to be an ENEMY. +If you attempt to build something for an ENEMY species, the computer will +reject your order. If you wish to build something for an ENEMY, then issue +a temporary NEUTRAL order and cancel it immediately afterwards, as in the +following example: + + Neutral SP Klingon + Ibuild SP Klingon, 21 IU + Enemy SP Klingon + +All ships and items produced with the IBUILD and ICONTINUE commands will +operate at the tech levels of the recipient species. + +If the cost of an item is based on a tech level (such as terraforming plants), +the cost will be based on the tech level of the builder. However, the item +will always operate at the tech level of whoever is using it. + + +******************** + + +AUXILIARY GUN UNITS + +A species with a Military tech level of at least 10 may build Auxiliary Gun +Units. These units are carried as cargo and add to a warship's existing +offensive power. Basically, these units can be used to convert unused cargo +space into additional offensive capacity. + +Auxilairy gun units are designed to enhance the normal firepower of warships +only. They may not be used on transports or starbases, although they may be +carried as cargo. + +Auxiliary gun units come in the following sizes: + + Needed Minimum + Unit Equivalent Carrying Unit Military + Abbreviation Tonnage Capacity Cost Tech Level + ------------------------------------------------------------------------ + GU1 50,000 5 250 10 + GU2 100,000 10 500 20 + GU3 150,000 15 750 30 + GU4 200,000 20 1000 40 + GU5 250,000 25 1250 50 + GU6 300,000 30 1500 60 + GU7 350,000 35 1750 70 + GU8 400,000 40 2000 80 + GU9 450,000 45 2250 90 + +The 'Equivalent tonnage' indicates the amount of additional offensive capacity +that the unit provides. For example, a 300,000 ton heavy cruiser carrying two +GU3s will have the normal firepower of a heavy cruiser PLUS the firepower of +two 150,000 ton destroyers. + +[Note that the FIREPOWER is additive - NOT the tonnage. Thus, the above +heavy cruiser does NOT have the offensive power of a single 600,000 ton +ship! Keep in mind that the defensive and offensive power of a ship is NOT +proportional to the tonnage. Larger ships are more powerful than several +smaller ships of the same total tonnage. For example, the firepower of a +single 400,000 ton battlecruiser is significantly greater than the combined +firepower of four 100,000 ton frigates. Also, greater firepower does not +necessarily mean that a ship will fire more often per round, since shots are +often combined. It DOES mean, however, that the same number of shots will +do more damage.] + +Use the BUILD command to build auxiliary gun units. For example, to build +3-100,000 ton auxiliary gun units, give the production order: + + BUILD 3 GU2 + +The total cost will be 1500. + +On the status reports, auxiliary gun units will be referred to as "Mark-1 Gun +Units", "Mark-2 Gun Units", etc. corresponding respectively to GU1, GU2, etc. + + +******************** + + +FAIL-SAFE JUMP UNITS + +A species with a Gravitics tech level of at least 20 may build Fail-Safe Jump +Units. The function of these devices is to provide more accurate control of +the energies involved in an interstellar jump. They accomplish this by tuning +themselves to the ship's engines and absorbing any stray energies that would +result in a mis-jump or self-destruction. In game terms, this is what happens: + + If a ship is about to mis-jump or self-destruct, then the + Fail-safe jump unit will instead be destroyed, and another + attempt will be made automatically. If a ship carries more + than one unit, then the process may be repeated. In effect, + if a mishap occurs, a fail-safe jump unit is destroyed and + the dice are rolled again. + +Each unit costs 25 to build, and requires a carrying capacity of 1. Use the +class abbreviation "FS" for Fail-Safe Jump Units. For example, to build 3 +units, give the production order: + + BUILD 3 FS + +The total cost will be 3 x 25 = 75. + +Fail-safe jump units will be used automatically, whenever they are needed, as +long as they are carried by a ship. + + +******************** + + +JUMP PORTAL UNITS + +A species with a Gravitics tech level of at least 25 may build Jump Portal +Units. These devices are carried as cargo on a starbase, and a starbase that +carries these units is called a "jump portal". A jump portal can be used to +allow sub-light ships to cross interstellar distances as if they had a jump +drive of their own. In effect, jump portals create a private wormhole for the +sub-light ship using them. Jump portals can also be used by older FTL ships +to reduce their chances of a mishap. There is no limit on how many times jump +portals may be used in a single turn. Jump portals may NOT be used to move +starbases. + +In order for jump portal units to be effective, they must be loaded onto a +starbase. In effect, the starbase that carries them becomes the control center +for a portal. A starbase may carry as many jump portal units as needed, as +long as it has sufficient cargo capacity. + +A jump portal is characterized by an effective tonnage, which indicates the +maximum tonnage of a ship that may use it. For example, a jump portal with +an effective tonnage of 80,000 tons will allow any ship to use it that is +80,000 tons or less. The effective tonnage of a jump portal is 10,000 times +the number of jump portal units carried by the starbase. For example, if a +starbase carries 20 jump portal units, then a ship of up to 200,000 tons may +use the portal. Units carried by different starbases may NOT be combined to +increase their effective tonnage - the units affecting a single ship must be +on a single starbase. Note that the tonnage of the starbase is not important. +Only the number of jump portal units carried by the starbase is important. + +Jump portal units have the class abbreviation "JP", a cost of 100 each, and +require a carrying capacity of 10 each. You can build jump portal units +in the usual way, using the BUILD command: + + Build 3 JP ; Build 3 jump portal units, total cost = 300. + +Jump portals are used with the PJUMP command in the jump phase of the turn. +For example: + + Pjump TR4S Willow's Helm, PL Orion IV, BAS Seneca Portal + + PJU CTS Hippocrates, 12 3 22, Bas Deep space 9 + +Note that the last argument of the PJUMP command is the name of the starbase +carrying the jump portal units. Jump portals may NOT be used to move cargo or +colonists directly. These items may only be moved if they are being carried +as cargo by a ship that uses the portal. + +Note also that a jump portal can only operate in one direction. It can send +a ship TO a different location, but it cannot receive a ship FROM a different +location. Thus, in order to establish two-way travel between two different +locations, you must have a jump portal at both locations. + +It is also possible to use a jump portal owned by another species, if that +species gives you permission. You may give another species permission to +use all of your jump portals with the ALLY command: + + Ally SP Klingon + +The above order tells the computer that you consider the Klingons to be allies +and that they are allowed to use any of your jump portals. ALLY orders must +appear in the pre-departure or post-arrival section of the orders and will +remain in effect until cancelled with a NEUTRAL or ENEMY order. + +If you want to allow more than one species to use your portals, then provide +a separate ALLY order for each species: + + Ally SP Klingon + ALL Sp Vulcans + ALLY sp bajorans + +A ship using a jump portal uses the age of the starbase and the gravitics +tech level of the species that owns the starbase to determine mishap +probabilities. However, only the ship using a portal can suffer a mis-jump +or self-destruction. Fail-safe Jump Units carried by the ship will have +their usual effect. Fail-safe Jump Units on the starbase will have no +effect at all. + +The use of jump portals by a starbase will have no effect on its offensive or +defensive combat abilities. + + +******************** + + +FORCED MISJUMP UNITS + +A species with a Gravitics tech level of at least 30 may build Forced Misjump +Units. These devices are carried and used on a starbase, and are designed to +force hostile ships to leave the star system. In effect, they are used as +weapons. If their operation is successful, then any targeted ship will mis- +jump to a different location. Furthermore, the ship may self-destruct. + +Forced misjump units are characterized by an effective tonnage, which indicates +the maximum tonnage of a ship that can be affected by them. The effective +tonnage is 10,000 times the number of units carried by the starbase. Units +carried on different starbases may NOT be used in concert to increase their +effective tonnage. The units affecting a single ship must be on a single +starbase. + +The base chance of forcing a misjump is 2% times the attacker's gravitics tech +level minus the target's gravitics tech level. This value is increased by 2 +percentage points for each forced misjump unit carried in excess of what is +actually needed to affect the target. Note that the base chance can be +negative, but the effective chance can still be positive if a sufficient +number of units are used. + +If the misjump occurs, a wormhole with totally random properties will be +created and the target ship will be forced into it. The destination will be +a randomly chosen location within the galaxy. (The x, y, and z co-ordinates +will be random values between 0 and 99, inclusive.) Since this could be a +large distance from the original location, the ship may self-destruct. + +Forced misjump units are used automatically whenever a starbase which carries +them takes part in combat. However, achieving a "lock on" can be difficult +in a fast-paced battle, and an opportunity to use the devices may or may not +arrive in a particular round of combat. Sometimes, though, if conditions are +exceptionally good, more than one "lock on" may occur in a single round. + +Forced misjump units have the class abbreviation "FM", a cost of 100 each, and +require a carrying capacity of 5 each. + +Fail-safe jump units carried by a target will not prevent a forced misjump, +but they may help prevent self-destruction. + +Forced misjump units will not be used against starbases. + +If a ship is forced to jump during the strike phase, then the ship name will +contain the designation "FJ" in the status report. These ships will jump +automatically in the jump phase of the next turn, and any explicit jump orders +will be ignored. + + +******************** + + +FORCED JUMP UNITS + +A species with a Gravitics tech level of at least 40 may build Forced Jump +Units. These devices are carried and used on a starbase and are designed to +force hostile ships to leave the star system. In effect, they are used as non- +lethal weapons, and are the non-destructive counterpart of forced mis-jump +units. If their operation is successful, then any targeted ship will jump to a +different location. Furthermore, unlike forced MIS-jump units, ships affected +by forced jump units will NOT normally self-destruct, since the wormhole +created by the units is controlled and set for only a very short distance +from the original location. + +In all other respects, forced jump units are like forced misjump units. + +Forced jump units have the class abbreviation "FJ", a cost of 125 each, and +require a carrying capacity of 5 each. + + +******************** + + +GRAVITIC TELESCOPES + +A species with a gravitics tech level of at least 50 may build Gravitic +Telescopes. A gravitic telescope allows the user to detect alien ships and +inhabited planets at large distances from the X Y Z location of the telescope +itself. + +A gravitic telescope operates on the same principle as interstellar +communication devices; that is, a small wormhole is created and used as a +conduit for the transmission of information. However, unlike interstellar +communication devices (which are used in pairs), a gravitic telescope is only +needed on the receiving end. + +Gravitic telescopes are installed and used on starbases. In effect, the +starbase provides the control center for the operation of the telescope. The +range in parsecs of a gravitic telescope is simply the number of telescope +units that are carried by the starbase divided by two (fractions dropped). For +example, if a starbase is carrying seven gravitic telescope units, then it may +observe aliens up to three parsecs away. The maximum distance is also limited +by the gravitics tech level of the species, as follows: + + + Gravitics tech level + Maximum distance = -------------------------- + 10 + + +Fractions are dropped. If a starbase carries more units than are allowed by +the tech level, then the excess units will not be used. + +To operate a gravitic telescope, use the TELESCOPE command in the post-arrival +section of your orders, as follows: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Telescope BAS Peeping Tom + +END + +where the first and only argument is the name of the starbase that carries +the gravitic telescope units. The above order will provide a list of all +detectable alien ships, starbases, and populated planets within the range +of the telescope. + +The information provided by a gravitic telescope is exactly the same as the +information that appears on your status reports when one of your ships is at +the same X Y Z coordinates as an alien ship or planet; i.e., the names of +ships in orbit or in deep space, and the names and approximate economic bases +of populated planets. For planets, the approximate economic base will be +indicated by a single number in parentheses immediately following the planet +name. Ships that have landed or that are under construction are not listed. +Ships and starbases that are at coordinates that do NOT contain a star system +will be listed if they are within range of the telescope. + +In addition, if use of a gravitic telescope detects an alien starbase that +ITSELF contains one or more gravitic telescope units, then the number of units +on the alien starbase will also be listed. + +A gravitic telescope is a very delicate and difficult instrument to operate, +and it is possible that some ships/planets may not be detected. The chance of +detecting a particular ship or planet will depend on the gravitic tech level of +the species operating the telescope (the higher the better). For planets, the +probability of detection will also depend on how much industry there is on the +planet and on whether or not a colony is actively hiding. In general, home +planets and large colonies are easy to detect, while smaller colonies are +harder to detect. Large ships are easier to detect than small ships. Field- +distorted ships (discussed later) are impossible to detect. + +A gravitic telescope requires a cargo capacity of 20, and has a cost of 500. +Use the item abbreviation "GT" for Gravitic Telescopes. + +It is possible that the operation of a gravitic telescope will be detected by +orbiting ships or starbases of the observed species. The chance of detection +is: + + + Chance of Detection = 2 x (GV2 - GV1) + + +where GV2 is the gravitics tech level of the species being watched, and GV1 is +the gravitics tech level of the observer. If the chance is zero or negative, +then the observer will not be detected. For example, if SP Ferengi (GV = 32) +is spying on SP Human (GV = 39), then the Humans have a 2 x (39 - 32) = 14 +percent chance that they will know that they are being observed. + +The check for detection will be done once for each orbiting ship or starbase +that is observed by the gravitic telescope. Planets and ships landed on the +surface cannot detect the operation of a gravitic telescope because of the +interference from the planet's gravity. + +The observer will not know if he is detected. + +If the observer is detected, then the status report of the species being +watched will indicate the location of the observer's gravitic telescope. + +If operation of a gravitic telescope observes an alien starbase that ITSELF +contains a gravitic telescope, then the above chance will be increased by two +times the number of gravitic telescope units carried by the starbase: + + + Chance of Detection = 2 x NGT + (2 x (GV2 - GV1)) + + +where NGT is the number of gravitic telescopes on the starbase that is being +observed. For purposes of detection, ALL gravitic telescope units on the +starbase are counted, even if they cannot all be used to scan distant locations +because of the gravitic tech level limitation. + +A TELESCOPE order may appear only in the post-arrival phase of the turn. A +starbase may be given only one TELESCOPE order per turn. + +Colonies hidden by means of the HIDE command MAY be detected by a gravitic +telescope. The reason for this is that successful hiding requires the ability +to evade detection when aliens are present. If the hiders do not know that +they are being observed, then they may fail at hiding. And even if a colony +eventually discovers that it is being scanned by a gravitic telescope, it may +be too late for it to successfully hide. + + +******************** + + +AUXILIARY SHIELD GENERATORS + +A species with a Life Support tech level of at least 10 may build Auxiliary +Shield Generators. These units are carried as cargo and add to a warship's +existing shields. Basically, these units can be used to convert unused cargo +space into additional defensive shield capacity. + +Auxilairy shield generators are designed to enhance the normal defensive +shields of warships only. They may not be used on transports or starbases, +although they may be carried as cargo. + +Shield generators come in the following sizes: + + Needed Minimum + Unit Equivalent Carrying Unit Life Support + Abbreviation Tonnage Capacity Cost Tech Level + ------------------------------------------------------------------------ + SG1 50,000 5 250 10 + SG2 100,000 10 500 20 + SG3 150,000 15 750 30 + SG4 200,000 20 1000 40 + SG5 250,000 25 1250 50 + SG6 300,000 30 1500 60 + SG7 350,000 35 1750 70 + SG8 400,000 40 2000 80 + SG9 450,000 45 2250 90 + +The 'Equivalent tonnage' indicates the amount of additional defensive capacity +that the unit provides. For example, a 300,000 ton heavy cruiser carrying two +SG3s will have the normal shields of a heavy cruiser PLUS the shields of two +150,000 ton destroyers. + +[Note that the SHIELD POWER is additive - NOT the tonnage. Thus, the above +heavy cruiser does NOT have the defensive shields of a single 300,000 ton +ship! Keep in mind that the defensive and offensive power of a ship is NOT +proportional to the tonnage. Larger ships are more powerful than several +smaller ships of the same total tonnage. For example, the shield power of a +single 400,000 ton battlecruiser is significantly greater than the combined +shield power of four 100,000 ton frigates.] + +Use the BUILD command to build auxiliary shield units. For example, to build +3-100,000 ton auxiliary shield generators, give the production order: + + BUILD 3 SG2 + +The total cost will be 1500. + +On the status reports, auxiliary shield generators will be referred to as +"Mark-1 Shield Generators", "Mark-2 Shield Generators", etc. corresponding +respectively to SG1, SG2, etc. + + +******************** + + +FIELD DISTORTION UNITS + +A species with a Life Support tech level of at least 20 may build Field +Distortion Units. These devices are carried only on ships and starbases, and +distort sensor data and visual data obtained by others. In effect, a ship or +starbase that carries field distortion units can be seen and its size can be +determined, but the name of the ship and the species that owns it can NOT be +determined. It is also not possible to determine if the ship is sub-light or +FTL. + +In order for field distortion to take place, the ship or starbase must carry a +number of units EXACTLY equal to its tonnage divided by 10,000. For example, +since the tonnage of a battleship is 450,000, field distortion will only take +place if the ship carries EXACTLY 45 units. A TR17S must carry EXACTLY 17 +field distortion units, a 250,000 ton starbase must carry EXACTLY 25 units, +and so on. If a number of units other than the required amount is carried, +then they will simply be carried as cargo and will not be put into operation. + +Field distortion units have the class abbreviation "FD", a cost of 50 each, +and require a carrying capacity of 1 each. + +A ship using field distortion will appear to others as simply a class +abbreviation and the name "???". The species name will simply be a number. +Here is an example of three alien ships that are using field distortion units +as listed on the status reports of the owners: + + +The owner of the first ship will see this: + +Ships at x = 19, y = 2, z = 36: + Name Cap. Cargo + ---------------------------------------------------------------------------- + CT Thieve's Cant (A8,O2) 2 2 FD + + +The owner of the second and third ships will see this: + +Ships at x = 19, y = 2, z = 36: + Name Cap. Cargo + ---------------------------------------------------------------------------- + BCS Bandicoot (A3,D) 40 40 FD + BS Jabberwocky (A1,D) 45 45 FD + + +And here is what other species at the same location would see: + +Aliens at x = 19, y = 2, z = 36: + Name Species + ---------------------------------------------------------------------------- + CT ??? (O2) SP 171 + BC ??? (D) SP 92 + BS ??? (D) SP 92 + + +The battlecruiser and the battleship are both owned by the same species, +and the corvette is owned by a different species. The numbers are randomly +generated, but a particular number will always apply to the same species as +long as it stays at the same life support tech level. If the tech level +changes, then a new random number is generated. To add to the confusion, +it is possible, although highly unlikely, that two species will have the +same number at the same time. + +For example, if SP 92 corresponds to SP Klingon in the above example, then +ALL field-distorted ships owned by the Klingons, wherever they may be, will be +listed as being owned by SP 92 as long as the Klingon life support tech level +does not change. However, it is also possible, but very unlikely, that another +species will also be assigned the number 92 at the same time. + +If you wish to attack a species that is using field distortion units, but you +don't know their real name, use the name that is listed in the status report. +For example, if you want to attack just the corvette shown above, you should +issue the combat order: + + ATTACK SP 171 + +Field distortion units will be used in combat automatically, only if ALL ships +and starbases of a species at the battle location are using the units, AND if +the species has no populated planets at the battle location. Otherwise the +units will not be used but will simply be carried as cargo. This is necessary +because ships and planets of the same species must collaborate, and doing so +could easily betray the real identity and owner of the ships. + +In combat, field-distorted ships will be harder to hit. Specifically, the +chance-to-hit a field-distorted ship will be 25% less than the chance to hit +an undistorted ship. + +If one or more field distortion units are destroyed in combat by damage that +passes through the shields, then the units will stop functioning, and other +participants in the battle will learn the real name of the ship and of the +species that owns the ship. Note that this will only occur if the units were +functioning when damage passed through the shields. It will not occur if the +units were simply being carried as cargo. This also applies to ships that are +destroyed in an intercept or in an ambush. + +For the purpose of INTERCEPTs only, a field-distorted ship will be considered +an enemy ship, even if the owner is not actually a declared enemy. In other +words, a ship that is "disguised" is assumed to be inherently hostile. + +Field distortion units should never be carried by an attacker if the attacker +plans to besiege a planet. It is impossible to conduct a siege with field- +distorted ships, and any attempt to do so will reveal the true identity of the +species using the units. + +Field-distorted ships and starbases are completely invisible to operators of +gravitic telescopes. + +Field distortion units can not be used by a ship that is landed on the surface +of a planet. Thus, the true name and species of a landed ship will be known +to another species if it has population on the same planet. + +Finally, note that by combining the use of field distortion units with the +HIJACK command, a species can raid its enemies and commit other acts of piracy +without giving away the attacker's identity. + + +******************** + + +POPULATION GROWTH + +A species with a Biology tech level of at least 20 will experience enhanced +population growth on colonies. + +Advanced biological knowledge will increase the fertility and survival rate of +people on colony worlds. In Far Horizons, we will simulate this reality by +adding a bonus to population growth. Note that this bonus will apply only to +colonies - it will NOT apply to the homeworld. + +Population growth will receive a bonus of N percentage points, where N is the +Biology tech level divided by 20, fractions dropped. For example, if the +normal population growth on a colony is 9 percent, and the Biology tech level +is 59, then the actual growth rate will be 9 + 59/20 = 11 percent. + + +******************** + + +TERRAFORMING + +A species with a Biology tech level of at least 40 may terraform a planet, +making it more suitable for habitation. Terraforming has the effect of +modifying the planet's temperature class, pressure class, and gaseous +composition. + +Terraforming is accomplished by operating special atmospheric processing +plants on the surface which use biological and chemical methods to modify +the atmosphere. Terraforming can also be used to add an atmosphere to a planet +that doesn't have one. + +The number of plants needed to completely terraform a planet is exactly the +same as the life support requirement (LSN) for the planet. For example, if +your species requires a minimum Life Support tech level of 9 to establish +a normal colony on the planet, then you must use 9 terraforming plants to +completely terraform the planet. + +The cost of each processing plant is 50,000 divided by the Biology tech level +of the species. For example, if the Biology tech level is 48, then the amount +needed to build a single plant is 50,000/48 = 1041 (drop fractions). + +To build terraforming plants, use the BUILD command and the abbreviation "TP": + + Build 6 TP ; Build 6 terraforming plants. + +Terraforming plants can then be transported to the colony where they must be +installed. Each terraforming plant requires a cargo capacity of 100. + +Alternatively, if the colony has sufficient production capacity, you can build +the terraforming plants on the colony where they will be used. + +To perform terraforming on a colony, you must issue a TERRAFORM command in +the post-arrival section of your orders, after TRANSFERing the plants to the +colony: + +START POST-ARRIVAL +; Place post-arrival orders here. + + Tran 6 tp TR30 Big Boy, PL Epsilon Eridani IV + Terraform 6 PL Epsilon Eridani IV + SCAN TR30 Big Boy + +END + +The above commands will transfer six terraforming plants from the transport +to the colony and will then install and activate them. The results of the +terraforming take effect immediately. The SCAN order will show you what the +results are. + +If the number of TPs is not specified or is 0, then all available TPs will be +used, but not more than are actually needed to completely terraform the colony. + +When the TERRAFORM order is processed, the gamemaster's computer will change +the planet's temperature class, pressure class, and atmospheric composition to +bring them closer to the home planet's. If the colony does not have exactly +the number needed to completely terraform the planet, then a partial +transformation will take place, in the following order: + + 1. Eliminate poisonous gases + 2. Add required gas + 3. Modify temperature class + 4. Modify pressure class + +After installation, terraforming plants will not appear in the inventory of +the colony. In effect, they are "used up". Terraforming plants may not be +recycled after installation. + +Although terraforming takes effect immediately in game terms, you can assume +that it actually takes a few years. Consequently, if a species were to attempt +to terraform, say, the planet of an enemy, the residents would have plenty of +time to prevent the installation and operation of the plants. Because of this, +terraforming plants may NOT be operated on a planet if one or more other +species also live on the planet, unless the other species allow it. The +gamemaster's computer will not be able to check for this, but a player +that violates this rule will be evicted from the game. + +The effects of terraforming will last until the end of a game, unless +counteracted by terraforming by another species. + + +******************** + + +GERM WARFARE BOMBS + +A species with a Biology tech level of at least 50 may build Germ Warfare +Bombs. When used successfully, a bomb will wipe out an entire species on a +particular planet. + +Germ warfare is accomplished by seeding an inhabited planet with specially +designed micro-organisms which are delivered in a device called a Germ Warfare +Bomb. The effectiveness of the bomb is a function of the relative Biology tech +levels of the attacking species and target species. Specifically, the base +chance of success is 50%, and this value is modified up or down by 2% per point +of difference in Biology tech levels of the two species. + +A Germ Warfare Bomb has a cost of 1000, requires a carrying capacity of 100, +and has the class abbreviation "GW". It should be built using the BUILD +command, as in the following example: + +;Build 2 germ warfare bombs. + BUILD 2 GW + +To use germ warfare bombs in combat, issue the appropriate ENGAGE and ATTACK +order as discussed earlier in the section on combat. All bombs that are +present at the battle will be used. A separate check is made for each bomb +that the attacker takes to the battle. If at least one bomb succeeds, then the +defending species will be destroyed. Thus, the more bombs an attacker brings, +the greater will be the chance of success. + +Germ warfare bombs do their dirty work very quickly and an affected planet may +be safely colonized in the next turn. Remember, ALL mining and manufacturing +base that was originally on the planet will have been destroyed. However, you +will gain some economic units from looting. + + +******************** + + +APPENDIX B: CLASS ABBREVIATIONS + +The following class abbreviations are currently being used in FAR HORIZONS: + +AU Colonial Manufacturing Unit +BAS Starbase +BC Battlecruiser +BI Biology tech level +BM Battlemoon +BR Battlestar +BS Battleship +BW Battleworld +CA Heavy Cruiser +CC Command Cruiser +CL Light Cruiser +CS Strike Cruiser +CT Corvette +CU Colonist Unit +DD Destroyer +DN Dreadnought +DR Damage Repair Unit +ES Escort +FD Field Distortion Unit +FF Frigate +FJ Forced Jump Unit +FM Forced Mis-jump Unit +FS Fail-Safe Jump Unit +GT Gravitic Telescope Unit +GUn Auxiliary Gun Unit, Mark-n +GV Gravitics tech level +GW Germ Warfare Bomb +IU Colonial Mining Unit +JP Jump Portal Units +LS Life Support tech level +MA Manufacturing tech level +MI Mining tech level +ML Military tech level +PB Picketboat +PD Planetary Defense Unit +PL Planet +RM Raw Material Unit +SD Super Dreadnought +SGn Auxiliary Shield Generator, Mark-n +SP Species +SU Starbase Unit +TP Terraforming Plant +TRn Transport, eg. TR7 for 70,000 tons, TR14 for 140,000 tons, etc. + +Remember, all ships may be built in sub-light versions, which have an "S" +suffixed to the abbreviation. For example, a sub-light battleship has the +class abbreviation "BSS", a sub-light 150,000 ton transport has the +abbreviation "TR15S", etc. + + + +APPENDIX C: COMMAND SUMMARY + +The following commands are currently being used in FAR HORIZONS: + +ALLY sp Declare species "sp" to be an ally +AMBUSH n Spend "n" in preparation for ambush +ATTACK sp Attack opponent "sp" +ATTACK SP n Attack field-distorted species number "n" +ATTACK 0 Attack all declared enemies +AUTO Automatically generate sensible orders for + next turn +BASE [n] s,base Build or increase size of starbase "base" + using "n" starbase units from "s" +BATTLE x y z Set the location for a battle +BUILD n ab Build "n" items of class "ab" +BUILD ship Build "ship" +BUILD ship,n Start building "ship", spend only "n" +BUILD base,n Start building starbase "base", spend "n" +CONTINUE ship Finish construction of "ship" +CONTINUE ship,n Continue construction on "ship", spend only "n" +CONTINUE base,n Increase size of starbase "base", spend "n" +DESTROY ship Destroy "ship" +DESTROY base Destroy starbase "base" +DEVELOP [n] Build CUs, IUs, and AUs for producing planet + but do not spend more than "n" +DEVELOP [n] pl Build CUs, IUs, and AUs for colony planet "pl" + in same sector but do not spend more than "n" +DEVELOP [n] pl, ship Build CUs, IUs, and AUs for colony planet "pl" + and load units onto "ship" but do not spend + more than "n" +DISBAND pl Disband colony "pl" +END End current section of the order form +ENEMY sp Declare species "sp" to be an enemy +ENEMY n Declare all species to be enemies +ENGAGE n [p] Specify combat engagement option "n" and + optional planet number "p" +ESTIMATE sp Estimate tech levels of species "sp" +HAVEN x y x Set rendezvous point for ships that withdraw + from combat +HIDE Actively hide this planet from alien observation +HIDE ship Keep "ship" out of combat unless you start to + lose the battle +HIJACK sp Hijack opponent "sp" +HIJACK SP n Hijack field-distorted species number "n" +HIJACK 0 Hijack all declared enemies +IBUILD sp,n ab Build "n" items of class "ab" for species "sp" +IBUILD sp,ship Build "ship" for species "sp" +IBUILD sp,base,n Build starbase "base" for species "sp", + spend "n" +ICONTINUE sp ship Finish construction of "ship" for species "sp" +ICONTINUE sp base,n Increase size of starbase "base" for species + "sp", spend "n" +INSTALL n ab pl Install "n" IUs or AUs on planet "pl" +INSTALL pl Install all available IUs and AUs on planet "pl" +INTERCEPT n Spend "n" in preparation for interception +JUMP ship,loc Have "ship" jump to destination "loc" +LAND ship,pl Have "ship" land on planet in same star system +MESSAGE sp Send a message to species "sp" +MOVE ship, x y z Move "ship" up to one parsec +MOVE base, x y z Tow starbase "base" up to one parsec +NAME x y z p PL name Give "name" to planet "p" at location "x y z" +NEUTRAL sp Declare neutrality towards species "sp" +NEUTRAL n Declare neutrality towards all species +ORBIT ship,pl Have "ship" orbit planet in same star system +PJUMP ship,loc,bas Have "ship" jump to destination "loc" via jump + portals on starbase "bas" +PRODUCTION PL name Start production on planet "name" +RECYCLE n ab Recycle "n" items of class "ab" +RECYCLE ship Recycle "ship" +RECYCLE base Recycle starbase "base" +REPAIR ship,n Repair "ship" using "n" onboard damage repair + units +REPAIR base,n Repair "base" using "n" onboard damage repair + units +REPAIR x y z [age] Repair as many ships/starbases as possible in + sector x y z, pooling damage repair units but + do not reduce age below "age" +RESEARCH n tech Spend "n" on research in technology "tech" +SCAN ship Have "ship" do a scan of its current location +SEND n sp Send "n" economic units to species "sp" +SHIPYARD Increase shipyard capacity by one. +START section Start processing "section" of the order form +SUMMARY Provide only a brief summary of combat results, + instead of listing every single hit and miss +TARGET n Concentrate fire on target type "n" during + combat +TEACH tech [n] sp Transfer knowledge of technology "tech" to + species "sp" to maximum tech level "n" +TELESCOPE base Operate gravitic telescope on starbase "base" +TERRAFORM [n] pl Terraform planet "pl" using "n" TPs +TRANSFER n ab s,d Transfer "n" items of class "ab" from "s" to "d" +UNLOAD ship Transfer all CUs, IUs, and AUs from "ship" or +UNLOAD base starbase "base" to the planet it is at and + install as many IUs and AUs as possible +UPGRADE ship Upgrade "ship" to age zero +UPGRADE base Upgrade starbase "base" to age zero +UPGRADE ship,n Upgrade "ship", spend "n" +UPGRADE base,n Upgrade starbase "base", spend "n" +VISITED x y z Mark a star system as having been visited, + even if you have not actually been there. +WITHDRAW n1 n2 n3 Set conditions for withdrawing from combat +WORMHOLE ship [,pl] Have "ship" jump to opposite end of wormhole + and orbit planet "pl" on arrival +WORMHOLE base [,pl] Have starbase "base" jump to opposite end of + wormhole and orbit planet "pl" on arrival +ZZZ Terminate a MESSAGE + +where: + ab = class abbreviation + base = name of a starbase, including "BAS" abbreviation + d = name of a ship, starbase, or planet, including class abbreviation + loc = jump destination, either "x y z" or "PL name" + n = a whole number, 0 or more + [n] = an optional whole number, 1 or more + name = name string, including any embedded spaces. May not start + with a digit! + p = planet number + pl = planet name, including abbreviation "PL" + s = name of a ship, starbase, or planet, including class abbreviation + section = COMBAT, PRE-DEPARTURE, JUMPS, PRODUCTION or POST-ARRIVAL + ship = name of a ship, including class abbreviation + sp = species name, including "SP" abbreviation + tech = technology abbreviation: MI, MA, ML, GV, LS, or BI + x y z = galactic coordinates of a sector + + + + +APPENDIX D: SET-UP FORM FOR ENTERING A GAME + +The following form must be filled out at the start of a game and sent to the +gamemaster. Refer to Chapter 3 for detailed information on how to fill out +the form. + +Allocate points to Military, Gravitics, Life Support, and Biology tech levels. +You have a total of 15 points to allocate. + + Military: + Gravitics: + Life Support: + Biology: + +[REMINDER: If a tech level is zero, you will not be able to raise it unless +another species transfers the knowledge or technology to you.] + +Next, enter the names for your species, home planet, and government. +You may use up to 31 characters each. + + Species name (MUST contain 7 or more characters): + Home planet name: + Government name: + Government type: + + IMPORTANT! If your gamemaster is running a list server for use + by the players, then your species name may not contain any of + the special characters '$' (dollar sign), '!' (exclamation + point), or '"' (double quote). In general, it is a good idea + not to use any of these characters when naming your species. + Also, make sure that the name of your species contains at + least seven characters, including embedded spaces. + +Fill out the above items and send them to the gamemaster before the game +starts. + + + End of Rules for FAR HORIZONS + + + diff --git a/game/deadline.msg b/game/deadline.msg new file mode 100644 index 0000000..f77f58c --- /dev/null +++ b/game/deadline.msg @@ -0,0 +1,19 @@ + +Your orders for the next turn are due on Saturday at: + + 12:00 noon Universal Time (UTC) + = 9:00 AM USA EST + = 6:00 AM USA PST + +USA players: Please note that the deadline is AM, not PM! Also, please +format the subject line of your orders as in the following example: + + Subject: FHOrders, Klingon + +I generally download orders within an hour of the above deadline. If they +have not arrived by that time, or if the "Subject:" line is not correctly +formatted, then I will not be able to process them. + + + + diff --git a/game/fh_names b/game/fh_names new file mode 100644 index 0000000..adc5c39 --- /dev/null +++ b/game/fh_names @@ -0,0 +1,15 @@ +01 +Romulan +freddy@monopoly.gov +02 +Vulcan +jim@dot.lake.com +05 +Klingon +karsh@famous.person.au +29 +The Storm Birds +storm@storm.bird.edu +03 +Hound Dogs +hnd@make.my.day diff --git a/game/noorders.txt b/game/noorders.txt new file mode 100644 index 0000000..9744a8f --- /dev/null +++ b/game/noorders.txt @@ -0,0 +1,12 @@ + + +Note from the gamemaster: + + Unfortunately, I did not receive your orders for the current turn on + time. Please make an effort to be on time for the next turn. If you + DID send me orders but they arrived late, I will use them for the next + turn (but keep in mind that many of them may not work properly). You + may also change and re-submit them to me based on the information in + THIS status report. However, if you do re-submit them, please make + an effort to submit them by the deadline. Thank you. + diff --git a/src/AddSpecies.c b/src/AddSpecies.c new file mode 100644 index 0000000..9efc182 --- /dev/null +++ b/src/AddSpecies.c @@ -0,0 +1,453 @@ + +/* This program will allow the gamemaster to add a new species to the + game. */ + + +#define THIS_IS_MAIN + +#include "fh.h" + +int species_number; + +struct galaxy_data galaxy; +struct species_data *species; +struct nampla_data *nampla_base; + +extern int num_stars, num_planets, print_LSN; +extern unsigned long last_random; +extern FILE *log_file; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, x, y, z, pn, temp, found, percent, species_fd, + good_gas[14], num_neutral, req_gas, galaxy_fd, + species_array_index, species_bit_number; + + long n, species_bit_mask; + + char c, filename[16], *cp; + + struct star_data *star; + struct planet_data *home_planet; + struct species_data spec; + struct nampla_data home_nampla; + + + species = &spec; + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get all the raw data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + + /* Check for valid command line. */ + if (argc == 1) + species_number = ++galaxy.num_species; + else if (argc == 2) + species_number = atoi (argv[1]); + else + { + fprintf (stderr, "\n Usage: AddSpecies [n]\n"); + fprintf (stderr, " where 'n' is the optional species number.\n\n"); + exit (0); + } + + /* Initialize all bytes of record to zero. */ + cp = (char *) &spec; + for (i = 0; i < sizeof (struct species_data); i++) + *cp++ = 0; + + /* Get info about new species. */ +get_name_again: + printf ("\nEnter name of species #%d: ", species_number); + get_name (spec.name); + j = strlen (spec.name); + for (i = 0; i < j; i++) + { + c = spec.name[i]; + if (c == '$' || c == '!' || c == '"') + { + printf ("\n\n\tERROR! Invalid character '%c' in species name!\n", + c); + goto get_name_again; + } + } + + delete_nampla (&home_nampla); /* Set everything to zero. */ + + printf ("Enter name of home planet: "); + get_name (home_nampla.name); + + printf ("Enter name of government: "); + get_name (spec.govt_name); + + printf ("Enter type of government: "); + get_name (spec.govt_type); + +get_xyz: + printf ("\nEnter x-coordinate: "); fflush (stdout); + scanf ("%d", &x); spec.x = x; home_nampla.x = x; + + printf ("Enter y-coordinate: "); fflush (stdout); + scanf ("%d", &y); spec.y = y; home_nampla.y = y; + + printf ("Enter z-coordinate: "); fflush (stdout); + scanf ("%d", &z); spec.z = z; home_nampla.z = z; + + /* Get pointers to appropriate star and planet. */ + found = 0; + star = star_base; + for (i = 0; i < num_stars; i++) + { + if (star->x == x && star->y == y && star->z == z) + { + found = 1; + break; + } + ++star; + } + + if (found == 0) + { + printf ("\n\tThere is no star at these coordinates! Try again.\n"); + goto get_xyz; + } + + printf ("\nScan of star system:\n\n"); + print_LSN = FALSE; + log_file = stdout; + scan (x, y, z); + + printf ("\nEnter planet number: "); fflush (stdout); + scanf ("%d", &pn); spec.pn = pn; home_nampla.pn = pn; + + if (pn > star->num_planets) + { + printf ("\n\tPlanet number is too large for star! Try again!\n"); + goto get_xyz; + } + + /* Get pointer to planet. */ + home_nampla.planet_index = star->planet_index + pn - 1; + home_planet = planet_base + (long) home_nampla.planet_index; + + /* Get player-specified tech levels. */ + printf ("\n"); + for (i = ML; i <= BI; i++) + { + get_tl: + printf ("Enter %s tech level: ", tech_name[i]); fflush (stdout); + scanf ("%d", &j); if (j < 0) goto get_tl; + spec.tech_level[i] = j; + spec.tech_knowledge[i] = j; + spec.init_tech_level[i] = j; + spec.tech_eps[i] = 0; + } + + /* Check tech levels. */ + n = 0; + for (i = ML; i <= BI; i++) n += spec.tech_level[i]; + if (n > 15) printf ("\n\tWarning! ML + GV + LS + BI is greater than 15!\n\n"); + + /* Mining and manufacturing are each 10. */ + spec.tech_level[MI] = 10; + spec.tech_level[MA] = 10; + + /* Initialize other tech stuff. */ + for (i = MI; i <= BI; i++) + { + j = spec.tech_level[i]; + spec.tech_knowledge[i] = j; + spec.init_tech_level[i] = j; + spec.tech_eps[i] = 0; + } + + /* Get required gas. */ + get_gas: + printf ("\n\n"); + for (i = 1; i <= 13; i++) + { + printf (" %2d - %3s", i, gas_string[i]); + if (i == 7) printf ("\n"); + } + + printf ("\n\n The home planet has the following gases:\n\t"); + for (i = 0; i < 4; i++) + { + if (home_planet->gas[i] == 0) break; + printf (" %s(%d%%) ", gas_string[home_planet->gas[i]], + home_planet->gas_percent[i]); + } + + printf ("\n\nEnter number of gas required by species: "); fflush (stdout); + scanf ("%d", &req_gas); if (req_gas < 1 || req_gas > 13) goto get_gas; + spec.required_gas = req_gas; + + /* While checking if selection is valid, start determining neutral + gases. */ + found = 0; + num_neutral = 0; + for (i = 1; i <= 13; i++) good_gas[i] = 0; + for (i = 0; i < 4; i++) + { + if (home_planet->gas[i] == req_gas) + { + percent = home_planet->gas_percent[i]; + found = 1; + } + if (home_planet->gas[i] > 0) + { + good_gas[home_planet->gas[i]] = 1; /* All home planet gases are either + required or neutral. */ + ++num_neutral; + } + } + if (found == 0) + { + printf ("\n\tPlanet does not have %s!\n", gas_string[req_gas]); + goto get_gas; + } + + temp = percent/2; + if (temp < 1) + spec.required_gas_min = 1; + else + spec.required_gas_min = temp; + + temp = 2*percent; + if (temp < 20) temp += 20; + if (temp > 100) temp = 100; + spec.required_gas_max = temp; + + /* Do neutral gases. Start with the good_gas array and add neutral + gases until there are exactly seven of them. One of the seven + gases will be the required gas. Helium must always be neutral + since it is a noble gas. Also, this game is biased towards oxygen + breathers, so make H2O neutral also. */ + if (good_gas[HE] == 0) + { + good_gas[HE] = 1; + ++num_neutral; + } + if (good_gas[H2O] == 0) + { + good_gas[H2O] = 1; + ++num_neutral; + } + while (num_neutral < 7) + { + i = rnd(13); + if (good_gas[i] == 0) + { + good_gas[i] = 1; + ++num_neutral; + } + } + + n = 0; + for (i = 1; i <= 13; i++) + { + if (good_gas[i] > 0 && i != req_gas) + { + spec.neutral_gas[n] = i; + ++n; + } + } + + /* Do poison gases. */ + n = 0; + for (i = 1; i <= 13; i++) + { + if (good_gas[i] == 0) + { + spec.poison_gas[n] = i; + ++n; + } + } + + /* Do mining and manufacturing bases of home planet. Initial mining + and production capacity will be 25 times sum of MI and MA plus + a small random amount. Mining and manufacturing base will be + reverse-calculated from the capacity. */ + i = spec.tech_level[MI] + spec.tech_level[MA]; + n = (25 * i) + rnd(i) + rnd(i) + rnd(i); + home_nampla.mi_base = + (n * (long) home_planet->mining_difficulty) + / (10L * (long) spec.tech_level[MI]); + home_nampla.ma_base = (10L * n) / (long) spec.tech_level[MA]; + + /* Initialize contact/ally/enemy masks. */ + for (i = 0; i < NUM_CONTACT_WORDS; i++) + { + spec.contact[i] = 0; + spec.ally[i] = 0; + spec.enemy[i] = 0; + } + + /* Fill out the rest. */ + spec.num_namplas = 1; /* Just the home planet for now ("nampla" + means "named planet"). */ + spec.num_ships = 0; + + home_nampla.status = HOME_PLANET | POPULATED; + home_nampla.pop_units = HP_AVAILABLE_POP; + home_nampla.shipyards = 1; + /* Everything else was initialized to zero in the earlier call to + 'delete_nampla'. */ + + /* Print summary. */ + printf ("\n Summary for species #%d:\n", species_number); + + printf ("\tName of species: %s\n", spec.name); + printf ("\tName of home planet: %s\n", home_nampla.name); + printf ("\t\tCoordinates: %d %d %d #%d\n", spec.x, + spec.y, spec.z, spec.pn); + printf ("\tName of government: %s\n", spec.govt_name); + printf ("\tType of government: %s\n\n", spec.govt_type); + + printf ("\tTech levels: "); + for (i = 0; i < 6; i++) + { + printf ("%s = %d", tech_name[i], spec.tech_level[i]); + if (i == 2) + printf ("\n\t "); + else if (i < 5) + printf (", "); + } + + printf ("\n\n\tFor this species, the required gas is %s (%d%%-%d%%).\n", + gas_string[spec.required_gas], + spec.required_gas_min, spec.required_gas_max); + + printf ("\tGases neutral to species:"); + for (i = 0; i < 6; i++) + printf (" %s ", gas_string[spec.neutral_gas[i]]); + + printf ("\n\tGases poisonous to species:"); + for (i = 0; i < 6; i++) + printf (" %s ", gas_string[spec.poison_gas[i]]); + + printf ("\n\n\tInitial mining base = %d.%d. Initial manufacturing base = %d.%d.\n", + home_nampla.mi_base/10, home_nampla.mi_base%10, + home_nampla.ma_base/10, home_nampla.ma_base%10); + printf ("\tIn the first turn, %d raw material units will be produced,\n", + (10 * spec.tech_level[MI] * home_nampla.mi_base) + /home_planet->mining_difficulty); + printf ("\tand the total production capacity will be %d.\n\n", + (spec.tech_level[MA] * home_nampla.ma_base)/10); + + + /* Give gamemaster one last chance to change his mind. */ + gamemaster_abort_option (); + + + /* Update galaxy file. */ + galaxy_fd = creat ("galaxy.dat", 0600); + if (galaxy_fd < 0) + { + fprintf (stderr, "\n Cannot create new version of file galaxy.dat!\n"); + exit (-1); + } + + n = write (galaxy_fd, &galaxy, sizeof (struct galaxy_data)); + if (n != sizeof (struct galaxy_data)) + { + fprintf (stderr, "\n\tCannot write data to file 'galaxy.dat'!\n\n"); + exit (-1); + } + close (galaxy_fd); + + /* Set visited_by bit in star data. */ + species_array_index = (species_number - 1) / 32; + species_bit_number = (species_number - 1) % 32; + species_bit_mask = 1 << species_bit_number; + star->visited_by[species_array_index] |= species_bit_mask; + save_star_data (); + + /* Create species file. */ + sprintf (filename, "sp%02d.dat\0", species_number); + + species_fd = creat (filename, 0600); + if (species_fd < 0) + { + fprintf (stderr, "\n Cannot create file %s!\n", filename); + exit (-1); + } + + n = write (species_fd, &spec, sizeof(spec)); + if (n != sizeof(spec)) + { + fprintf (stderr, "\n Cannot write species data to file!\n"); + exit (-1); + } + + n = write (species_fd, &home_nampla, sizeof(home_nampla)); + if (n != sizeof(home_nampla)) + { + fprintf (stderr, "\n Cannot write home nampla data to file!\n"); + exit (-1); + } + close (species_fd); + + /* Create log file for first turn. Write home star system data to it. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "w"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for writing!\n\n", filename); + exit (-1); + } + + fprintf (log_file, "\nScan of home star system for SP %s:\n\n", + spec.name); + print_LSN = TRUE; + nampla_base = &home_nampla; + scan (home_nampla.x, home_nampla.y, home_nampla.z); + + fclose (log_file); + + exit (0); +} + +get_name (name) + +char name[]; + +{ + int i; + char temp[1024]; + +again: + fflush (stdout); + fgets (temp, 1024, stdin); + if (strlen(temp) > 32) + { + printf ("\n\tIt's too long! 31 characters max!\n"); + printf ("\nEnter again: "); + goto again; + } + + i = 0; + while (1) + { + if (temp[i] == '\n') break; + name[i] = temp[i]; + ++i; + } + + name[i] = '\0'; +} diff --git a/src/AsciiToBinary.c b/src/AsciiToBinary.c new file mode 100644 index 0000000..3509cd7 --- /dev/null +++ b/src/AsciiToBinary.c @@ -0,0 +1,384 @@ + +/* + This program performs the reverse operation of BinaryToAscii. +*/ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int num_species, species_index, species_number; + +struct galaxy_data galaxy; +struct species_data *species; +struct star_data *star; +struct planet_data *planet; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern int num_stars, num_planets; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, n, galaxy_fd; + + char *tp; + + FILE *ascii_file; + + + /* Open file 'ascii.dat'. */ + ascii_file = fopen ("ascii.dat", "r"); + if (ascii_file == NULL) + { + fprintf (stderr, "\n\tCannot open 'ascii.dat' for reading!\n\n"); + exit (-1); + } + + /* Do galaxy data. */ + printf ("Doing galaxy data...\n"); + fscanf (ascii_file, "%d %d %d %d\n", &galaxy.d_num_species, + &galaxy.num_species, &galaxy.radius, &galaxy.turn_number); + + galaxy_fd = creat ("galaxy.dat", 0600); + if (galaxy_fd < 0) + { + fprintf (stderr, "\n Cannot create new version of file galaxy.dat!\n"); + exit (-1); + } + + n = write (galaxy_fd, &galaxy, sizeof (struct galaxy_data)); + if (n != sizeof (struct galaxy_data)) + { + fprintf (stderr, "\n\tCannot write data to file 'galaxy.dat'!\n\n"); + exit (-1); + } + close (galaxy_fd); + + /* Do star data. */ + printf ("Doing star data...\n"); + fscanf (ascii_file, "%d\n", &num_stars); + + /* Allocate enough memory for all stars. */ + n = num_stars * sizeof(struct star_data); + star_base = (struct star_data *) malloc (n); + if (star_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for star data!\n\n"); + exit (-1); + } + + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + /* Initialize structure to all zeros. */ + tp = (char *) star; + for (j = 0; j < sizeof (struct star_data); j++) *tp++ = 0; + + fscanf (ascii_file, " %d", &n); + if (n != i+1) + { + fprintf (stderr, "\n\tStar data test failure!\n\n"); + exit (-1); + } + + fscanf (ascii_file, " %d", &n); star->x = n; + fscanf (ascii_file, " %d", &n); star->y = n; + fscanf (ascii_file, " %d", &n); star->z = n; + fscanf (ascii_file, " %d", &n); star->type = n; + fscanf (ascii_file, " %d", &n); star->color = n; + fscanf (ascii_file, " %d", &n); star->size = n; + fscanf (ascii_file, " %d", &n); star->num_planets = n; + fscanf (ascii_file, " %d", &n); star->home_system = n; + fscanf (ascii_file, " %d", &n); star->worm_here = n; + fscanf (ascii_file, " %d", &n); star->worm_x = n; + fscanf (ascii_file, " %d", &n); star->worm_y = n; + fscanf (ascii_file, " %d", &n); star->worm_z = n; + fscanf (ascii_file, " %d", &n); star->planet_index = n; + fscanf (ascii_file, " %ld", &n); star->message = n; + for (j = 0; j < NUM_CONTACT_WORDS; j++) + { + fscanf (ascii_file, " %ld", &n); + star->visited_by[j] = n; + } + fscanf (ascii_file, "\n"); + } + + /* Do planet data. */ + printf ("Doing planet data...\n"); + fscanf (ascii_file, "%d\n", &num_planets); + + /* Allocate enough memory for all planets. */ + n = num_planets * sizeof(struct planet_data); + planet_base = (struct planet_data *) malloc (n); + if (planet_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for planet data!\n\n"); + exit (-1); + } + + for (i = 0; i < num_planets; i++) + { + planet = planet_base + i; + + /* Initialize structure to all zeros. */ + tp = (char *) planet; + for (j = 0; j < sizeof (struct planet_data); j++) *tp++ = 0; + + fscanf (ascii_file, " %d", &n); + if (n != i+1) + { + fprintf (stderr, "\n\tPlanet data test failure!\n\n"); + exit (-1); + } + + fscanf (ascii_file, " %d", &n); planet->temperature_class = n; + fscanf (ascii_file, " %d", &n); planet->pressure_class = n; + for (j = 0; j < 4; j++) + { + fscanf (ascii_file, " %d", &n); + planet->gas[j] = n; + } + for (j = 0; j < 4; j++) + { + fscanf (ascii_file, " %d", &n); + planet->gas_percent[j] = n; + } + fscanf (ascii_file, " %d", &n); planet->diameter = n; + fscanf (ascii_file, " %d", &n); planet->gravity = n; + fscanf (ascii_file, " %d", &n); planet->mining_difficulty = n; + fscanf (ascii_file, " %d", &n); planet->econ_efficiency = n; + fscanf (ascii_file, " %d", &n); planet->md_increase = n; + fscanf (ascii_file, " %ld\n", &n); planet->message = n; + } + + /* Do species data. */ + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + data_modified[species_index] = FALSE; + data_in_memory[species_index] = FALSE; + } + + while (! feof (ascii_file)) + { + fscanf (ascii_file, "%d\n", &n); + + species_number = n; + species_index = n - 1; + + data_in_memory[species_index] = TRUE; + data_modified[species_index] = TRUE; + + species = &spec_data[species_index]; + + /* Initialize structure to all zeros. */ + tp = (char *) species; + for (j = 0; j < sizeof (struct species_data); j++) *tp++ = 0; + + fscanf (ascii_file, "%[^\n]", species->name); + fscanf (ascii_file, "\n"); + printf ("Doing species #%d, SP %s...\n", species_number, species->name); + + fscanf (ascii_file, "%[^\n]", species->govt_name); + fscanf (ascii_file, "\n"); + fscanf (ascii_file, "%[^\n]", species->govt_type); + fscanf (ascii_file, "\n"); + fscanf (ascii_file, " %d", &n); species->x = n; + fscanf (ascii_file, " %d", &n); species->y = n; + fscanf (ascii_file, " %d", &n); species->z = n; + fscanf (ascii_file, " %d", &n); species->pn = n; + fscanf (ascii_file, " %d", &n); species->required_gas = n; + fscanf (ascii_file, " %d", &n); species->required_gas_min = n; + fscanf (ascii_file, " %d", &n); species->required_gas_max = n; + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %d", &n); + species->neutral_gas[j] = n; + } + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %d", &n); + species->poison_gas[j] = n; + } + fscanf (ascii_file, " %d", &n); species->auto_orders = n; + fscanf (ascii_file, " %d", &n); species->num_namplas = n; + fscanf (ascii_file, " %d\n", &n); species->num_ships = n; + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %d", &n); + species->tech_level[j] = n; + } + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %d", &n); + species->init_tech_level[j] = n; + } + fscanf (ascii_file, "\n"); + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %d", &n); + species->tech_knowledge[j] = n; + } + for (j = 0; j < 6; j++) + { + fscanf (ascii_file, " %ld", &n); + species->tech_eps[j] = n; + } + fscanf (ascii_file, " %ld", &n); species->econ_units = n; + fscanf (ascii_file, " %ld", &n); species->hp_original_base = n; + fscanf (ascii_file, " %ld", &n); species->fleet_cost = n; + fscanf (ascii_file, " %ld\n", &n); species->fleet_percent_cost = n; + for (j = 0; j < NUM_CONTACT_WORDS; j++) + { + fscanf (ascii_file, " %ld", &n); + species->contact[j] = n; + } + for (j = 0; j < NUM_CONTACT_WORDS; j++) + { + fscanf (ascii_file, " %ld", &n); + species->ally[j] = n; + } + for (j = 0; j < NUM_CONTACT_WORDS; j++) + { + fscanf (ascii_file, " %ld", &n); + species->enemy[j] = n; + } + fscanf (ascii_file, "\n"); + + /* Allocate enough memory for all namplas. */ + n = species->num_namplas * sizeof (struct nampla_data); + namp_data[species_index] = (struct nampla_data *) malloc (n); + if (namp_data[species_index] == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for nampla data!\n\n"); + exit (-1); + } + + /* Do namplas for this species. */ + nampla_base = namp_data[species_index]; + for (i = 0; i < species->num_namplas; i++) + { + nampla = nampla_base + i; + + /* Initialize structure to all zeros. */ + tp = (char *) nampla; + for (j = 0; j < sizeof (struct nampla_data); j++) *tp++ = 0; + + fscanf (ascii_file, "%d\n", &n); + if (n != i+1) + { + fprintf (stderr, + "\n\tNampla data test failure, i = %d, n = %d\n\n", i, n); + exit (-1); + } + + fscanf (ascii_file, "%[^\n]", nampla->name); + fscanf (ascii_file, "\n"); + + fscanf (ascii_file, " %d", &n); nampla->x = n; + fscanf (ascii_file, " %d", &n); nampla->y = n; + fscanf (ascii_file, " %d", &n); nampla->z = n; + fscanf (ascii_file, " %d", &n); nampla->pn = n; + fscanf (ascii_file, " %d", &n); nampla->status = n; + fscanf (ascii_file, " %d", &n); nampla->hiding = n; + fscanf (ascii_file, " %d", &n); nampla->hidden = n; + fscanf (ascii_file, " %d", &n); nampla->planet_index = n; + fscanf (ascii_file, " %d", &n); nampla->siege_eff = n; + fscanf (ascii_file, " %d", &n); nampla->shipyards = n; + fscanf (ascii_file, " %d", &n); nampla->IUs_needed = n; + fscanf (ascii_file, " %d", &n); nampla->AUs_needed = n; + fscanf (ascii_file, " %d", &n); nampla->auto_IUs = n; + fscanf (ascii_file, " %d", &n); nampla->auto_AUs = n; + fscanf (ascii_file, " %d", &n); nampla->IUs_to_install = n; + fscanf (ascii_file, " %d", &n); nampla->AUs_to_install = n; + fscanf (ascii_file, " %ld", &n); nampla->mi_base = n; + fscanf (ascii_file, " %ld", &n); nampla->ma_base = n; + fscanf (ascii_file, " %ld\n", &n); nampla->pop_units = n; + for (j = 0; j < MAX_ITEMS; j++) + { + fscanf (ascii_file, " %ld", &n); + nampla->item_quantity[j] = n; + } + fscanf (ascii_file, " %ld", &n); nampla->use_on_ambush = n; + fscanf (ascii_file, " %ld\n", &n); nampla->message = n; + } + + /* Allocate enough memory for all ships. */ + n = species->num_ships * sizeof (struct ship_data); + ship_data[species_index] = (struct ship_data *) malloc (n); + if (ship_data[species_index] == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for ship data!\n\n"); + exit (-1); + } + + /* Do ships for this species. */ + ship_base = ship_data[species_index]; + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + /* Initialize structure to all zeros. */ + tp = (char *) ship; + for (j = 0; j < sizeof (struct ship_data); j++) *tp++ = 0; + + fscanf (ascii_file, "%d\n", &n); + if (n != i+1) + { + fprintf (stderr, + "\n\tShip data test failure, i = %d, n = %d\n\n", i, n); + exit (-1); + } + + fscanf (ascii_file, "%[^\n]", ship->name); + fscanf (ascii_file, "\n"); + + fscanf (ascii_file, " %d", &n); ship->x = n; + fscanf (ascii_file, " %d", &n); ship->y = n; + fscanf (ascii_file, " %d", &n); ship->z = n; + fscanf (ascii_file, " %d", &n); ship->pn = n; + fscanf (ascii_file, " %d", &n); ship->status = n; + fscanf (ascii_file, " %d", &n); ship->type = n; + fscanf (ascii_file, " %d", &n); ship->dest_x = n; + fscanf (ascii_file, " %d", &n); ship->dest_y = n; + fscanf (ascii_file, " %d", &n); ship->dest_z = n; + fscanf (ascii_file, " %d", &n); ship->just_jumped = n; + fscanf (ascii_file, " %d", &n); ship->arrived_via_wormhole = n; + fscanf (ascii_file, " %d", &n); ship->class = n; + fscanf (ascii_file, " %d\n", &n); ship->tonnage = n; + for (j = 0; j < MAX_ITEMS; j++) + { + fscanf (ascii_file, " %d", &n); + ship->item_quantity[j] = n; + } + fscanf (ascii_file, " %d", &n); ship->age = n; + fscanf (ascii_file, " %d", &n); ship->loading_point = n; + fscanf (ascii_file, " %d", &n); ship->unloading_point = n; + fscanf (ascii_file, " %d\n", &n); ship->remaining_cost = n; + } + } + + fclose (ascii_file); + + /* Save all binary data. */ + save_star_data (); + save_planet_data (); + save_species_data (); + + free_species_data (); + free (planet_base); + free (star_base); + + exit (0); +} diff --git a/src/BinaryToAscii.c b/src/BinaryToAscii.c new file mode 100644 index 0000000..ac469a7 --- /dev/null +++ b/src/BinaryToAscii.c @@ -0,0 +1,235 @@ + +/* + This program will create the single ASCII file 'ascii.dat' which + will contain an ASCII version of all '.dat' files in the game + (except 'locations.dat' which can be generated using the separate + Locations program). The companion program AsciiToBinary will + perform the reverse operation. +*/ + +#define THIS_IS_MAIN + +#include "fh.h" + + +extern int num_stars, num_planets; + +int species_index, species_number; + + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j; + + FILE *ascii_file; + + + /* Get all binary data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + get_species_data (); + + /* Create file 'ascii.dat'. */ + ascii_file = fopen ("ascii.dat", "w"); + if (ascii_file == NULL) + { + fprintf (stderr, "\n\tCannot open 'ascii.dat' for writing!\n\n"); + exit (-1); + } + + /* Do galaxy data. */ + printf ("Doing galaxy data...\n"); + fprintf (ascii_file, "%d %d %d %d\n", galaxy.d_num_species, + galaxy.num_species, galaxy.radius, galaxy.turn_number); + + /* Do star data. */ + printf ("Doing star data...\n"); + fprintf (ascii_file, "%d\n", num_stars); + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + fprintf (ascii_file, " %d", i+1); + fprintf (ascii_file, " %d", star->x); + fprintf (ascii_file, " %d", star->y); + fprintf (ascii_file, " %d", star->z); + fprintf (ascii_file, " %d", star->type); + fprintf (ascii_file, " %d", star->color); + fprintf (ascii_file, " %d", star->size); + fprintf (ascii_file, " %d", star->num_planets); + fprintf (ascii_file, " %d", star->home_system); + fprintf (ascii_file, " %d", star->worm_here); + fprintf (ascii_file, " %d", star->worm_x); + fprintf (ascii_file, " %d", star->worm_y); + fprintf (ascii_file, " %d", star->worm_z); + fprintf (ascii_file, " %d", star->planet_index); + fprintf (ascii_file, " %ld", star->message); + for (j = 0; j < NUM_CONTACT_WORDS; j++) + fprintf (ascii_file, " %ld", star->visited_by[j]); + fprintf (ascii_file, "\n"); + } + + /* Do planet data. */ + printf ("Doing planet data...\n"); + fprintf (ascii_file, "%d\n", num_planets); + for (i = 0; i < num_planets; i++) + { + planet = planet_base + i; + + fprintf (ascii_file, " %d", i+1); + fprintf (ascii_file, " %d", planet->temperature_class); + fprintf (ascii_file, " %d", planet->pressure_class); + for (j = 0; j < 4; j++) + fprintf (ascii_file, " %d", planet->gas[j]); + for (j = 0; j < 4; j++) + fprintf (ascii_file, " %d", planet->gas_percent[j]); + fprintf (ascii_file, " %d", planet->diameter); + fprintf (ascii_file, " %d", planet->gravity); + fprintf (ascii_file, " %d", planet->mining_difficulty); + fprintf (ascii_file, " %d", planet->econ_efficiency); + fprintf (ascii_file, " %d", planet->md_increase); + fprintf (ascii_file, " %ld\n", planet->message); + } + + /* Do species data. */ + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + species_number = species_index + 1; + + if (! data_in_memory[species_index]) + { + printf ("Skipping species #%d.\n", species_number); + continue; + } + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + printf ("Doing species #%d, SP %s...\n", species_number, species->name); + fprintf (ascii_file, "%d\n", species_number); + fprintf (ascii_file, "%s\n", species->name); + fprintf (ascii_file, "%s\n", species->govt_name); + fprintf (ascii_file, "%s\n", species->govt_type); + fprintf (ascii_file, " %d", species->x); + fprintf (ascii_file, " %d", species->y); + fprintf (ascii_file, " %d", species->z); + fprintf (ascii_file, " %d", species->pn); + fprintf (ascii_file, " %d", species->required_gas); + fprintf (ascii_file, " %d", species->required_gas_min); + fprintf (ascii_file, " %d", species->required_gas_max); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %d", species->neutral_gas[j]); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %d", species->poison_gas[j]); + fprintf (ascii_file, " %d", species->auto_orders); + fprintf (ascii_file, " %d", species->num_namplas); + fprintf (ascii_file, " %d\n", species->num_ships); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %d", species->tech_level[j]); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %d", species->init_tech_level[j]); + fprintf (ascii_file, "\n"); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %d", species->tech_knowledge[j]); + for (j = 0; j < 6; j++) + fprintf (ascii_file, " %ld", species->tech_eps[j]); + fprintf (ascii_file, " %ld", species->econ_units); + fprintf (ascii_file, " %ld", species->hp_original_base); + fprintf (ascii_file, " %ld", species->fleet_cost); + fprintf (ascii_file, " %ld\n", species->fleet_percent_cost); + for (j = 0; j < NUM_CONTACT_WORDS; j++) + fprintf (ascii_file, " %ld", species->contact[j]); + for (j = 0; j < NUM_CONTACT_WORDS; j++) + fprintf (ascii_file, " %ld", species->ally[j]); + for (j = 0; j < NUM_CONTACT_WORDS; j++) + fprintf (ascii_file, " %ld", species->enemy[j]); + + fprintf (ascii_file, "\n"); + + /* Do namplas for this species. */ + for (i = 0; i < species->num_namplas; i++) + { + nampla = nampla_base + i; + + fprintf (ascii_file, "%d\n", i+1); + fprintf (ascii_file, "%s\n", nampla->name); + fprintf (ascii_file, " %d", nampla->x); + fprintf (ascii_file, " %d", nampla->y); + fprintf (ascii_file, " %d", nampla->z); + fprintf (ascii_file, " %d", nampla->pn); + fprintf (ascii_file, " %d", nampla->status); + fprintf (ascii_file, " %d", nampla->hiding); + fprintf (ascii_file, " %d", nampla->hidden); + fprintf (ascii_file, " %d", nampla->planet_index); + fprintf (ascii_file, " %d", nampla->siege_eff); + fprintf (ascii_file, " %d", nampla->shipyards); + fprintf (ascii_file, " %d", nampla->IUs_needed); + fprintf (ascii_file, " %d", nampla->AUs_needed); + fprintf (ascii_file, " %d", nampla->auto_IUs); + fprintf (ascii_file, " %d", nampla->auto_AUs); + fprintf (ascii_file, " %d", nampla->IUs_to_install); + fprintf (ascii_file, " %d", nampla->AUs_to_install); + fprintf (ascii_file, " %ld", nampla->mi_base); + fprintf (ascii_file, " %ld", nampla->ma_base); + fprintf (ascii_file, " %ld\n", nampla->pop_units); + for (j = 0; j < MAX_ITEMS; j++) + fprintf (ascii_file, " %ld", nampla->item_quantity[j]); + fprintf (ascii_file, " %ld", nampla->use_on_ambush); + fprintf (ascii_file, " %ld\n", nampla->message); + } + + /* Do ships for this species. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + fprintf (ascii_file, "%d\n", i+1); + fprintf (ascii_file, "%s\n", ship->name); + fprintf (ascii_file, " %d", ship->x); + fprintf (ascii_file, " %d", ship->y); + fprintf (ascii_file, " %d", ship->z); + fprintf (ascii_file, " %d", ship->pn); + fprintf (ascii_file, " %d", ship->status); + fprintf (ascii_file, " %d", ship->type); + fprintf (ascii_file, " %d", ship->dest_x); + fprintf (ascii_file, " %d", ship->dest_y); + fprintf (ascii_file, " %d", ship->dest_z); + fprintf (ascii_file, " %d", ship->just_jumped); + fprintf (ascii_file, " %d", ship->arrived_via_wormhole); + fprintf (ascii_file, " %d", ship->class); + fprintf (ascii_file, " %d\n", ship->tonnage); + for (j = 0; j < MAX_ITEMS; j++) + fprintf (ascii_file, " %d", ship->item_quantity[j]); + fprintf (ascii_file, " %d", ship->age); + fprintf (ascii_file, " %d", ship->loading_point); + fprintf (ascii_file, " %d", ship->unloading_point); + fprintf (ascii_file, " %d\n", ship->remaining_cost); + } + } + + fclose (ascii_file); + + free_species_data (); + free (planet_base); + free (star_base); + + exit (0); +} diff --git a/src/Combat.c b/src/Combat.c new file mode 100644 index 0000000..35c370e --- /dev/null +++ b/src/Combat.c @@ -0,0 +1,1129 @@ + +/* + Terminology: A "battle" consists of one or more "actions", and each + action can take place at a different location in a star system. + In turn, each action can be broken down into one or more "rounds", + in which actual combat occurs. + + A battle is defined by a variable of type "struct battle_data", + and a pointer to a variable of this type, called "bat", is used + throughout the combat routines. + + An action is defined by a variable of type "struct action_data", + and a pointer to a variable of this type, called "act", is used + throughout the combat routines. +*/ + + +#define THIS_IS_MAIN + +#include "fh.h" +#include "combat.h" + + +int strike_phase = FALSE; +int ship_index, test_mode, verbose_mode; + +struct galaxy_data galaxy; +struct species_data *species, *c_species[MAX_SPECIES]; +struct nampla_data *nampla_base, *c_nampla[MAX_SPECIES]; +struct ship_data *ship_base, *ship, *c_ship[MAX_SPECIES]; +struct battle_data *battle_base; + + +int prompt_gm; + +extern int end_of_file, num_locs, log_stdout, + just_opened_file; +extern char input_line[], upper_name[], *input_line_pointer, + append_log[MAX_SPECIES], + original_line[256], + make_enemy[MAX_SPECIES][MAX_SPECIES]; +extern long last_random; +extern long value; +extern FILE *input_file, *log_file; +extern struct sp_loc_data loc[MAX_LOCATIONS]; + + +/* Some unused routines in utils.c need the following items. */ +int num_stars, species_number, star_data_modified; +struct star_data *star_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, k, found, command, species_number, sp_index, num_battles, + location_index, species_fd, num_enemies, battle_index, + option_index, num_species, sp_num[MAX_SPECIES], arg_index, + do_all_species, default_summary, at_number, at_index, + really_hidden, num_pls, pl_num[9], enemy_word_number, + enemy_bit_number, log_open, distorted_name, save, best_score, + next_best_score, best_species_index, betrayed_species_number, + name_length, minimum_score, first_line; + + long n, n_bytes, enemy_mask; + + char x, y, z, option, filename[32], sp_name[MAX_SPECIES][32], + keyword[4], answer[16], log_line[256], *temp_ptr; + + FILE *temp_species_log, *species_log; + + struct species_data *sp, *at_sp; + struct nampla_data *namp, *at_namp; + struct ship_data *sh, *at_sh; + struct battle_data *bat; + struct sp_loc_data *locations_base, *location; + + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get commonly used data. */ + get_galaxy_data (); + get_planet_data (); + get_transaction_data (); + get_location_data (); + locations_base = &loc[0]; + + /* Allocate memory for battle data. */ + n_bytes = MAX_BATTLES * sizeof (struct battle_data); + battle_base = (struct battle_data *) malloc (n_bytes); + if (battle_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for battle data!\n\n"); + exit (-1); + } + + /* Check arguments. If an argument is -s, then set SUMMARY mode for + everyone. The default is for players to receive a detailed report + of the battles. If an argument is -p, then prompt the GM before + saving results; otherwise, operate quietly; i.e, do not prompt GM + before saving results and do not display anything except errors. + Any additional arguments must be species numbers. If no species + numbers are specified, then do all species. */ + num_species = 0; + default_summary = FALSE; + prompt_gm = FALSE; + test_mode = FALSE; + verbose_mode = FALSE; + + if (strstr (argv[0], "Strike") != NULL) strike_phase = TRUE; + + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-s") == 0) + default_summary = TRUE; + else if (strcmp (argv[i], "-p") == 0) + prompt_gm = TRUE; + else if (strcmp (argv[i], "-t") == 0) + test_mode = TRUE; + else if (strcmp (argv[i], "-v") == 0) + verbose_mode = TRUE; + else + { + n = atoi (argv[i]); + sp_num[num_species++] = n; + } + } + + log_stdout = prompt_gm; + + if (num_species == 0) + { + num_species = galaxy.num_species; + for (i = 0; i < num_species; i++) + sp_num[i] = i+1; + do_all_species = TRUE; + } + else + do_all_species = FALSE; + + if (default_summary && prompt_gm) + printf ("\nSUMMARY mode is in effect for all species.\n\n"); + + /* Read in species data and make an uppercase copy of each name for + comparison purposes later. Also do some initializations. */ + get_species_data (); + for (sp_index = 0; sp_index < galaxy.num_species; sp_index++) + { + sp_name[sp_index][0] = '\0'; /* Initialize. */ + + if (! data_in_memory[sp_index]) continue; /* No longer in game. */ + + sp = &spec_data[sp_index]; + ship_base = ship_data[sp_index]; + + /* Convert name to upper case. */ + for (i = 0; i < 31; i++) + sp_name[sp_index][i] = toupper(sp->name[i]); + + for (i = 0; i < sp->num_ships; i++) + { + ship = ship_base + i; + ship->special = 0; + } + } + + /* Main loop. For each species, take appropriate action. */ + num_battles = 0; + for (arg_index = 0; arg_index < num_species; arg_index++) + { + species_number = sp_num[arg_index]; + if (! data_in_memory[species_number - 1]) continue; + + sp = &spec_data[species_number - 1]; + + /* The following two items are needed by get_ship(). */ + species = sp; + ship_base = ship_data[species_number - 1]; + + /* Open orders file for this species. */ + sprintf (filename, "sp%02d.ord\0", species_number); + input_file = fopen (filename, "r"); + if (input_file == NULL) + { + if (do_all_species) + { + if (prompt_gm) + printf ("\nNo orders for species #%d, SP %s.\n", + species_number, sp->name); + continue; + } + else + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + } + + end_of_file = FALSE; + + just_opened_file = TRUE; /* Tell parse.c to skip mail header, + if any. */ +find_start: + + /* Search for START COMBAT order. */ + found = FALSE; + while (! found) + { + command = get_command(); + if (command == MESSAGE) + { + /* Skip MESSAGE text. It may contain a line that starts + with "start". */ + while (TRUE) + { + command = get_command(); + if (command < 0) + { + fprintf (stderr, + "WARNING: Unterminated MESSAGE command in file %s!\n", + filename); + break; + } + + if (command == ZZZ) goto find_start; + } + } + + if (command < 0) + break; /* End of file. */ + + if (command != START) + continue; + + /* Get the first three letters of the keyword and convert to + upper case. */ + skip_whitespace(); + for (i = 0; i < 3; i++) + { + keyword[i] = toupper (*input_line_pointer); + ++input_line_pointer; + } + keyword[3] = '\0'; + + if (strike_phase) + { + if (strcmp(keyword, "STR") == 0) found = TRUE; + } + else + { + if (strcmp(keyword, "COM") == 0) found = TRUE; + } + } + + if (found) + { + if (prompt_gm) + { + if (strike_phase) + printf ("\nStrike orders for species #%d, SP %s...\n", + species_number, sp->name); + else + printf ("\nCombat orders for species #%d, SP %s...\n", + species_number, sp->name); + } + } + else + { + if (prompt_gm) + { + if (strike_phase) + printf ("\nNo strike orders for species #%d, SP %s...\n", + species_number, sp->name); + else + printf ("\nNo combat orders for species #%d, SP %s...\n", + species_number, sp->name); + } + goto done_orders; + } + + /* Open temporary log file for appending. */ + sprintf (filename, "sp%02d.temp.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + + append_log[species_number - 1] = TRUE; + + log_stdout = FALSE; + if (strike_phase) + log_string ("\nStrike orders:\n"); + else + log_string ("\nCombat orders:\n"); + log_stdout = prompt_gm; + + /* Parse all combat commands for this species and save results + for later use. */ + battle_index = -1; + while (TRUE) + { + command = get_command (); + if (end_of_file) break; + + if (command == END) break; + + if (command == BATTLE) + { + num_enemies = 0; /* No enemies specified yet. */ + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + x = value; + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + y = value; + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + z = value; + + /* Make sure that species is present at battle location. */ + found = FALSE; + location = locations_base - 1; + for (i = 0; i < num_locs; i++) + { + ++location; + if (location->s != species_number) continue; + if (location->x != x) continue; + if (location->y != y) continue; + if (location->z != z) continue; + + found = TRUE; + break; + } + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Your species is not at this location!\n"); + continue; + } + + log_string (" A battle order was issued for sector "); + log_int (x); log_char (' '); + log_int (y); log_char (' '); + log_int (z); log_string (".\n"); + + /* Add coordinates to list if not already there. */ + found = FALSE; + bat = battle_base; + for (i = 0; i < num_battles; i++) + { + if (x == bat->x && y == bat->y && z == bat->z) + { + found = TRUE; + battle_index = i; + break; + } + + ++bat; + } + + if (! found) + { + /* This is a new battle location. */ + if (num_battles == MAX_BATTLES) + { + fprintf (stderr, "\n\n\tMAX_BATTLES exceeded! Edit file 'combat.h' and re-compile!\n\n"); + exit (-1); + } + battle_index = num_battles; + sp_index = 0; + bat->x = x; + bat->y = y; + bat->z = z; + bat->spec_num[0] = species_number; + bat->special_target[0] = 0; /* Default. */ + bat->transport_withdraw_age[0] = 0; /* Default. */ + bat->warship_withdraw_age[0] = 100; /* Default. */ + bat->fleet_withdraw_percentage[0] = 100; /* Default. */ + bat->haven_x[0] = 127; + /* 127 means not yet specified. */ + bat->engage_option[sp_index][0] = DEFENSE_IN_PLACE; + bat->num_engage_options[0] = 1; + bat->can_be_surprised[0] = FALSE; + bat->hijacker[0] = FALSE; + bat->summary_only[0] = default_summary; + bat->num_species_here = 1; + for (i = 0; i < MAX_SPECIES; i++) + bat->enemy_mine[0][i] = 0; + ++num_battles; + } + else + { + /* Add another species to existing battle location. */ + sp_index = bat->num_species_here; + bat->spec_num[sp_index] = species_number; + bat->special_target[sp_index] = 0; /* Default. */ + bat->transport_withdraw_age[sp_index] = 0; /* Default. */ + bat->warship_withdraw_age[sp_index] = 100; /* Default. */ + bat->fleet_withdraw_percentage[sp_index] = 100; /* Default. */ + bat->haven_x[sp_index] = 127; + /* 127 means not yet specified. */ + bat->engage_option[sp_index][0] = DEFENSE_IN_PLACE; + bat->num_engage_options[sp_index] = 1; + bat->can_be_surprised[sp_index] = FALSE; + bat->hijacker[sp_index] = FALSE; + bat->summary_only[sp_index] = default_summary; + ++bat->num_species_here; + for (i = 0; i < MAX_SPECIES; i++) + bat->enemy_mine[sp_index][i] = 0; + } + continue; + } + + if (command == SUMMARY) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + bat->summary_only[sp_index] = TRUE; + + log_string (" Summary mode was specified.\n"); + + continue; + } + + if (command == WITHDRAW) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + if (get_value () == 0 || value < 0 || value > 100) + { + bad_argument (); + continue; + } + i = value; + bat->transport_withdraw_age[sp_index] = i; + + if (get_value () == 0 || value < 0 || value > 100) + { + bad_argument (); + continue; + } + j = value; + bat->warship_withdraw_age[sp_index] = j; + + if (get_value () == 0 || value < 0 || value > 100) + { + bad_argument (); + continue; + } + k = value; + bat->fleet_withdraw_percentage[sp_index] = k; + + log_string (" Withdrawal conditions were set to "); + log_int (i); log_char (' '); log_int (j); log_char (' '); + log_int (k); log_string (".\n"); + + continue; + } + + if (command == HAVEN) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + i = value; + bat->haven_x[sp_index] = value; + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + j = value; + bat->haven_y[sp_index] = value; + + if (get_value () == 0) + { + bad_coordinates (); + continue; + } + k = value; + bat->haven_z[sp_index] = value; + + log_string (" Haven location set to sector "); + log_int (i); log_char (' '); log_int (j); log_char (' '); + log_int (k); log_string (".\n"); + + continue; + } + + if (command == ENGAGE) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + option_index = bat->num_engage_options[sp_index]; + if (option_index >= MAX_ENGAGE_OPTIONS) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Too many ENGAGE orders!\n"); + continue; + } + + if (get_value () == 0 || value < 0 || value > 7) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid ENGAGE option!\n"); + continue; + } + option = value; + + if (strike_phase && (option > 4)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid ENGAGE option for strike phase!\n"); + continue; + } + + bat->engage_option[sp_index][option_index] = option; + + /* Get planet to attack/defend, if any. */ + if (option == PLANET_DEFENSE || (option >= PLANET_ATTACK + && option <= SIEGE)) + { + if (get_value () == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing planet argument in ENGAGE order!\n"); + continue; + } + + if (value < 1 || value > 9) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet argument in ENGAGE order!\n"); + continue; + } + + bat->engage_planet[sp_index][option_index] = value; + } + else + { + value = 0; + bat->engage_planet[sp_index][option_index] = 0; + } + + ++bat->num_engage_options[sp_index]; + + log_string (" Engagement order "); + log_int (option); + if (value != 0) + { + log_char (' '); log_long (value); + } + log_string (" was specified.\n"); + + continue; + } + + if (command == HIDE) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing ship name!\n"); + continue; + } + + if (ship->status != ON_SURFACE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship must be landed to HIDE!\n"); + continue; + } + + ship->special = NON_COMBATANT; + + log_string (" "); log_string (ship_name (ship)); + log_string (" will attempt to stay out of the battle.\n"); + + continue; + } + + if (command == TARGET) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + if (get_value () == 0 || value < 1 || value > 4) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid TARGET option!\n"); + continue; + } + bat->special_target[sp_index] = value; + + log_string (" Strategic target "); log_long (value); + log_string (" was specified.\n"); + + continue; + } + + if (command == ATTACK || command == HIJACK) + { + if (battle_index < 0) + { + battle_error (species_number); + continue; + } + + if (command == HIJACK) bat->hijacker[sp_index] = TRUE; + + /* Check if this is an order to attack all declared enemies. */ + if (get_value() && value == 0) + { + for (i = 0; i < galaxy.num_species; i++) + { + if (species_number == i+1) continue; + + if (! data_in_memory[i]) continue; + + enemy_word_number = i / 32; + enemy_bit_number = i % 32; + enemy_mask = 1 << enemy_bit_number; + + if (sp->enemy[enemy_word_number] & enemy_mask) + { + if (num_enemies == MAX_SPECIES) + { + fprintf (stderr, + "\n\n\tToo many enemies to ATTACK or HIJACK!\n\n"); + exit (-1); + } + if (command == HIJACK) + bat->enemy_mine[sp_index][num_enemies] = -(i+1); + else + bat->enemy_mine[sp_index][num_enemies] = i+1; + ++num_enemies; + } + } + + if (command == HIJACK) + log_string (" An order was given to hijack all declared enemies.\n"); + else + log_string (" An order was given to attack all declared enemies.\n"); + + continue; + } + + + if (num_enemies == MAX_SPECIES) + { + fprintf (stderr, "\n\n\tToo many enemies to ATTACK or HIJACK!\n\n"); + exit (-1); + } + + /* Set 'n' to the species number of the named enemy. */ + temp_ptr = input_line_pointer; + if (get_class_abbr() != SPECIES_ID) + { + /* Check if SP abbreviation was accidentally omitted. */ + if (isdigit (*temp_ptr)) + input_line_pointer = temp_ptr; + else if (*input_line_pointer != ' ' + && *input_line_pointer != '\t') + input_line_pointer = temp_ptr; + } + + distorted_name = FALSE; + if (get_value()) + { + n = undistorted ((int) value); + distorted_name = TRUE; + goto att1; + } + else if (get_name() < 5) + { + bad_species(); + continue; + } + + /* Check for spelling error. */ + best_score = -9999; + next_best_score = -9999; + for (i = 0; i < galaxy.num_species; i++) + { + if (*sp_name[i] == '\0') continue; + + n = agrep_score (sp_name[i], upper_name); + if (n > best_score) + { + best_score = n; + best_species_index = i; + } + else if (n > next_best_score) + next_best_score = n; + } + + name_length = strlen (sp_name[best_species_index]); + minimum_score = name_length - ((name_length / 7) + 1); + + if (best_score < minimum_score + || best_score == next_best_score) + /* Score too low or another name with equal score. */ + { + bad_species(); + continue; + } + + n = best_species_index + 1; + + att1: + + /* Make sure the named species is at the battle location. */ + found = FALSE; + location = locations_base - 1; + for (i = 0; i < num_locs; i++) + { + ++location; + if (location->s != n) continue; + if (location->x != bat->x) continue; + if (location->y != bat->y) continue; + if (location->z != bat->z) continue; + + found = TRUE; + break; + } + + /* Save species number temporarily in enemy_mine array. */ + if (found) + { + if (command == HIJACK) + bat->enemy_mine[sp_index][num_enemies] = -n; + else + bat->enemy_mine[sp_index][num_enemies] = n; + ++num_enemies; + } + + if (command == HIJACK) + log_string (" An order was given to hijack SP "); + else + log_string (" An order was given to attack SP "); + + if (distorted_name) + log_int (distorted ((int) n)); + else + log_string (spec_data[n-1].name); + log_string (".\n"); + + continue; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid combat command.\n"); + } + + fclose (log_file); + +done_orders: + + fclose (input_file); + } + + /* Check each battle. If a species specified a BATTLE command but did + not specify any engage options, then add a DEFENSE_IN_PLACE option. */ + bat = battle_base; + for (battle_index = 0; battle_index < num_battles; battle_index++) + { + for (i = 0; i < bat->num_species_here; i++) + { + if (bat->num_engage_options[i] == 0) + { + bat->num_engage_options[i] = 1; + bat->engage_option[i][0] = DEFENSE_IN_PLACE; + } + } + + ++bat; + } + + /* Initialize make_enemy array. */ + for (i = 0; i < galaxy.num_species; i++) + for (j = 0; j < galaxy.num_species; j++) + make_enemy[i][j] = 0; + + /* Check each battle location. If a species is at the location + but has no combat orders, add it to the list of species at that + battle, and apply defaults. After all species are accounted for + at the current battle location, do battle. */ + bat = battle_base - 1; + for (battle_index = 0; battle_index < num_battles; battle_index++) + { + ++bat; + + x = bat->x; + y = bat->y; + z = bat->z; + + /* Check file 'locations.dat' for other species at this location. */ + location = locations_base - 1; + for (location_index = 0; location_index < num_locs; location_index++) + { + ++location; + if (location->x != x) continue; + if (location->y != y) continue; + if (location->z != z) continue; + + /* Check if species is already accounted for. */ + found = FALSE; + species_number = location->s; + for (sp_index = 0; sp_index < bat->num_species_here; sp_index++) + { + if (bat->spec_num[sp_index] == species_number) + { + found = TRUE; + break; + } + } + + if (found) continue; + + /* Species is present but did not give any combat orders. + This species will be included in the battle ONLY if it has + ships in deep space or in orbit or if it has an unhidden, + populated planet in this sector or if it has a hidden + planet that is being explicitly attacked. */ + found = FALSE; + + sp = &spec_data[species_number - 1]; + + num_pls = 0; + + namp = namp_data[species_number - 1] - 1; + for (i = 0; i < sp->num_namplas; i++) + { + ++namp; + + if (namp->pn == 99) continue; + if (namp->x != x) continue; + if (namp->y != y) continue; + if (namp->z != z) continue; + if ((namp->status & POPULATED) == 0) continue; + + really_hidden = FALSE; + if (namp->hidden) + { + /* If this species and planet is explicitly mentioned in + ATTACK/ENGAGE orders, then the planet cannot hide + during the battle. */ + + really_hidden = TRUE; + + for (at_index = 0; at_index < bat->num_species_here; at_index++) + { + for (j = 0; j < MAX_SPECIES; j++) + { + k = bat->enemy_mine[at_index][j]; + if (k < 0) k = -k; + if (k == species_number) + { + for (k = 0; k < bat->num_engage_options[at_index]; k++) + { + if (bat->engage_option[at_index][k] >= PLANET_ATTACK + && bat->engage_option[at_index][k] <= SIEGE + && bat->engage_planet[at_index][k] == namp->pn) + { + really_hidden = FALSE; + break; + } + } + if (! really_hidden) break; + } + } + if (! really_hidden) break; + } + } + + if (really_hidden) continue; + + found = TRUE; + pl_num[num_pls++] = namp->pn; + } + + sh = ship_data[species_number - 1] - 1; + for (i = 0; i < sp->num_ships; i++) + { + ++sh; + + if (sh->pn == 99) continue; + if (sh->x != x) continue; + if (sh->y != y) continue; + if (sh->z != z) continue; + if (sh->status == UNDER_CONSTRUCTION) continue; + if (sh->status == ON_SURFACE) continue; + if (sh->status == JUMPED_IN_COMBAT) continue; + if (sh->status == FORCED_JUMP) continue; + found = TRUE; + + break; + } + + if (! found) continue; + + sp_index = bat->num_species_here; + bat->spec_num[sp_index] = location->s; + bat->special_target[sp_index] = 0; + bat->transport_withdraw_age[sp_index] = 0; + bat->warship_withdraw_age[sp_index] = 100; + bat->fleet_withdraw_percentage[sp_index] = 100; + bat->haven_x[sp_index] = 127; + bat->engage_option[sp_index][0] = DEFENSE_IN_PLACE; + bat->num_engage_options[sp_index] = 1; + if (num_pls > 0) + { + /* Provide default Engage 2 options. */ + for (i= 0; i < num_pls; i++) + { + bat->engage_option[sp_index][i+1] = PLANET_DEFENSE; + bat->engage_planet[sp_index][i+1] = pl_num[i]; + } + bat->num_engage_options[sp_index] = num_pls + 1; + } + bat->can_be_surprised[sp_index] = TRUE; + bat->hijacker[sp_index] = FALSE; + bat->summary_only[sp_index] = default_summary; + for (i = 0; i < MAX_SPECIES; i++) + bat->enemy_mine[sp_index][i] = 0; + ++bat->num_species_here; + } + + /* If haven locations have not been specified, provide random + locations nearby. */ + for (sp_index = 0; sp_index < bat->num_species_here; sp_index++) + { + if (bat->haven_x[sp_index] != 127) continue; + + while (1) + { + i = x + 2 - rnd(3); + j = y + 2 - rnd(3); + k = z + 2 - rnd(3); + + if (i != x || j != y || k != z) break; + } + + bat->haven_x[sp_index] = i; + bat->haven_y[sp_index] = j; + bat->haven_z[sp_index] = k; + } + + /* Do battle at this battle location. */ + do_battle (bat); + + if (prompt_gm) + { + printf ("Hit RETURN to continue..."); + fflush (stdout); + fgets (answer, 16, stdin); + } + } + + /* Declare new enmities. */ + for (i = 0; i < galaxy.num_species; i++) + { + log_open = FALSE; + + for (j = 0; j < galaxy.num_species; j++) + { + if (i == j) continue; + + betrayed_species_number = make_enemy[i][j]; + if (betrayed_species_number == 0) continue; + + enemy_word_number = j / 32; + enemy_bit_number = j % 32; + enemy_mask = 1 << enemy_bit_number; + + /* Clear ally bit. */ + spec_data[i].ally[enemy_word_number] &= ~enemy_mask; + + /* Set enemy and contact bits (in case this is first encounter). */ + spec_data[i].enemy[enemy_word_number] |= enemy_mask; + spec_data[i].contact[enemy_word_number] |= enemy_mask; + + data_modified[i] = TRUE; + + if (! log_open) + { + /* Open temporary species log file for appending. */ + sprintf (filename, "sp%02d.temp.log\0", i+1); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + + append_log[i] = TRUE; + log_open = TRUE; + } + + log_string ("\n!!! WARNING: Enmity has been automatically declared towards SP "); + log_string (spec_data[j].name); + log_string (" because they surprise-attacked SP "); + log_string (spec_data[betrayed_species_number-1].name); + log_string ("!\n"); + } + + if (log_open) fclose (log_file); + } + + save = TRUE; + if (prompt_gm) + { + printf ("\n*** Gamemaster safe-abort option ... type q or Q to quit: "); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] == 'q' || answer[0] == 'Q') save = FALSE; + } + + /* If results are to be saved, append temporary logs to actual species + logs. In either case, delete temporary logs. */ + for (i = 0; i < galaxy.num_species; i++) + { + if (! append_log[i]) continue; + + if (save) + { + sprintf (filename, "sp%02d.log", i+1); + species_log = fopen (filename, "a"); + if (species_log == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + } + + sprintf (filename, "sp%02d.temp.log\0", i+1); + + if (save) + { + temp_species_log = fopen (filename, "r"); + if (temp_species_log == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + + /* Copy temporary log to permanent species log. */ + while (fgets(log_line, 256, temp_species_log) != NULL) + fputs (log_line, species_log); + + fclose (temp_species_log); + fclose (species_log); + } + + /* Delete temporary log file. */ + unlink (filename); + } + + if (save) + { + save_planet_data (); + save_species_data (); + save_transaction_data (); + } + + free_species_data (); + + exit (0); +} diff --git a/src/Edit.c b/src/Edit.c new file mode 100644 index 0000000..3e8c256 --- /dev/null +++ b/src/Edit.c @@ -0,0 +1,1257 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int x, y, z, pn, species_number, species_index; + +long value; + + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + + +extern int num_stars, num_planets, truncate_name, ignore_field_distorters; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, option, stars_modified, planets_modified, species_modified; + + char answer[16]; + + + /* Get data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + get_species_data (); + + ignore_field_distorters = TRUE; + truncate_name = TRUE; + stars_modified = FALSE; + planets_modified = FALSE; + species_modified = FALSE; + +again: + /* Get what to edit. */ + printf ("\n\nEdit what (1=star, 2=planet, 3=species, 4=create star, 8=save, 9=quit)? "); + if (get_value() != 1) goto again; + option = value; + + if (option == 1) + { + edit_star (); + stars_modified = TRUE; + goto again; + } + else if (option == 2) + { + edit_planet (); + planets_modified = TRUE; + goto again; + } + else if (option == 3) + { + edit_species (); + species_modified = TRUE; + goto again; + } + else if (option == 4) + { + create_star (); + stars_modified = TRUE; + planets_modified = TRUE; + goto again; + } + else if (option == 8) + { + /* Save data. */ + if (stars_modified) save_star_data (); + if (planets_modified) save_planet_data (); + if (species_modified) + { + save_species_data (); + do_locations (); /* Create new locations array. */ + save_location_data (); + } + + stars_modified = FALSE; + planets_modified = FALSE; + species_modified = FALSE; + } + else if (option == 9) + { + if (stars_modified || planets_modified || species_modified) + { + printf ("\007\n\n\tWARNING! Data may have been modified!\n"); + printf ("\n\tDo you really want to exit (y or Y = yes): "); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] != 'y' && answer[0] != 'Y') goto again; + printf ("\n"); + } + + free_species_data (); + free (star_base); + free (planet_base); + exit (0); + } + + goto again; +} + + + +create_star () +{ + int i; + + char *cp; + + + if (get_location (FALSE)) goto no_change; + + star = star_base + num_stars; + + cp = (char *) star; + for (i = 0; i < sizeof (struct star_data); i++) + *cp++ = 0; + + star->x = x; + star->y = y; + star->z = z; + star->planet_index = num_planets; + + printf ("Enter star type (1=dwarf, 2=degen, 3=main, 4=giant): "); + if (get_value () < 1) goto no_change; + star->type = value; + + printf ("Enter star color (1=O, 2=B, 3=A, 4=F, 5=G, 6=K, 7=M): "); + if (get_value () < 1) goto no_change; + star->color = value; + + printf ("Enter star size (0-9): "); + if (get_value () < 1) goto no_change; + star->size = value; + + printf ("Enter number of planets (1-9) to generate: "); + if (get_value () < 1) goto no_change; + i = value; + star->num_planets = i; + + ++num_stars; + + planet = planet_base + num_planets; + + generate_planets (planet, i); + + num_planets += star->num_planets; + + return; + +no_change: + + printf ("\n\tAbort. No changes were made.\n\n"); + +} + + + +edit_star () + +{ + int i; + + + if (! get_location (FALSE)) return; + + printf ("Current message = %ld: ", star->message); + i = get_value (); + if (i == 1) star->message = value; + else if (i == -1) return; + + printf ("Current worm_here = %d: ", star->worm_here); + i = get_value (); + if (i == 1) star->worm_here = value; + else if (i == -1) return; + + printf ("Current worm_x = %d: ", star->worm_x); + i = get_value (); + if (i == 1) star->worm_x = value; + else if (i == -1) return; + + printf ("Current worm_y = %d: ", star->worm_y); + i = get_value (); + if (i == 1) star->worm_y = value; + else if (i == -1) return; + + printf ("Current worm_z = %d: ", star->worm_z); + i = get_value (); + if (i == 1) star->worm_z = value; + else if (i == -1) return; +} + + + + +edit_planet () + +{ + int i, n, p, num_gases; + + char answer[64]; + + + if (! get_location (TRUE)) return; + + printf ("\n Temp Press Mining\n"); + printf (" # Dia Grav Class Class Diff Atmosphere\n"); + printf (" ------------------------------------------------------------------\n"); + + printf (" %d %3d %d.%02d %2d %2d %d.%02d ", + pn, + planet->diameter, + planet->gravity/100, + planet->gravity%100, + planet->temperature_class, + planet->pressure_class, + planet->mining_difficulty/100, + planet->mining_difficulty%100); + + num_gases = 0; + for (n = 0; n < 4; n++) + { + if (planet->gas_percent[n] > 0) + { + if (num_gases > 0) printf (","); + printf ("%s(%d%%)", gas_string[planet->gas[n]], + planet->gas_percent[n]); + ++num_gases; + } + } + + if (num_gases == 0) printf ("No atmosphere"); + + printf ("\n"); + + /* List each planet attribute and let user change it. */ + printf ("\nEnter new value for planet or hit RETURN key to leave as is...\n\n"); + + printf ("Current diameter = %d: ", planet->diameter); + i = get_value (); + if (i == 1) planet->diameter = value; + else if (i == -1) return; + + printf ("Current gravity times 100 = %d: ", planet->gravity); + i = get_value (); + if (i == 1) planet->gravity = value; + else if (i == -1) return; + + printf ("Current temperature class = %d: ", planet->temperature_class); + i = get_value (); + if (i == 1) planet->temperature_class = value; + else if (i == -1) return; + + printf ("Current pressure class = %d: ", planet->pressure_class); + i = get_value (); + if (i == 1) planet->pressure_class = value; + else if (i == -1) return; + + printf ("Current mining difficulty times 100 = %d: ", planet->mining_difficulty); + i = get_value (); + if (i == 1) planet->mining_difficulty = value; + else if (i == -1) return; + + printf ("Current md_increase times 100 = %d: ", planet->md_increase); + i = get_value (); + if (i == 1) planet->md_increase = value; + else if (i == -1) return; + + printf ("Current econ_efficiency = %d: ", planet->econ_efficiency); + i = get_value (); + if (i == 1) planet->econ_efficiency = value; + else if (i == -1) return; + + printf ("Current message = %ld: ", planet->message); + i = get_value (); + if (i == 1) planet->message = value; + else if (i == -1) return; + +next_gas: + printf ("\nGases:\n"); + for (i = 1; i <= 13; i++) + printf (" %d-%s", i, gas_string[i]); + printf ("\n\n"); + + n = 0; + for (i = 0; i < 4; i++) + { + printf ("\t%d - %s = %d\%", i, gas_string[planet->gas[i]], + planet->gas_percent[i]); + n += planet->gas_percent[i]; + } + + printf ("\n\nTotal percentage = %d\%.\n", n); + + printf ("\nEnter 'index, new gas number, new percent' or RETURN for as is: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = -1; n = 0; + sscanf (answer, "%d,%d,%d", &i, &n, &p); + if (i >= 0) + { + planet->gas[i] = n; + planet->gas_percent[i] = p; + goto next_gas; + } + } +} + + + +edit_species () + +{ + int n, found, sp_index, species_number, option; + + + n = 0; + printf ("\n"); + for (sp_index = 0; sp_index < galaxy.num_species; sp_index++) + { + species_number = sp_index + 1; + + found = data_in_memory[sp_index]; + if (! found) continue; + + printf ("%4d - %-18.18s", species_number, spec_data[sp_index].name); + + if (n++ % 3 == 2) printf ("\n"); + } + if (n % 3) printf ("\n"); + + printf ("\nEnter species number: "); + if (get_value() != 1) return; + species_number = value; + + sp_index = species_number - 1; + + if (! data_in_memory[sp_index]) + { + printf ("\n\n\tNo such species!\n"); + return; + } + + data_modified[sp_index] = TRUE; + + species = &spec_data[sp_index]; + nampla_base = namp_data[sp_index]; + ship_base = ship_data[sp_index]; + +again: + printf ("\nEdit what (1 = species stats, 2 = nampla, 3 = ship, 9 = return): "); + if (get_value() != 1) return; + option = value; + + if (option == 1) + { + edit_species_stats (); + goto again; + } + else if (option == 2) + { + edit_nampla (); + goto again; + } + else if (option == 3) + { + edit_ship (); + goto again; + } + else if (option != 9) + goto again; + else + return; +} + + +edit_species_stats () + +{ + int i, n, delete, array_index, bit_number; + + long bit_mask; + + char name[32], answer[32]; + + + /* List each nampla attribute and let user change it. */ + printf ("\nEnter new value for SP %s or hit RETURN key to leave as is...\n\n", + species->name); + + printf ("Species name is %s: ", species->name); + get_name (name); + if (answer[0] == 27) return; + else if (name[0] != '\0') strcpy (species->name, name); + + printf ("Species government name is %s: ", species->govt_name); + get_name (name); + if (answer[0] == 27) return; + else if (name[0] != '\0') strcpy (species->govt_name, name); + + printf ("Species government type is %s: ", species->govt_type); + get_name (name); + if (answer[0] == 27) return; + else if (name[0] != '\0') strcpy (species->govt_type, name); + + printf ("\nCurrent economic units = %ld: ", species->econ_units); + i = get_value (); + if (i == 1) species->econ_units = value; + else if (i == -1) return; + +next_tech_level: + printf ("\nTech levels:\n\n"); + for (i = 0; i < 6; i++) printf ("\t%d - %s = %d\n", i+1, tech_name[i], + species->tech_level[i]); + + printf ("\nEnter 'tech number-space-new level' or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = 0; n = 0; + sscanf (answer, "%d%d", &i, &n); + if (i != 0) + { + species->tech_level[i-1] = n; + goto next_tech_level; + } + } + + +next_tech_knowledge: + printf ("\nTech knowledges:\n\n"); + for (i = 0; i < 6; i++) printf ("\t%d - %s = %d\n", i+1, tech_name[i], + species->tech_knowledge[i]); + + printf ("\nEnter 'tech number-space-new knowledge' or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = 0; n = 0; + sscanf (answer, "%d%d", &i, &n); + if (i != 0) + { + species->tech_knowledge[i-1] = n; + goto next_tech_knowledge; + } + } + +next_tech_eps: + printf ("\nTech experience points:\n\n"); + for (i = 0; i < 6; i++) printf ("\t%d - %s = %d\n", i+1, tech_name[i], + species->tech_eps[i]); + + printf ("\nEnter 'tech number-space-new eps' or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = 0; n = 0; + sscanf (answer, "%d%d", &i, &n); + if (i != 0) + { + species->tech_eps[i-1] = n; + goto next_tech_eps; + } + } + +next_contact_mask: + printf ("\nSpecies contacted:\n\n"); + n = 0; + for (i = 1; i <= galaxy.num_species; i++) + { + if (! data_in_memory[i-1]) continue; + + array_index = (i - 1) / 32; + bit_number = (i - 1) % 32; + bit_mask = 1 << bit_number; + if ((species->contact[array_index] & bit_mask) == 0) continue; + + printf ("%4d - %-18.18s", i, spec_data[i-1].name); + + if (n++ % 3 == 2) printf ("\n"); + } + if (n % 3) printf ("\n"); + + printf ("\n Enter negative species number to delete bit, positive number to add bit,\n"); + printf (" or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + n = 0; + sscanf (answer, "%d", &n); + if (n != 0) + { + if (n < 0) + { + delete = TRUE; + n = -n; + } + else + delete = FALSE; + + array_index = (n - 1) / 32; + bit_number = (n - 1) % 32; + bit_mask = 1 << bit_number; + + if (delete) + species->contact[array_index] &= ~bit_mask; + else + species->contact[array_index] |= bit_mask; + + goto next_contact_mask; + } + } + +next_ally_mask: + printf ("\nSpecies declared ALLY:\n\n"); + n = 0; + for (i = 1; i <= galaxy.num_species; i++) + { + if (! data_in_memory[i-1]) continue; + + array_index = (i - 1) / 32; + bit_number = (i - 1) % 32; + bit_mask = 1 << bit_number; + if ((species->ally[array_index] & bit_mask) == 0) continue; + + printf ("%4d - %-18.18s", i, spec_data[i-1].name); + + if (n++ % 3 == 2) printf ("\n"); + } + if (n % 3) printf ("\n"); + + printf ("\n Enter negative species number to delete bit, positive number to add bit,\n"); + printf (" or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + n = 0; + sscanf (answer, "%d", &n); + if (n != 0) + { + if (n < 0) + { + delete = TRUE; + n = -n; + } + else + delete = FALSE; + + array_index = (n - 1) / 32; + bit_number = (n - 1) % 32; + bit_mask = 1 << bit_number; + + if (delete) + species->ally[array_index] &= ~bit_mask; + else + species->ally[array_index] |= bit_mask; + + goto next_ally_mask; + } + } + +next_enemy_mask: + printf ("\nSpecies declared ENEMY:\n\n"); + n = 0; + for (i = 1; i <= galaxy.num_species; i++) + { + if (! data_in_memory[i-1]) continue; + + array_index = (i - 1) / 32; + bit_number = (i - 1) % 32; + bit_mask = 1 << bit_number; + if ((species->enemy[array_index] & bit_mask) == 0) continue; + + printf ("%4d - %-18.18s", i, spec_data[i-1].name); + + if (n++ % 3 == 2) printf ("\n"); + } + if (n % 3) printf ("\n"); + + printf ("\n Enter negative species number to delete bit, positive number to add bit,\n"); + printf (" or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + n = 0; + sscanf (answer, "%d", &n); + if (n != 0) + { + if (n < 0) + { + delete = TRUE; + n = -n; + } + else + delete = FALSE; + + array_index = (n - 1) / 32; + bit_number = (n - 1) % 32; + bit_mask = 1 << bit_number; + + if (delete) + species->enemy[array_index] &= ~bit_mask; + else + species->enemy[array_index] |= bit_mask; + + goto next_enemy_mask; + } + } +} + + + +edit_nampla () + +{ + int i, n, nampla_number, index_changed, found; + + char answer[32]; + +again: + printf ("\n"); + n = 0; + nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->pn == 99) continue; + + printf ("%3d - %-32s", i+1, nampla->name); + + if (n++ % 2 == 1) printf ("\n"); + } + if (n % 2 == 1) printf ("\n"); + + printf ("\nWhich nampla (0 to create a new one, negative to delete)? "); + if (get_value() != 1) return; + nampla_number = value; + + if (nampla_number < 0) + { + nampla_number = -nampla_number; + nampla = nampla_base + nampla_number - 1; + + printf ("\nDo you really want to delete PL %s (y or Y = yes)? ", + nampla->name); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] == 'y' || answer[0] == 'Y') delete_nampla (nampla); + return; + } + + if (nampla_number == 0) + create_nampla (); + else + nampla = nampla_base + nampla_number - 1; + + /* List each nampla attribute and let user change it. */ + printf ("\nEnter new value for PL %s or hit RETURN key to leave as is...\n\n", + nampla->name); + + index_changed = FALSE; + + x = nampla->x; + printf ("Current x = %d: ", x); + i = get_value (); + if (i == 1) { x = value; index_changed = TRUE; } + else if (i == -1) return; + + y = nampla->y; + printf ("Current y = %d: ", y); + i = get_value (); + if (i == 1) { y = value; index_changed = TRUE; } + else if (i == -1) return; + + z = nampla->z; + printf ("Current z = %d: ", z); + i = get_value (); + if (i == 1) { z = value; index_changed = TRUE; } + else if (i == -1) return; + + pn = nampla->pn; + printf ("Current pn = %d: ", pn); + i = get_value (); + if (i == 1) { pn = value; index_changed = TRUE; } + else if (i == -1) return; + + if (index_changed) + { + found = FALSE; + star = star_base - 1; + for (i = 0; i < num_stars; i++) + { + ++star; + + if (star->x != x) continue; + if (star->y != y) continue; + if (star->z != z) continue; + + if (pn > star->num_planets) break; + + found = TRUE; + + break; + } + + if (! found) + { + printf ("\n\tPlanet does not exist!\n\n"); + return; + } + nampla->x = x; + nampla->y = y; + nampla->z = z; + nampla->pn = pn; + nampla->planet_index = star->planet_index + pn - 1; + } + + printf ("\nStatus bits:\n\n\tHome planet = 1\t\tColony = 2\n"); + printf ("\tSelf-sufficient = 4\tPopulated = 8\n"); + printf ("\tMining colony = 16\tResort colony = 32\n"); + printf ("\tDisbanded colony = 64\n\n"); + + printf ("Current status = %d: ", nampla->status); + i = get_value (); + if (i == 1) nampla->status = value; + else if (i == -1) return; + + printf ("\nCurrent mining base times 10 = %ld: ", nampla->mi_base); + i = get_value (); + if (i == 1) nampla->mi_base = value; + else if (i == -1) return; + + printf ("\nCurrent manufacturing base times 10 = %ld: ", nampla->ma_base); + i = get_value (); + if (i == 1) nampla->ma_base = value; + else if (i == -1) return; + + printf ("\nCurrent IUs to install = %d: ", nampla->IUs_to_install); + i = get_value (); + if (i == 1) nampla->IUs_to_install = value; + else if (i == -1) return; + + printf ("\nCurrent AUs to install = %d: ", nampla->AUs_to_install); + i = get_value (); + if (i == 1) nampla->AUs_to_install = value; + else if (i == -1) return; + + printf ("\nCurrent population units = %ld: ", nampla->pop_units); + i = get_value (); + if (i == 1) nampla->pop_units = value; + else if (i == -1) return; + + printf ("Current message = %ld: ", nampla->message); + i = get_value (); + if (i == 1) nampla->message = value; + else if (i == -1) return; + + printf ("Current shipyards = %d: ", nampla->shipyards); + i = get_value (); + if (i == 1) nampla->shipyards = value; + else if (i == -1) return; + +next_item: + printf ("\n"); + n = 0; + for (i = 0; i < MAX_ITEMS; i++) + { + printf ("\t%d: %d %ss", i+1, nampla->item_quantity[i], item_abbr[i]); + if (++n % 4 == 0) printf ("\n"); + } + if (n % 4) printf ("\n"); + printf ("\nEnter 'item number-space-new quantity' or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = 0; n = 0; + sscanf (answer, "%d%d", &i, &n); + if (i != 0) + { + nampla->item_quantity[i-1] = n; + goto next_item; + } + } + + printf ("\nCurrent hiding value = %d: ", nampla->hiding); + i = get_value (); + if (i == 1) nampla->hiding = value; + else if (i == -1) return; + + printf ("\nCurrent hidden value = %d: ", nampla->hidden); + i = get_value (); + if (i == 1) nampla->hidden = value; + else if (i == -1) return; + + printf ("\nCurrent siege_eff value = %d: ", nampla->siege_eff); + i = get_value (); + if (i == 1) nampla->siege_eff = value; + else if (i == -1) return; + + printf ("\nCurrent use_on_ambush value = %ld: ", nampla->use_on_ambush); + i = get_value (); + if (i == 1) nampla->use_on_ambush = value; + else if (i == -1) return; +} + + + +create_nampla () + +{ + int i, found, unused_nampla_available, nampla_index; + + char name[32], upper_nampla_name[32], upper_name[32]; + + struct nampla_data *unused_nampla; + + + /* Get planet cordinates. */ + if (! get_location (TRUE)) return; + + /* Get planet name and make an upper case copy. */ + printf ("\nEnter name: "); + get_name (name); + if (name[0] == 27 || name[0] == '\0') return; + for (i = 0; i < 32; i++) upper_name[i] = toupper(name[i]); + + /* Search existing namplas for name and location. */ + found = FALSE; + unused_nampla_available = FALSE; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->pn == 99) + { + /* We can re-use this nampla rather than append a new one. */ + unused_nampla = nampla; + unused_nampla_available = TRUE; + continue; + } + + /* Check if a named planet already exists at this location. */ + if (nampla->x == x && nampla->y == y && nampla->z == z + && nampla->pn == pn) + { + printf ("\nThe planet at these coordinates already has a name.\n\n"); + return; + } + + /* Make upper case copy of nampla name. */ + for (i = 0; i < 32; i++) + upper_nampla_name[i] = toupper(nampla->name[i]); + + /* Compare names. */ + if (strcmp (upper_nampla_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (found) + { + printf ("\nPlanet name is already in use.\n\n"); + return; + } + + /* Add new nampla to database for this species. */ + if (unused_nampla_available) + nampla = unused_nampla; + else + { + nampla = nampla_base + species->num_namplas; + species->num_namplas += 1; + delete_nampla (nampla); /* Set everything to zero. */ + } + + /* Initialize new nampla. */ + strcpy (nampla->name, name); + nampla->x = x; + nampla->y = y; + nampla->z = z; + nampla->pn = pn; + nampla->planet_index = star->planet_index + pn - 1; + nampla->status = COLONY; + /* Everything else was set to zero in above call to 'delete_nampla'. */ +} + + + +edit_ship () + +{ + int i, n, ship_number; + + char answer[32]; + + +again: + n = 0; + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + + printf ("%3d - %-32s", i+1, ship_name(ship)); + + if (n++ % 2 == 1) printf ("\n"); + } + if (n % 2 == 1) printf ("\n"); + + printf ("\nWhich ship (0 to create a new one, negative to delete)? "); + if (get_value() != 1) return; + ship_number = value; + + if (ship_number < 0) + { + ship_number = -ship_number; + ship = ship_base + ship_number - 1; + + printf ("\nDo you really want to delete %s (y or Y = yes)? ", + ship_name (ship)); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] == 'y' || answer[0] == 'Y') delete_ship (ship); + return; + } + + if (ship_number == 0) + create_ship (); + else + ship = ship_base + ship_number - 1; + + /* List each ship attribute and let user change it. */ + printf ("\nEnter new value for %s or hit RETURN key to leave as is...\n\n", + ship_name(ship)); + + printf ("Current x = %d: ", ship->x); + i = get_value (); + if (i == 1) ship->x = value; + else if (i == -1) return; + + printf ("Current y = %d: ", ship->y); + i = get_value (); + if (i == 1) ship->y = value; + else if (i == -1) return; + + printf ("Current z = %d: ", ship->z); + i = get_value (); + if (i == 1) ship->z = value; + else if (i == -1) return; + + printf ("Current pn = %d: ", ship->pn); + i = get_value (); + if (i == 1) ship->pn = value; + else if (i == -1) return; + + printf ("\nStatus values:\n\n\tUnder Construction = 0\tOn Surface = 1\n"); + printf ("\tIn Orbit = 2\t\tIn Deep Space = 3\n"); + printf ("\tJumped in Combat = 4\tForced Jump = 5\n\n"); + + printf ("Current status = %d: ", ship->status); + i = get_value (); + if (i == 1) ship->status = value; + else if (i == -1) return; + + printf ("\n\nShip types: FTL = 0, Sub-light = 1, Starbase = 2\n"); + + printf ("\nCurrent ship type = %d: ", ship->type); + i = get_value (); + if (i == 1) ship->type = value; + else if (i == -1) return; + + printf ("\n\nShip classes:\n\n"); + for (i = 0; i < NUM_SHIP_CLASSES; i++) + { + printf ("\t%d - %s", i, ship_abbr[i]); + if (i % 5 == 4) printf ("\n"); + } + if (i % 5 != 4) printf ("\n"); + + printf ("\nCurrent ship class = %d: ", ship->class); + i = get_value (); + if (i == 1) ship->class = value; + else if (i == -1) return; + + printf ("\nCurrent ship tonnage = %d: ", ship->tonnage); + i = get_value (); + if (i == 1) ship->tonnage = value; + else if (i == -1) return; + + printf ("\nCurrent ship dest_x = %d: ", ship->dest_x); + i = get_value (); + if (i == 1) ship->dest_x = value; + else if (i == -1) return; + + printf ("\nCurrent ship dest_y = %d: ", ship->dest_y); + i = get_value (); + if (i == 1) ship->dest_y = value; + else if (i == -1) return; + + printf ("\nCurrent ship dest_z = %d: ", ship->dest_z); + i = get_value (); + if (i == 1) ship->dest_z = value; + else if (i == -1) return; + +next_item: + printf ("\n"); + n = 0; + for (i = 0; i < MAX_ITEMS; i++) + { + printf ("\t%d: %d %ss", i+1, ship->item_quantity[i], item_abbr[i]); + if (++n % 4 == 0) printf ("\n"); + } + if (n % 4) printf ("\n"); + printf ("\nEnter 'item number-space-new quantity' or RETURN to continue: "); + get_name (answer); + if (answer[0] == 27) return; + else if (answer[0] != '\0') + { + i = 0; n = 0; + sscanf (answer, "%d%d", &i, &n); + if (i != 0) + { + ship->item_quantity[i-1] = n; + goto next_item; + } + } + + printf ("\nCurrent just_jumped value = %d: ", ship->just_jumped); + i = get_value (); + if (i == 1) ship->just_jumped = value; + else if (i == -1) return; + + printf ("\nCurrent age value = %d: ", ship->age); + i = get_value (); + if (i == 1) ship->age = value; + else if (i == -1) return; + + printf ("\nCurrent remaining_cost value = %d: ", ship->remaining_cost); + i = get_value (); + if (i == 1) ship->remaining_cost = value; + else if (i == -1) return; +} + + + +create_ship () + +{ + int i, found, unused_ship_available, ship_index; + + char name[32], upper_ship_name[32], upper_name[32]; + + struct ship_data *unused_ship; + + + /* Get ship name and make an upper case copy. */ + printf ("\nEnter name: "); + get_name (name); + if (name[0] == 27 || name[0] == '\0') return; + for (i = 0; i < 32; i++) upper_name[i] = toupper(name[i]); + + /* Search existing ships for name and location. */ + found = FALSE; + unused_ship_available = FALSE; + ship = ship_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) + { + /* We can re-use this ship rather than append a new one. */ + unused_ship = ship; + unused_ship_available = TRUE; + continue; + } + + /* Make upper case copy of ship name. */ + for (i = 0; i < 32; i++) + upper_ship_name[i] = toupper(ship->name[i]); + + /* Compare names. */ + if (strcmp (upper_ship_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (found) + { + printf ("\nShip name is already in use.\n\n"); + return; + } + + /* Add new ship to database for this species. */ + if (unused_ship_available) + ship = unused_ship; + else + { + ship = ship_base + (int) species->num_ships; + species->num_ships += 1; + delete_ship (ship); /* Set everything to zero. */ + } + + /* Initialize new ship. */ + strcpy (ship->name, name); + /* Everything else was set to zero in above call to 'delete_ship'. */ +} + + + +int get_location (need_planet) + +int need_planet; + +{ + int i, found; + + + printf ("\nEnter x-coordinate: "); + if (get_value() != 1) return; + x = value; + + printf ("\nEnter y-coordinate: "); + if (get_value() != 1) return; + y = value; + + printf ("\nEnter z-coordinate: "); + if (get_value() != 1) return; + z = value; + + if (need_planet) + { + printf ("Enter planet number: "); + if (get_value () != 1) return; + pn = value; + } + else + pn = 0; + + /* Get pointers to appropriate star and planet. */ + found = 0; + star = star_base; + for (i = 0; i < num_stars; i++) + { + if (star->x == x && star->y == y && star->z == z) + { + found = 1; + break; + } + ++star; + } + + if (found == 0) + { + printf ("\nThere is currently no star at these coordinates.\n\n"); + return FALSE; + } + + if (pn > star->num_planets) + { + printf ("\nPlanet number is too large for star!\n\n"); + return FALSE; + } + + /* Get pointer to planet. */ + if (need_planet) + planet = planet_base + (long) (star->planet_index + pn - 1); + + return TRUE; +} + + + +get_name (name) + +char name[]; + +{ + int i; + char temp[1024]; + + + for (i = 0; i < 32; i++) name[i] = 0; + +again: + fflush (stdout); + fgets (temp, 1024, stdin); + if (strlen(temp) > 32) + { + printf ("\n\tIt's too long! 31 characters max!\n"); + printf ("\nEnter again: "); + goto again; + } + + i = 0; + while (1) + { + if (temp[i] == '\n') break; + name[i] = temp[i]; + ++i; + } + + name[i] = '\0'; +} + + + +get_value () + +{ + char temp[1024]; + +again: + fflush (stdout); + fgets (temp, 1024, stdin); + + if (temp[0] == '\n') return 0; + + if (temp[0] == 27) return -1; /* Escape character. */ + + sscanf (temp, "%ld", &value); + + return 1; +} diff --git a/src/Finish.c b/src/Finish.c new file mode 100644 index 0000000..5f3c813 --- /dev/null +++ b/src/Finish.c @@ -0,0 +1,1282 @@ + +/* + This program should be run immediately before running the Report program; + i.e. immediately after the last run of AddSpecies in the very first turn, or + immediately after running PostArrival on all subsequent turns. This program + will create the file 'locations.dat' (via the do_locations subroutine), + update populations, handle interspecies transactions, and do some other + housekeeping chores. +*/ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number, species_index, header_printed; +int test_mode, verbose_mode; + +struct galaxy_data galaxy; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern int log_stdout, num_planets, num_transactions, num_locs; +extern unsigned long last_random; +extern FILE *log_file; + +extern struct planet_data *planet_base; +extern struct trans_data transaction[MAX_TRANSACTIONS]; +extern struct sp_loc_data loc[MAX_LOCATIONS]; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, n, rec, don, nampla_index, ship_index, ls_needed, + ls_actual, tech, turn_number, percent_increase, old_tech_level, + new_tech_level, experience_points, their_level, my_level, + new_level, orders_received, contact_bit_number, + contact_word_number, alien_number, galaxy_fd, + production_penalty, max_tech_level; + + short ns; + + long change, total_pop_units, contact_mask, salvage_EUs, + salvage_value, original_cost, ib, ab, increment, old_base, + max_cost, actual_cost, one_point_cost, working_pop_units, + ib_increment, ab_increment, md, growth_factor, denom, + fleet_maintenance_cost, balance, total_species_production, + RMs_produced, production_capacity, diff, total, eb, + *total_econ_base; + + char filename[32], *dest, *src; + + struct planet_data *home_planet; + struct species_data *donor_species; + struct nampla_data *home_nampla; + + + /* Check for options, if any. */ + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-t") == 0) test_mode = TRUE; + if (strcmp (argv[i], "-v") == 0) verbose_mode = TRUE; + } + + /* Seed random number generator. */ + last_random = time(NULL); + n = 907; + for (i = 0; i < n; i++) rnd(100); + + /* Get commonly used data. */ + get_galaxy_data (); + get_planet_data (); + get_species_data (); + get_transaction_data (); + num_locs = 0; + + /* Allocate memory for array "total_econ_base". */ + total = (long) num_planets * sizeof (long); + total_econ_base = (long *) malloc (total); + if (total_econ_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for total_econ_base!\n\n"); + exit (-1); + } + + /* Handle turn number. */ + turn_number = ++galaxy.turn_number; + galaxy_fd = creat ("galaxy.dat", 0600); + if (galaxy_fd < 0) + { + fprintf (stderr, "\n Cannot create new version of file galaxy.dat!\n"); + exit (-1); + } + + n = write (galaxy_fd, &galaxy, sizeof (struct galaxy_data)); + if (n != sizeof (struct galaxy_data)) + { + fprintf (stderr, "\n\tCannot write data to file 'galaxy.dat'!\n\n"); + exit (-1); + } + close (galaxy_fd); + + /* Do mining difficulty increases and initialize total economic base + for each planet. */ + planet = planet_base; + for (i = 0; i < num_planets; i++) + { + planet->mining_difficulty += planet->md_increase; + planet->md_increase = 0; + + total_econ_base[i] = 0; + + ++planet; + } + + /* Main loop. For each species, take appropriate action. */ + if (verbose_mode) printf ("\nFinishing up for all species...\n"); + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + if (! data_in_memory[species_number - 1]) continue; + + data_modified[species_number - 1] = TRUE; + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + /* Check if player submitted orders for this turn. */ + sprintf (filename, "sp%02d.ord\0", species_number); + i = open (filename, 0); + if (i < 0) + orders_received = FALSE; + else + { + orders_received = TRUE; + close (i); + } + if (turn_number == 1) orders_received = TRUE; + + /* Display name of species. */ + if (verbose_mode) + { + printf (" Now doing SP %s...", species->name); + if (! orders_received) + printf (" WARNING: player did not submit orders this turn!"); + printf ("\n"); + } + + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + log_stdout = FALSE; + header_printed = FALSE; + + if (turn_number == 1) goto check_for_message; + + /* Check if any ships of this species experienced mishaps. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == SHIP_MISHAP + && transaction[i].number1 == species_number) + { + if (! header_printed) print_header(); + log_string (" !!! "); + log_string (transaction[i].name1); + if (transaction[i].value < 3) + { + /* Intercepted or self-destructed. */ + log_string (" disappeared without a trace, cause unknown!\n"); + } + else if (transaction[i].value == 3) + { + /* Mis-jumped. */ + log_string (" mis-jumped to "); + log_int (transaction[i].x); log_char (' '); + log_int (transaction[i].y); log_char (' '); + log_int (transaction[i].z); log_string ("!\n"); + } + else + { + /* One fail-safe jump unit used. */ + log_string (" had a jump mishap! A fail-safe jump unit was expended.\n"); + } + } + } + + /* Take care of any disbanded colonies. */ + home_nampla = nampla_base; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if ((nampla->status & DISBANDED_COLONY) == 0) continue; + + /* Salvage ships on the surface and starbases in orbit. */ + salvage_EUs = 0; + ship = ship_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != ship->pn) continue; + if (ship->type != STARBASE && ship->status == IN_ORBIT) + continue; + + /* Transfer cargo to planet. */ + for (i = 0; i < MAX_ITEMS; i++) + nampla->item_quantity[i] += ship->item_quantity[i]; + + /* Salvage the ship. */ + if (ship->class == TR || ship->type == STARBASE) + original_cost = ship_cost[ship->class] * ship->tonnage; + else + original_cost = ship_cost[ship->class]; + + if (ship->type == SUB_LIGHT) + original_cost = (3 * original_cost) / 4; + + if (ship->status == UNDER_CONSTRUCTION) + salvage_value = + (original_cost - (long) ship->remaining_cost) / 4; + else + salvage_value = + (3 * original_cost * (60 - (long) ship->age)) / 400; + + salvage_EUs += salvage_value; + + /* Destroy the ship. */ + delete_ship (ship); + } + + /* Salvage items on the planet. */ + for (i = 0; i < MAX_ITEMS; i++) + { + if (i == RM) + salvage_value = nampla->item_quantity[RM] / 10; + else if (nampla->item_quantity[i] > 0) + { + original_cost = nampla->item_quantity[i] * item_cost[i]; + if (i == TP) + { + if (species->tech_level[BI] > 0) + original_cost /= (long) species->tech_level[BI]; + else + original_cost /= 100; + } + salvage_value = original_cost / 4; + } + else + salvage_value = 0; + + salvage_EUs += salvage_value; + } + + /* Transfer EUs to species. */ + species->econ_units += salvage_EUs; + + /* Log what happened. */ + if (! header_printed) print_header(); + log_string (" PL "); + log_string (nampla->name); + log_string (" was disbanded, generating "); + log_long (salvage_EUs); + log_string (" economic units in salvage.\n"); + + /* Destroy the colony. */ + delete_nampla (nampla); + } + + /* Check if this species is the recipient of a transfer of economic + units from another species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].recipient == species_number && + (transaction[i].type == EU_TRANSFER + || transaction[i].type == SIEGE_EU_TRANSFER + || transaction[i].type == LOOTING_EU_TRANSFER)) + { + /* Transfer EUs to attacker if this is a siege or looting + transfer. If this is a normal transfer, then just log + the result since the actual transfer was done when the + order was processed. */ + if (transaction[i].type != EU_TRANSFER) + species->econ_units += transaction[i].value; + + if (! header_printed) print_header(); + log_string (" "); + log_long (transaction[i].value); + log_string (" economic units were received from SP "); + log_string (transaction[i].name1); + if (transaction[i].type == SIEGE_EU_TRANSFER) + { + log_string (" as a result of your successful siege of their PL "); + log_string (transaction[i].name3); + log_string (". The siege was "); + log_long (transaction[i].number1); + log_string ("% effective"); + } + else if (transaction[i].type == LOOTING_EU_TRANSFER) + { + log_string (" as a result of your looting their PL "); + log_string (transaction[i].name3); + } + log_string (".\n"); + } + } + + /* Check if any jump portals of this species were used by aliens. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == ALIEN_JUMP_PORTAL_USAGE + && transaction[i].number1 == species_number) + { + if (! header_printed) print_header(); + log_string (" "); + log_string (transaction[i].name1); + log_char (' '); + log_string (transaction[i].name2); + log_string (" used jump portal "); + log_string (transaction[i].name3); + log_string (".\n"); + } + } + + /* Check if any starbases of this species detected the use of gravitic + telescopes by aliens. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == TELESCOPE_DETECTION + && transaction[i].number1 == species_number) + { + if (! header_printed) print_header(); + log_string ("! "); + log_string (transaction[i].name1); + log_string (" detected the operation of an alien gravitic telescope at x = "); + log_int (transaction[i].x); + log_string (", y = "); log_int (transaction[i].y); + log_string (", z = "); log_int (transaction[i].z); + log_string (".\n"); + } + } + + /* Check if this species is the recipient of a tech transfer from + another species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == TECH_TRANSFER + && transaction[i].recipient == species_number) + { + rec = transaction[i].recipient - 1; + don = transaction[i].donor - 1; + + /* Try to transfer technology. */ + if (! header_printed) print_header(); + log_string (" "); + tech = transaction[i].value; + log_string (tech_name[tech]); + log_string (" tech transfer from SP "); + log_string (transaction[i].name1); + their_level = transaction[i].number3; + my_level = species->tech_level[tech]; + + if (their_level <= my_level) + { + log_string (" failed.\n"); + transaction[i].number1 = -1; + continue; + } + + new_level = my_level; + max_cost = transaction[i].number1; + donor_species = &spec_data[don]; + if (max_cost == 0) + max_cost = donor_species->econ_units; + else if (donor_species->econ_units < max_cost) + max_cost = donor_species->econ_units; + actual_cost = 0; + while (new_level < their_level) + { + one_point_cost = new_level * new_level; + one_point_cost -= one_point_cost/4; /* 25% discount. */ + if ((actual_cost + one_point_cost) > max_cost) break; + actual_cost += one_point_cost; + ++new_level; + } + + if (new_level == my_level) + { + log_string (" failed due to lack of funding.\n"); + transaction[i].number1 = -2; + } + else + { + log_string (" raised your tech level from "); + log_int (my_level); + log_string (" to "); + log_int (new_level); + log_string (" at a cost to them of "); + log_long (actual_cost); + log_string (".\n"); + transaction[i].number1 = actual_cost; + transaction[i].number2 = my_level; + transaction[i].number3 = new_level; + + species->tech_level[tech] = new_level; + donor_species->econ_units -= actual_cost; + } + } + } + + /* Calculate tech level increases. */ + for (tech = MI; tech <= BI; tech++) + { + old_tech_level = species->tech_level[tech]; + new_tech_level = old_tech_level; + + experience_points = species->tech_eps[tech]; + if (experience_points == 0) goto check_random; + + /* Determine increase as if there were NO randomness in the + process. */ + i = experience_points; + j = old_tech_level; + while (i >= j * j) + { + i -= j * j; + ++j; + } + + /* When extremely large amounts are spent on research, tech + level increases are sometimes excessive. Set a limit. */ + if (old_tech_level > 50) + max_tech_level = j + 1; + else + max_tech_level = 9999; + + /* Allocate half of the calculated increase NON-RANDOMLY. */ + n = (j - old_tech_level) / 2; + for (i = 0; i < n; i++) + { + experience_points -= new_tech_level * new_tech_level; + ++new_tech_level; + } + + /* Allocate the rest randomly. */ + while (experience_points >= new_tech_level) + { + experience_points -= new_tech_level; + n = new_tech_level; + + /* The chance of success is 1 in n. At this point, n is + always at least 1. */ + + i = rnd (16*n); + if (i >= 8*n && i <= 8*n+15) + new_tech_level = n + 1; + } + + /* Save unused experience points. */ + species->tech_eps[tech] = experience_points; + +check_random: + + /* See if any random increase occurred. Odds are 1 in 6. */ + if (old_tech_level > 0 && rnd(6) == 6) ++new_tech_level; + + if (new_tech_level > max_tech_level) + new_tech_level = max_tech_level; + + /* Report result only if tech level went up. */ + if (new_tech_level > old_tech_level) + { + if (! header_printed) print_header(); + log_string (" "); + log_string (tech_name[tech]); + log_string (" tech level rose from "); + log_int (old_tech_level); log_string (" to "); + log_int (new_tech_level); + log_string (".\n"); + + species->tech_level[tech] = new_tech_level; + } + } + + /* Notify of any new high tech items. */ + for (tech = MI; tech <= BI; tech++) + { + old_tech_level = species->init_tech_level[tech]; + new_tech_level = species->tech_level[tech]; + + if (new_tech_level > old_tech_level) + check_high_tech_items (tech, old_tech_level, new_tech_level); + + species->init_tech_level[tech] = new_tech_level; + } + + /* Check if this species is the recipient of a knowledge transfer + from another species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == KNOWLEDGE_TRANSFER + && transaction[i].recipient == species_number) + { + rec = transaction[i].recipient - 1; + don = transaction[i].donor - 1; + + /* Try to transfer technology. */ + tech = transaction[i].value; + their_level = transaction[i].number3; + my_level = species->tech_level[tech]; + n = species->tech_knowledge[tech]; + if (n > my_level) my_level = n; + + if (their_level <= my_level) continue; + + species->tech_knowledge[tech] = their_level; + + if (! header_printed) print_header(); + log_string (" SP "); + log_string (transaction[i].name1); + log_string (" transferred knowledge of "); + log_string (tech_name[tech]); + log_string (" to you up to tech level "); + log_long (their_level); + log_string (".\n"); + } + } + + /* Loop through each nampla for this species. */ + home_nampla = nampla_base; + home_planet = planet_base + (long) home_nampla->planet_index; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->pn == 99) continue; + + /* Get planet pointer. */ + planet = planet_base + (long) nampla->planet_index; + + /* Clear any amount spent on ambush. */ + nampla->use_on_ambush = 0; + + /* Handle HIDE order. */ + nampla->hidden = nampla->hiding; + nampla->hiding = FALSE; + + /* Check if any IUs or AUs were installed. */ + if (nampla->IUs_to_install > 0) + { + nampla->mi_base += nampla->IUs_to_install; + nampla->IUs_to_install = 0; + } + + if (nampla->AUs_to_install > 0) + { + nampla->ma_base += nampla->AUs_to_install; + nampla->AUs_to_install = 0; + } + + /* Check if another species on the same planet has become + assimilated. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == ASSIMILATION + && transaction[i].value == species_number + && transaction[i].x == nampla->x + && transaction[i].y == nampla->y + && transaction[i].z == nampla->z + && transaction[i].pn == nampla->pn) + { + ib = transaction[i].number1; + ab = transaction[i].number2; + ns = transaction[i].number3; + nampla->mi_base += ib; + nampla->ma_base += ab; + nampla->shipyards += ns; + + if (! header_printed) print_header(); + + log_string (" Assimilation of "); + log_string (transaction[i].name1); + log_string (" PL "); + log_string (transaction[i].name2); + log_string (" increased mining base of "); + log_string (species->name); + log_string (" PL "); + log_string (nampla->name); + log_string (" by "); + log_long (ib/10); log_char ('.'); log_long (ib%10); + log_string (", and manufacturing base by "); + log_long (ab/10); log_char ('.'); log_long (ab%10); + if (ns > 0) + { + log_string (". Number of shipyards was also increased by "); + log_int (ns); + } + log_string (".\n"); + } + } + + /* Calculate available population for this turn. */ + nampla->pop_units = 0; + + eb = nampla->mi_base + nampla->ma_base; + total_pop_units = eb + nampla->item_quantity[CU] + + nampla->item_quantity[PD]; + + if (nampla->status & HOME_PLANET) + { + if (nampla->status & POPULATED) + { + nampla->pop_units = HP_AVAILABLE_POP; + + if (species->hp_original_base != 0) /* HP was bombed. */ + { + if (eb >= species->hp_original_base) + species->hp_original_base = 0; /* Fully recovered. */ + else + nampla->pop_units = (eb * HP_AVAILABLE_POP) + / species->hp_original_base; + } + } + } + else if (nampla->status & POPULATED) + { + /* Get life support tech level needed. */ + ls_needed = life_support_needed (species, home_planet, planet); + + /* Basic percent increase is 10*(1 - ls_needed/ls_actual). */ + ls_actual = species->tech_level[LS]; + percent_increase = + 10 * (100 - ((100 * ls_needed)/ls_actual)); + + if (percent_increase < 0) /* Colony wiped out! */ + { + if (! header_printed) print_header(); + + log_string (" !!! Life support tech level was too low to support colony on PL "); + log_string (nampla->name); + log_string (". Colony was destroyed.\n"); + + nampla->status = COLONY; /* No longer populated or + self-sufficient. */ + nampla->mi_base = 0; + nampla->ma_base = 0; + nampla->pop_units = 0; + nampla->item_quantity[PD] = 0; + nampla->item_quantity[CU] = 0; + nampla->siege_eff = 0; + } + else + { + percent_increase /= 100; + + /* Add a small random variation. */ + percent_increase += + rnd(percent_increase/4) - rnd(percent_increase/4); + + /* Add bonus for Biology technology. */ + percent_increase += (int) species->tech_level[BI] / 20; + + /* Calculate and apply the change. */ + change = (percent_increase * total_pop_units) / 100; + + if (nampla->mi_base > 0 && nampla->ma_base == 0) + { + nampla->status |= MINING_COLONY; + change = 0; + } + else if (nampla->status & MINING_COLONY) + { + /* A former mining colony has been converted to a + normal colony. */ + nampla->status &= ~MINING_COLONY; + change = 0; + } + + if (nampla->ma_base > 0 && nampla->mi_base == 0 + && ls_needed <= 6 + && planet->gravity <= home_planet->gravity) + { + nampla->status |= RESORT_COLONY; + change = 0; + } + else if (nampla->status & RESORT_COLONY) + { + /* A former resort colony has been converted to a + normal colony. */ + nampla->status &= ~RESORT_COLONY; + change = 0; + } + + if (total_pop_units == nampla->item_quantity[PD]) + change = 0; /* Probably an invasion force. */ + + nampla->pop_units = change; + } + } + + /* Handle losses due to attrition and update location array if + planet is still populated. */ + if (nampla->status & POPULATED) + { + total_pop_units = nampla->pop_units + nampla->mi_base + + nampla->ma_base + nampla->item_quantity[CU] + + nampla->item_quantity[PD]; + + if (total_pop_units > 0 && total_pop_units < 50) + { + if (nampla->pop_units > 0) + { + --nampla->pop_units; + goto do_auto_increases; + } + else if (nampla->item_quantity[CU] > 0) + { + --nampla->item_quantity[CU]; + if (! header_printed) print_header(); + log_string (" Number of colonist units on PL "); + log_string (nampla->name); + log_string (" was reduced by one unit due to normal attrition."); + } + else if (nampla->item_quantity[PD] > 0) + { + --nampla->item_quantity[PD]; + if (! header_printed) print_header(); + log_string (" Number of planetary defense units on PL "); + log_string (nampla->name); + log_string (" was reduced by one unit due to normal attrition."); + } + else if (nampla->ma_base > 0) + { + --nampla->ma_base; + if (! header_printed) print_header(); + log_string (" Manufacturing base of PL "); + log_string (nampla->name); + log_string (" was reduced by 0.1 due to normal attrition."); + } + else + { + --nampla->mi_base; + if (! header_printed) print_header(); + log_string (" Mining base of PL "); + log_string (nampla->name); + log_string (" was reduced by 0.1 due to normal attrition."); + } + + if (total_pop_units == 1) + { + if (! header_printed) print_header(); + log_string (" The colony is dead!"); + } + + log_char ('\n'); + } + } + +do_auto_increases: + + /* Apply automatic 2% increase to mining and manufacturing bases + of home planets. */ + if (nampla->status & HOME_PLANET) + { + growth_factor = 20L; + ib = nampla->mi_base; + ab = nampla->ma_base; + old_base = ib + ab; + increment = (growth_factor * old_base) / 1000; + md = planet->mining_difficulty; + + denom = 100 + md; + ab_increment = + (100 * (increment + ib) - (md * ab) + denom/2) / denom; + ib_increment = increment - ab_increment; + + if (ib_increment < 0) + { + ab_increment = increment; + ib_increment = 0; + } + if (ab_increment < 0) + { + ib_increment = increment; + ab_increment = 0; + } + nampla->mi_base += ib_increment; + nampla->ma_base += ab_increment; + } + + check_pop: + + check_population (nampla); + + /* Update total economic base for colonies. */ + if ((nampla->status & HOME_PLANET) == 0) + total_econ_base[nampla->planet_index] += + nampla->mi_base + nampla->ma_base; + } + + /* Loop through all ships for this species. */ + ship = ship_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) continue; + + /* Set flag if ship arrived via a natural wormhole. */ + if (ship->just_jumped == 99) + ship->arrived_via_wormhole = TRUE; + else + ship->arrived_via_wormhole = FALSE; + + /* Clear 'just-jumped' flag. */ + ship->just_jumped = FALSE; + + /* Increase age of ship. */ + if (ship->status != UNDER_CONSTRUCTION) + { + ship->age += 1; + if (ship->age > 49) ship->age = 49; + } + } + + /* Check if this species has a populated planet that another species + tried to land on. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == LANDING_REQUEST + && transaction[i].number1 == species_number) + { + if (! header_printed) print_header(); + log_string (" "); + log_string (transaction[i].name2); + log_string (" owned by SP "); + log_string (transaction[i].name3); + if (transaction[i].value) + log_string (" was granted"); + else + log_string (" was denied"); + log_string (" permission to land on PL "); + log_string (transaction[i].name1); + log_string (".\n"); + } + } + + /* Check if this species is the recipient of interspecies + construction. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == INTERSPECIES_CONSTRUCTION + && transaction[i].recipient == species_number) + { + /* Simply log the result. */ + if (! header_printed) print_header(); + log_string (" "); + if (transaction[i].value == 1) + { + log_long (transaction[i].number1); log_char (' '); + log_string (item_name[transaction[i].number2]); + if (transaction[i].number1 == 1) + log_string (" was"); + else + log_string ("s were"); + log_string (" constructed for you by SP "); + log_string (transaction[i].name1); + log_string (" on PL "); + log_string (transaction[i].name2); + } + else + { + log_string (transaction[i].name2); + log_string (" was constructed for you by SP "); + log_string (transaction[i].name1); + } + log_string (".\n"); + } + } + + /* Check if this species is besieging another species and detects + forbidden construction, landings, etc. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == DETECTION_DURING_SIEGE + && transaction[i].number3 == species_number) + { + /* Log what was detected and/or destroyed. */ + if (! header_printed) print_header(); + log_string (" "); + log_string ("During the siege of "); + log_string (transaction[i].name3); + log_string (" PL "); + log_string (transaction[i].name1); + log_string (", your forces detected the "); + + if (transaction[i].value == 1) + { + /* Landing of enemy ship. */ + log_string ("landing of "); + log_string (transaction[i].name2); + log_string (" on the planet.\n"); + } + else if (transaction[i].value == 2) + { + /* Enemy ship or starbase construction. */ + log_string ("construction of "); + log_string (transaction[i].name2); + log_string (", but you destroyed it before it"); + log_string (" could be completed.\n"); + } + else if (transaction[i].value == 3) + { + /* Enemy PD construction. */ + log_string ("construction of planetary defenses, but you"); + log_string (" destroyed them before they could be completed.\n"); + } + else if (transaction[i].value == 4 + || transaction[i].value == 5) + { + /* Enemy item construction. */ + log_string ("transfer of "); + log_int (transaction[i].number1); + log_char (' '); + log_string (item_name[transaction[i].number2]); + if (transaction[i].number1 > 1) log_char ('s'); + if (transaction[i].value == 4) + log_string (" to PL "); + else + log_string (" from PL "); + log_string (transaction[i].name2); + log_string (", but you destroyed them in transit.\n"); + } + else + { + fprintf (stderr, "\n\tInternal error! Cannot reach this point!\n\n"); + exit (-1); + } + } + } + +check_for_message: + + /* Check if this species is the recipient of a message from another + species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == MESSAGE_TO_SPECIES + && transaction[i].number2 == species_number) + { + if (! header_printed) print_header(); + log_string ("\n You received the following message from SP "); + log_string (transaction[i].name1); + log_string (":\n\n"); + + sprintf (filename, "m%d.msg\0", (int) transaction[i].value); + + log_message (filename); + + log_string ("\n *** End of Message ***\n\n"); + } + } + + /* Close log file. */ + fclose (log_file); + } + + /* Calculate economic efficiency for each planet. */ + planet = planet_base; + for (i = 0; i < num_planets; i++) + { + total = total_econ_base[i]; + diff = total - 2000; + + if (diff <= 0) + planet->econ_efficiency = 100; + else + planet->econ_efficiency = (100 * (diff/20 + 2000)) / total; + + ++planet; + } + + /* Create new locations array. */ + do_locations (); + + if (turn_number == 1) goto clean_up; + + /* Go through all species one more time to update alien contact masks, + report tech transfer results to donors, and calculate fleet + maintenance costs. */ + if (verbose_mode) printf ("\nNow updating contact masks et al.\n"); + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (! data_in_memory[species_index]) continue; + + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + ship_base = ship_data[species_index]; + species_number = species_index + 1; + + home_nampla = nampla_base; + home_planet = planet_base + (long) home_nampla->planet_index; + + /* Update contact mask in species data if this species has met a + new alien. */ + for (i = 0; i < num_locs; i++) + { + if (loc[i].s != species_number) continue; + + for (j = 0; j < num_locs; j++) + { + if (loc[j].s == species_number) continue; + if (loc[j].x != loc[i].x) continue; + if (loc[j].y != loc[i].y) continue; + if (loc[j].z != loc[i].z) continue; + + /* We are in contact with an alien. Make sure it is not + hidden from us. */ + alien_number = loc[j].s; + if (alien_is_visible (loc[j].x, loc[j].y, loc[j].z, + species_number, alien_number)) + { + contact_word_number = (loc[j].s - 1) / 32; + contact_bit_number = (loc[j].s - 1) % 32; + contact_mask = 1 << contact_bit_number; + species->contact[contact_word_number] |= contact_mask; + } + } + } + + /* Report results of tech transfers to donor species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type == TECH_TRANSFER + && transaction[i].donor == species_number) + { + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + log_stdout = FALSE; + + log_string (" "); + tech = transaction[i].value; + log_string (tech_name[tech]); + log_string (" tech transfer to SP "); + log_string (transaction[i].name2); + + if (transaction[i].number1 < 0) + { + log_string (" failed"); + if (transaction[i].number1 == -2) + log_string (" due to lack of funding"); + } + else + { + log_string (" raised their tech level from "); + log_long (transaction[i].number2); + log_string (" to "); + log_long (transaction[i].number3); + log_string (" at a cost to you of "); + log_long (transaction[i].number1); + } + + log_string (".\n"); + + fclose (log_file); + } + } + + /* Calculate fleet maintenance cost and its percentage of total + production. */ + fleet_maintenance_cost = 0; + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + + if (ship->class == TR) + n = 4 * (int) ship->tonnage; + else if (ship->class == BA) + n = 10 * (int) ship->tonnage; + else + n = 20 * (int) ship->tonnage; + + if (ship->type == SUB_LIGHT) + n -= (25 * n) / 100; + + fleet_maintenance_cost += n; + } + + /* Subtract military discount. */ + i = (int) species->tech_level[ML] / 2; + fleet_maintenance_cost -= (i * fleet_maintenance_cost) / 100; + + /* Calculate total production. */ + total_species_production = 0; + nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->pn == 99) continue; + if (nampla->status & DISBANDED_COLONY) continue; + + planet = planet_base + (long) nampla->planet_index; + + ls_needed = life_support_needed (species, home_planet, planet); + + if (ls_needed == 0) + production_penalty = 0; + else + production_penalty = (100 * ls_needed) / species->tech_level[LS]; + + RMs_produced = + (10L * (long) species->tech_level[MI] * (long) nampla->mi_base) + / (long) planet->mining_difficulty; + RMs_produced + -= (production_penalty * RMs_produced) / 100; + + production_capacity = + ((long) species->tech_level[MA] * (long) nampla->ma_base) / 10L; + production_capacity + -= (production_penalty * production_capacity) / 100; + + if (nampla->status & MINING_COLONY) + balance = (2 * RMs_produced) / 3; + else if (nampla->status & RESORT_COLONY) + balance = (2 * production_capacity) / 3; + else + { + RMs_produced += nampla->item_quantity[RM]; + balance = (RMs_produced > production_capacity) + ? production_capacity : RMs_produced; + } + + balance = (((long) planet->econ_efficiency * balance) + 50) / 100; + + total_species_production += balance; + } + + /* If cost is greater than production, take as much as possible + from EUs in treasury.* + if (fleet_maintenance_cost > total_species_production) + { + if (fleet_maintenance_cost > species->econ_units) + { + fleet_maintenance_cost -= species->econ_units; + species->econ_units = 0; + { + else + { + species->econ_units -= fleet_maintenance_cost; + fleet_maintenance_cost = 0; + } + } + + /* Save fleet maintenance results. */ + species->fleet_cost = fleet_maintenance_cost; + if (total_species_production > 0) + species->fleet_percent_cost = (10000 * fleet_maintenance_cost) + / total_species_production; + else + species->fleet_percent_cost = 10000; + } + +clean_up: + + /* Clean up and exit. */ + save_planet_data (); + save_location_data (); + save_species_data (); + free_species_data (); + free (planet_base); + free (total_econ_base); + exit (0); +} + + + + +print_header () + +{ + log_string ("\nOther events:\n"); + header_printed = TRUE; +} + + + +alien_is_visible (x, y, z, species_number, alien_number) + +char x, y, z; +int species_number, alien_number; + +{ + + int i, j; + + struct species_data *species, *alien; + struct nampla_data *nampla, *alien_nampla; + struct ship_data *alien_ship; + + + /* Check if the alien has a ship or starbase here that is in orbit or in + deep space. */ + alien = &spec_data[alien_number - 1]; + alien_ship = ship_data[alien_number - 1] - 1; + for (i = 0; i < alien->num_ships; i++) + { + ++alien_ship; + + if (alien_ship->x != x) continue; + if (alien_ship->y != y) continue; + if (alien_ship->z != z) continue; + if (alien_ship->item_quantity[FD] == alien_ship->tonnage) continue; + + if (alien_ship->status == IN_ORBIT + || alien_ship->status == IN_DEEP_SPACE) + return TRUE; + } + + /* Check if alien has a planet that is not hidden. */ + alien_nampla = namp_data[alien_number - 1] - 1; + for (i = 0; i < alien->num_namplas; i++) + { + ++alien_nampla; + + if (alien_nampla->x != x) continue; + if (alien_nampla->y != y) continue; + if (alien_nampla->z != z) continue; + if ((alien_nampla->status & POPULATED) == 0) continue; + + if (! alien_nampla->hidden) return TRUE; + + /* The colony is hidden. See if we have population on the same + planet. */ + species = &spec_data[species_number - 1]; + nampla = namp_data[species_number - 1] - 1; + for (j = 0; j < species->num_namplas; j++) + { + ++nampla; + + if (nampla->x != x) continue; + if (nampla->y != y) continue; + if (nampla->z != z) continue; + if (nampla->pn != alien_nampla->pn) continue; + if ((nampla->status & POPULATED) == 0) continue; + + /* We have population on the same planet, so the alien + cannot hide. */ + return TRUE; + } + } + + return FALSE; +} diff --git a/src/HomeSystem.c b/src/HomeSystem.c new file mode 100644 index 0000000..297df15 --- /dev/null +++ b/src/HomeSystem.c @@ -0,0 +1,275 @@ + +/* This program has two modes: if provided with X Y Z coordinates, it will +convert the star system to one suitable for a home system. If not given any +arguments, it will randomly select an X Y Z that is at least 10 parsecs from +all other home systems. */ + + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int x, y, z, species_number; + +long min_distance, min_d_squared; + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet, *first_planet; + +extern int num_stars, num_planets; +extern unsigned long last_random; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, found, home_system_fd, home_planet_number, + num_home_systems; + + long n, num_bytes; + + char filename[32], answer[16]; + + /* Check for valid command line. */ + min_distance = 10; + if (argc == 1) + ; + else if (argc == 2) + min_distance = atoi (argv[1]); + else if (argc == 4) + { + x = atoi (argv[1]); + y = atoi (argv[2]); + z = atoi (argv[3]); + } + else + { + fprintf (stderr, "\n Usage: HomeSystem min_distance or HomeSystem [x y z]\n"); + fprintf (stderr, "\t\t (default min_distance is 10 parsecs)\n\n"); + exit (-1); + } + min_d_squared = min_distance * min_distance; + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get all the raw data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + + if (argc < 3) + { + get_random_xyz (); + fprintf (stdout, "\n\nIs %d %d %d okay (y or Y = yes)? ", x, y, z); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] == 'y' || answer[0] == 'Y') + goto convert; + else + exit (0); + } + + /* Get pointers to appropriate star. */ + found = FALSE; + star = star_base; + for (i = 0; i < num_stars; i++) + { + if (star->x == x && star->y == y && star->z == z) + { + found = TRUE; + break; + } + ++star; + } + + if (found == 0) + { + fprintf (stderr, + "\n\tThere is no star at these coordinates! Try again.\n\n"); + exit (-1); + } + + if (star->num_planets < 3) + { + fprintf (stderr, + "\n\tA home system must have at least three planets! Try again.\n\n"); + exit (-1); + } + +convert: + + /* Open file HSn, where n is the number of planets in the system. We will + overwrite the existing planet data with the data in the file. */ + sprintf (filename, "HS%d\0", star->num_planets); + home_system_fd = open (filename, 0); + if (home_system_fd < 0) + { + fprintf (stderr, "\n\tFile '%s' does not exist!\n\n", filename); + exit (-1); + } + + first_planet = planet_base + (long) star->planet_index; + + num_bytes = (long) star->num_planets * sizeof (struct planet_data); + n = read (home_system_fd, first_planet, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\n\tCannot read home system data in file '%s'!\n\n", + filename); + exit (-1); + } + + /* Make minor random modifications to data for planets in this system. */ + planet = first_planet; + home_planet_number = 999; + for (i = 0; i < star->num_planets; i++) + { + if (planet->special == 1) home_planet_number = i + 1; + + if (planet->temperature_class == 0) + ; + else if (planet->temperature_class > 12) + planet->temperature_class -= rnd(3) - 1; + else + planet->temperature_class += rnd(3) - 1; + + if (planet->pressure_class == 0) + ; + else if (planet->pressure_class > 12) + planet->pressure_class -= rnd(3) - 1; + else + planet->pressure_class += rnd(3) - 1; + + if (planet->gas[2] > 0) + { + j = rnd(25) + 10; + if (planet->gas_percent[2] > 50) + { + planet->gas_percent[1] += j; + planet->gas_percent[2] -= j; + } + else if (planet->gas_percent[1] > 50) + { + planet->gas_percent[1] -= j; + planet->gas_percent[2] += j; + } + } + + if (planet->diameter > 12) + planet->diameter -= rnd(3) - 1; + else + planet->diameter += rnd(3) - 1; + + if (planet->gravity > 100) + planet->gravity -= rnd(10); + else + planet->gravity += rnd(10); + + if (planet->mining_difficulty > 100) + planet->mining_difficulty -= rnd(10); + else + planet->mining_difficulty += rnd(10); + + ++planet; + } + + star->home_system = TRUE; + + /* Count number of home systems. */ + star = star_base; + num_home_systems = 0; + for (i = 0; i < num_stars; i++) + { + if (star->home_system) ++num_home_systems; + + ++star; + } + + /* Save data and clean up. */ + save_star_data (); + save_planet_data (); + free (star_base); + free (planet_base); + + fprintf (stdout, "\n\tNew home planet is at %d %d %d #%d.\n", + x, y, z, home_planet_number); + + fprintf (stdout, "\n\tTotal number of home systems is now %d.\n\n", + num_home_systems); + + exit (0); +} + + + +get_random_xyz () + +{ + int i, found; + + long n, max_checks, dx, dy, dz, d_sq; + + struct star_data *star2; + + + n = 0; + max_checks = 25L * num_stars; + + while (1) + { + if (n++ > max_checks) + { + fprintf (stderr, "\n\tIt appears that all suitable systems are within %ld parsecs of an\n", min_distance); + fprintf (stderr, "\texisting home system. You'll have to select a system manually.\n\n"); + exit (0); + } + + i = rnd(num_stars); + star = star_base + (i - 1); + + if (star->home_system) continue; + if (star->worm_here) continue; + if (star->num_planets < 3) continue; + + x = star->x; + y = star->y; + z = star->z; + + /* See if there is another home system within 'min-distance' parsecs. */ + found = FALSE; + star2 = star_base - 1; + for (i = 0; i < num_stars; i++) + { + ++star2; + + if (star2->home_system == FALSE) continue; + + dx = (long) x - (long) star2->x; + dy = (long) y - (long) star2->y; + dz = (long) z - (long) star2->z; + + d_sq = dx * dx + dy * dy + dz * dz; + + if (d_sq < min_d_squared) + { + found = TRUE; + break; + } + } + + if (! found) return; + } +} diff --git a/src/Jump.c b/src/Jump.c new file mode 100644 index 0000000..f50ec68 --- /dev/null +++ b/src/Jump.c @@ -0,0 +1,391 @@ +#define THIS_IS_MAIN + +#include "fh.h" + + +int x, y, z, pn, nampla_index, first_pass, ship_index, species_number; + +int test_mode, verbose_mode; + +extern int star_data_modified, planet_data_modified; +extern struct star_data *star_base; +extern struct planet_data *planet_base; + +struct galaxy_data galaxy; +struct star_data *star; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + + +extern int truncate_name, end_of_file, num_stars, num_planets, log_stdout, + ignore_field_distorters, just_opened_file; +extern long last_random; +extern char input_line[256], *input_line_pointer; +extern FILE *input_file, *log_file; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, found, num_species, sp_num[MAX_SPECIES], sp_index, + command, log_file_open, do_all_species; + + char filename[32], species_jumped[MAX_SPECIES], keyword[4]; + + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get commonly used data. */ + get_galaxy_data (); + get_transaction_data (); + + ignore_field_distorters = TRUE; + + /* Check arguments. If an argument is -p, then do two passes. In the + first pass, display results and prompt the GM, allowing him to + abort if necessary before saving results to disk. All other + arguments must be species numbers. If no species numbers are + specified, then do all species. */ + num_species = 0; + first_pass = FALSE; + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-p") == 0) + first_pass = TRUE; + else if (strcmp (argv[i], "-t") == 0) + test_mode = TRUE; + else if (strcmp (argv[i], "-v") == 0) + verbose_mode = TRUE; + else + { + n = atoi (argv[i]); + if (n < 1 || n > galaxy.num_species) + { + fprintf (stderr, + "\n '%s' is not a valid argument!\n", argv[i]); + exit (-1); + } + sp_num[num_species++] = n; + } + } + + if (num_species == 0) + { + num_species = galaxy.num_species; + for (i = 0; i < num_species; i++) + sp_num[i] = i+1; + do_all_species = TRUE; + } + else + do_all_species = FALSE; + + /* For these commands, do not display age or landed/orbital status + of ships. */ + truncate_name = TRUE; + log_stdout = FALSE; /* We will control value of log_file from here. */ + + /* Initialize array that will indicate which species provided jump + orders. If ships of a species withdrew or were forced from combat + and there were no jump orders for that species, then combat jumps + will not take place. This array will allow us to handle them + separately. */ + for (i = 0; i < galaxy.num_species; i++) + species_jumped[i] = FALSE; + + /* Two passes through all orders will be done. The first pass will + check for errors and abort if any are found. Results will be written + to disk only on the second pass. */ + +start_pass: + + if (first_pass) printf ("\nStarting first pass...\n\n"); + + get_species_data (); + get_star_data (); + get_planet_data (); + + /* Main loop. For each species, take appropriate action. */ + for (sp_index = 0; sp_index < num_species; sp_index++) + { + species_number = sp_num[sp_index]; + + found = data_in_memory[species_number - 1]; + if (! found) + { + if (do_all_species) + { + if (first_pass) printf ("\n Skipping species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n Cannot get data for species #%d!\n", + species_number); + exit (-1); + } + } + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + /* Open orders file for this species. */ + sprintf (filename, "sp%02d.ord\0", species_number); + input_file = fopen (filename, "r"); + if (input_file == NULL) + { + if (do_all_species) + { + if (first_pass) printf ("\n No orders for species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + } + + /* Open log file. Use stdout for first pass. */ + if (first_pass) + { + log_file = stdout; + } + else + { + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + } + + end_of_file = FALSE; + + just_opened_file = TRUE; /* Tell parse.c to skip mail header, + if any. */ +find_start: + + /* Search for START JUMPS order. */ + found = FALSE; + while (! found) + { + command = get_command(); + if (command == MESSAGE) + { + /* Skip MESSAGE text. It may contain a line that starts + with "start". */ + while (TRUE) + { + command = get_command(); + if (command < 0) + { + fprintf (stderr, + "WARNING: Unterminated MESSAGE command in file %s!\n", + filename); + break; + } + + if (command == ZZZ) goto find_start; + } + } + + if (command < 0) + break; /* End of file. */ + + if (command != START) + continue; + + /* Get the first three letters of the keyword and convert to + upper case. */ + skip_whitespace(); + for (i = 0; i < 3; i++) + { + keyword[i] = toupper (*input_line_pointer); + ++input_line_pointer; + } + keyword[3] = '\0'; + + if (strcmp(keyword, "JUM") == 0) found = TRUE; + } + + if (! found) + { + if (first_pass) printf ("\nNo jump orders for species #%d, SP %s.\n", + species_number, species->name); + goto done_orders; + } + + /* Handle jump orders for this species. */ + log_string ("\nJump orders:\n"); + do_jump_orders (); + species_jumped[species_number - 1] = TRUE; + data_modified[species_number - 1] = TRUE; + +done_orders: + + fclose (input_file); + + /* Take care of any ships that withdrew or were forced to jump during + combat. */ + ship = ship_base; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + if (ship->status == FORCED_JUMP + || ship->status == JUMPED_IN_COMBAT) + do_JUMP_command (TRUE, FALSE); + ++ship; + } + + /* If this is the second pass, close the log file. */ + if (! first_pass) fclose (log_file); + } + + if (first_pass) + { + printf ("\nFinal chance to abort safely!\n"); + gamemaster_abort_option (); + first_pass = FALSE; + free_species_data (); + free (star_base); /* In case data was modified. */ + free (planet_base); /* In case data was modified. */ + + printf ("\nStarting second pass...\n\n"); + + goto start_pass; + } + +no_jump_orders: + + /* Take care of any ships that withdrew from combat but were not + handled above because no jump orders were received for species. */ + log_stdout = TRUE; + log_file_open = FALSE; + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + if (species_jumped[species_number - 1]) continue; + + if (! data_in_memory[species_number - 1]) continue; + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + ship = ship_base; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + if (! log_file_open) + { + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + log_file_open = TRUE; + log_string ("\nWithdrawals and forced jumps during combat:\n"); + } + + do_JUMP_command (TRUE, FALSE); + } + ++ship; + } + + data_modified[species_number - 1] = log_file_open; + + if (log_file_open) + { + fclose (log_file); + log_file_open = FALSE; + } + } + + save_species_data (); + save_transaction_data (); + if (star_data_modified) save_star_data (); + if (planet_data_modified) save_planet_data (); + free_species_data (); + free (star_base); + free (planet_base); + exit (0); +} + + + +do_jump_orders () + +{ + int i, command; + + + if (first_pass) + printf ("\nStart of jump orders for species #%d, SP %s...\n", + species_number, species->name); + + while (TRUE) + { + command = get_command(); + + if (command == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Unknown or missing command.\n"); + continue; + } + + if (end_of_file || command == END) + { + if (first_pass) + printf ("End of jump orders for species #%d, SP %s.\n", + species_number, species->name); + + if (first_pass) gamemaster_abort_option (); + + break; /* END for this species. */ + } + + switch (command) + { + case JUMP: + do_JUMP_command (FALSE, FALSE); + break; + + case MOVE: + do_MOVE_command (); + break; + + case PJUMP: + do_JUMP_command (FALSE, TRUE); + break; + + case VISITED: + do_VISITED_command (); + break; + + case WORMHOLE: + do_WORMHOLE_command (); + break; + + default: + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid jump command.\n"); + } + } +} diff --git a/src/ListGalaxy.c b/src/ListGalaxy.c new file mode 100644 index 0000000..c7f2062 --- /dev/null +++ b/src/ListGalaxy.c @@ -0,0 +1,258 @@ + +/* This program will list all of the planets in the galaxy using the data + in the files "galaxy.dat" and "planets.dat". If the -p option is + specified, planets will not be listed. If the -w option is specified, + only wormhole locations will be listed. */ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number; + +struct galaxy_data galaxy; + +extern int num_stars, num_planets; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, n, star_index, total_planets, list_planets, usage_error, + type_count[10], num_gases, home_system, total_wormstars, + list_wormholes; + + struct star_data *star, *worm_star; + struct planet_data *planet, *home_planet; + + + /* Check for valid command line. */ + usage_error = FALSE; + list_planets = FALSE; + list_wormholes = FALSE; + if (argc == 2) + { + if (argv[1][0] == '-' && argv[1][1] == 'p') + list_planets = FALSE; + else if (argv[1][0] == '-' && argv[1][1] == 'w') + list_wormholes = TRUE; + else + usage_error = TRUE; + } + else + list_planets = TRUE; + + if (usage_error || argc > 2) + { + fprintf (stderr, "\n Usage: ListPlanets [-p | -w]\n"); + fprintf (stderr, "\tUse -p option to NOT list planets.\n"); + fprintf (stderr, "\tUse -w option to list only wormholes.\n\n"); + exit (-1); + } + + /* Get all the raw data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + + /* Initialize counts. */ + for (i = DWARF; i <= GIANT; i++) type_count[i] = 0; + total_planets = 0; + total_wormstars = 0; + + /* For each star, list info. */ + star = (struct star_data *) star_base; + planet = (struct planet_data *) planet_base; + for (star_index = 0; star_index < num_stars; star_index++) + { + if (! list_wormholes) + { + if (list_planets) + printf ("System #%d:\t", star_index + 1); + printf ("x = %d\ty = %d\tz = %d", star->x, star->y, star->z); + printf ("\tstellar type = %c%c%c", type_char[star->type], + color_char[star->color], size_char[star->size]); + if (list_planets) + printf ("\t%d planets.", star->num_planets); + printf ("\n"); + + if (star->num_planets == 0) + { + printf ("\tStar #%d went nova!", star_index + 1); + printf (" All planets were blown away!\n"); + } + } + + total_planets += star->num_planets; + type_count[star->type] += 1; + + if (star->worm_here) + { + ++total_wormstars; + if (list_planets) + printf ("!!! Natural wormhole from here to %d %d %d\n", + star->worm_x, star->worm_y, star->worm_z); + else if (list_wormholes) + { + printf ("Wormhole #%d: from %d %d %d to %d %d %d\n", + total_wormstars, star->x, star->y, star->z, + star->worm_x, star->worm_y, star->worm_z); + worm_star = (struct star_data *) star_base; + for (i = 0; i < num_stars; i++) + { + if (star->worm_x == worm_star->x + && star->worm_y == worm_star->y + && star->worm_z == worm_star->z) + { + worm_star->worm_here = FALSE; + break; + } + ++worm_star; + } + } + } + + home_system = FALSE; + home_planet = planet; + if (list_planets) /* Check if system has a home planet. */ + for (i = 1; i <= star->num_planets; i++) + { + if (home_planet->special == 1 || home_planet->special == 2) + { + home_system = TRUE; + break; + } + ++home_planet; + } + + if (list_planets) + for (i = 1; i <= star->num_planets; i++) + { + switch (planet->special) + { + case 0: printf (" "); break; + case 1: printf (" HOM "); break; /* Ideal home planet. */ + case 2: printf (" COL "); break; /* Ideal colony planet. */ + } + printf ("#%d dia=%3d g=%d.%02d tc=%2d pc=%2d md=%d.%02d", i, + planet->diameter, + planet->gravity/100, + planet->gravity%100, + planet->temperature_class, + planet->pressure_class, + planet->mining_difficulty/100, + planet->mining_difficulty%100); + + if (home_system) + print_LSN (planet, home_planet); + else + printf (" "); + + num_gases = 0; + for (n = 0; n < 4; n++) + { + if (planet->gas_percent[n] > 0) + { + if (num_gases > 0) printf (","); + printf ("%s(%d%%)", gas_string[planet->gas[n]], + planet->gas_percent[n]); + ++num_gases; + } + } + + if (num_gases == 0) printf ("No atmosphere"); + + printf ("\n"); + ++planet; + } + + if (list_planets) printf ("\n"); + + ++star; + } + + if (list_wormholes) goto done; + + /* Print summary. */ + printf ("\nThe galaxy has a radius of %d parsecs.\n", galaxy.radius); + printf ("It contains %d dwarf stars, %d degenerate stars, ", + type_count[DWARF], type_count[DEGENERATE]); + printf ("%d main sequence stars,\n and %d giant stars, ", + type_count[MAIN_SEQUENCE], type_count[GIANT]); + printf ("for a total of %d stars.\n", num_stars); + + if (! list_planets) goto done; + + printf ("The total number of planets in the galaxy is %d.\n", total_planets); + printf ("The total number of natural wormholes in the galaxy is %d.\n", + total_wormstars/2); + printf ("The galaxy was designed for %d species.\n", galaxy.d_num_species); + printf ("A total of %d species have been designated so far.\n\n", + galaxy.num_species); + +done: + + /* Internal test. */ + if (num_planets != total_planets) + { + fprintf (stderr, "\n\nWARNING! Program error! Internal inconsistency!\n\n"); + exit (-1); + } + + /* Clean up and exit. */ + exit (0); +} + + +print_LSN (planet, home_planet) + +struct planet_data *planet, *home_planet; + +{ + /* This routine provides an approximate LSN for a planet. It assumes + that oxygen is required and any gas that does not appear on the + home planet is poisonous. */ + + int i, j, k, ls_needed, poison; + + ls_needed = 0; + + j = planet->temperature_class - home_planet->temperature_class; + if (j < 0) j = -j; + ls_needed = 2 * j; /* Temperature class. */ + + j = planet->pressure_class - home_planet->pressure_class; + if (j < 0) j = -j; + ls_needed += 2 * j; /* Pressure class. */ + + /* Check gases. Assume oxygen is not present. */ + ls_needed += 2; + for (j = 0; j < 4; j++) /* Check gases on planet. */ + { + if (planet->gas[j] == 0) continue; + + if (planet->gas[j] == O2) ls_needed -= 2; + + poison = TRUE; + for (k = 0; k < 4; k++) /* Compare with home planet. */ + { + if (planet->gas[j] == home_planet->gas[k]) + { + poison = FALSE; + break; + } + } + if (poison) ls_needed += 2; + } + + printf ("%4d ", ls_needed); +} diff --git a/src/Locations.c b/src/Locations.c new file mode 100644 index 0000000..ee160f2 --- /dev/null +++ b/src/Locations.c @@ -0,0 +1,120 @@ + +/* This program will create the file locations.dat and will update the +economic efficiencies of all planets. These functions are also performed +by Finish.c. This program should be run before the strike phase or whenever +manual changes are made to the species data files that resulted in something +not being where it was or something being where it was not. It should also +be run if you run Finish on fewer than all species and decide to keep the +resulting planets.dat file. */ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number, species_index; +int test_mode, verbose_mode; + +struct galaxy_data galaxy; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern int num_locs, num_planets; + +extern struct sp_loc_data loc[MAX_LOCATIONS]; +extern struct planet_data *planet_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, nampla_index; + + long diff, total, *total_econ_base; + + + /* Check for options, if any. */ + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-t") == 0) test_mode = TRUE; + if (strcmp (argv[i], "-v") == 0) verbose_mode = TRUE; + } + + /* Get commonly used data. */ + get_galaxy_data (); + get_planet_data (); + get_species_data (); + + /* Allocate memory for array "total_econ_base". */ + total = (long) num_planets * sizeof (long); + total_econ_base = (long *) malloc (total); + if (total_econ_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for total_econ_base!\n\n"); + exit (-1); + } + + /* Initialize total econ base for each planet. */ + planet = planet_base; + for (i = 0; i < num_planets; i++) + { + total_econ_base[i] = 0; + + ++planet; + } + + /* Get total economic base for each planet from nampla data. */ + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + if (! data_in_memory[species_number - 1]) continue; + + data_modified[species_number - 1] = TRUE; + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + nampla = nampla_base + nampla_index; + + if (nampla->pn == 99) continue; + + if ((nampla->status & HOME_PLANET) == 0) + total_econ_base[nampla->planet_index] += + nampla->mi_base + nampla->ma_base; + } + } + + /* Update economic efficiencies of all planets. */ + planet = planet_base; + for (i = 0; i < num_planets; i++) + { + total = total_econ_base[i]; + diff = total - 2000; + + if (diff <= 0) + planet->econ_efficiency = 100; + else + planet->econ_efficiency = (100 * (diff/20 + 2000)) / total; + + ++planet; + } + + /* Create new locations array. */ + do_locations (); + + /* Clean up and exit. */ + save_location_data (); + save_planet_data (); + free_species_data (); + free (planet_base); + exit (0); +} diff --git a/src/MakeHomes.c b/src/MakeHomes.c new file mode 100644 index 0000000..33880e9 --- /dev/null +++ b/src/MakeHomes.c @@ -0,0 +1,473 @@ +/* This program will generate files HS3 through HS9, which will be used later + by the HomeSystem program to create home star systems. */ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int potential_home_system, species_number; + +struct galaxy_data galaxy; + +extern unsigned long last_random; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, earth_like, home_system_fd, num_planets; + + long n, num_bytes; + + char filename[32]; + + struct planet_data *planet_base, *planet, planets[9]; + + + planet_base = &planets[0]; + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + earth_like = TRUE; + for (num_planets = 3; num_planets < 10; num_planets++) + { + sprintf (filename, "HS%d\0", num_planets); + printf ("Now doing file '%s'...\n", filename); + + potential_home_system = FALSE; + + while (! potential_home_system) + generate_planets (planet_base, num_planets, earth_like); + + home_system_fd = creat (filename, 0600); + if (home_system_fd < 0) + { + fprintf (stderr, "\n\tCannot create file '%s'!\n\n", filename); + exit (-1); + } + + num_bytes = num_planets * sizeof (struct planet_data); + n = write (home_system_fd, planet_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\n\tCannot write home system data to file '%s'!\n\n", + filename); + exit (-1); + } + + close (home_system_fd); + } + + exit (0); +} + + + +/* Generate planets. */ + +int start_diameter[10] = {0, 5, 12, 13, 7, 20, 143, 121, 51, 49}; +int start_temp_class[10] = {0, 29, 27, 11, 9, 8, 6, 5, 5, 3}; + /* Values for the planets of Earth's solar system will be used + as starting values. Diameters are in thousands of kilometers. + The zeroth element of each array is a placeholder and is not + used. The fifth element corresponds to the asteroid belt, and + is pure fantasy on my part. I omitted Pluto because it is probably + a captured planet, rather than an original member of our solar + system. */ + +generate_planets (first_planet, num_planets, earth_like) + +struct planet_data *first_planet; + +int num_planets, earth_like; + +{ + int i, j, n, planet_number, dia, diameter[10], gas_giant, die_size, + density, grav, g[10], tc, temperature_class[10], pc, temp, + pressure_class[10], n_rolls, mining_dif, mining_difficulty[10], + gas[10][5], gas_percent[10][5], first_gas, num_gases_wanted, + num_gases_found, gas_quantity, total_percent, make_earth, + special[10], potential; + + char *cp; + + struct planet_data *home_planet, *current_planet; + + + /* Set flag to indicate if this star system requires an earth-like + planet. If so, we will zero this flag after we use it. */ + make_earth = earth_like; + + /* Main loop. Generate one planet at a time. */ + for (planet_number = 1; planet_number <= num_planets; planet_number++) + { + /* Start with diameters, temperature classes and pressure classes + based on the planets in Earth's solar system. */ + if (num_planets > 3) + { + i = (9 * planet_number)/num_planets; + dia = start_diameter[i]; + tc = start_temp_class[i]; + } + else + { + i = 2 * planet_number + 1; + dia = start_diameter[i]; + tc = start_temp_class[i]; + } + + /* Randomize the diameter. */ + die_size = dia/4; if (die_size < 2) die_size = 2; + for (i = 1; i <= 4; i++) + { + if (rnd(100) > 50) + dia = dia + rnd(die_size); + else + dia = dia - rnd(die_size); + } + + /* Minimum allowable diameter is 3,000 km. Note that the + maximum diameter we can generate is 283,000 km. */ + while (dia < 3) dia += rnd(4); + + diameter[planet_number] = dia; + + /* If diameter is greater than 40,000 km, assume the planet + is a gas giant. */ + gas_giant = (dia > 40); + + /* Density will depend on whether or not the planet is a gas giant. + Again ignoring Pluto, densities range from 0.7 to 1.6 times the + density of water for the gas giants, and from 3.9 to 5.5 for the + others. We will expand this range slightly and use 100 times the + actual density so that we can use integer arithmetic. */ + if (gas_giant) + density = 58 + rnd(56) + rnd(56); + /* Final values from 60 thru 170. */ + else + density = 368 + rnd(101) + rnd(101); + /* Final values from 370 thru 570. */ + + /* Gravitational acceleration is proportional to the mass divided + by the radius-squared. The radius is proportional to the + diameter, and the mass is proportional to the density times the + radius-cubed. The net result is that "g" is proportional to + the density times the diameter. Our value for "g" will be + a multiple of Earth gravity, and will be further multiplied + by 100 to allow us to use integer arithmetic. */ + grav = (density * diameter[planet_number]) / 72; + /* The factor 72 ensures that "g" will be 100 for + Earth (density=550 and diameter=13). */ + g[planet_number] = grav; + + /* Randomize the temperature class obtained earlier. */ + die_size = tc/4; if (die_size < 2) die_size = 2; + n_rolls = rnd(3) + rnd(3) + rnd(3); + for (i = 1; i <= n_rolls; i++) + { + if (rnd(100) > 50) + tc = tc + rnd(die_size); + else + tc = tc - rnd(die_size); + } + + if (gas_giant) + { + while (tc < 3) tc += rnd(2); + while (tc > 7) tc -= rnd(2); + } + else + { + while (tc < 1) tc += rnd(3); + while (tc > 30) tc -= rnd(3); + } + + /* Sometimes, planets close to the sun in star systems with less + than four planets are too cold. Warm them up a little. */ + if (num_planets < 4 && planet_number < 3) + { + while (tc < 12) tc += rnd(4); + } + + /* Make sure that planets farther from the sun are not warmer + than planets closer to the sun. */ + if (planet_number > 1) + { + if (temperature_class[planet_number-1] < tc) + tc = temperature_class[planet_number-1]; + } + + temperature_class[planet_number] = tc; + + /* Check if this planet should be earth-like. If so, discard all + of the above and replace with earth-like characteristics. */ + special[planet_number] = 0; + if (make_earth && (tc <= 11)) + { + make_earth = 0; /* Once only. */ + + /* Initialize 3rd & 4th gases in case they are not used below. */ + gas[planet_number][3] = 0; + gas_percent[planet_number][3] = 0; + gas[planet_number][4] = 0; + gas_percent[planet_number][4] = 0; + + diameter[planet_number] = 11 + rnd(3); + g[planet_number] = 93 + rnd(11) + rnd(11) + rnd(5); + temperature_class[planet_number] = 9 + rnd(3); + pressure_class[planet_number] = 8 + rnd(3); + mining_difficulty[planet_number] = 208 + rnd(11) + rnd(11); + special[planet_number] = 1; /* Maybe ideal home planet. */ + + i = 1; + total_percent = 0; + + if (rnd(3) == 1) /* Give it a shot of ammonia. */ + { + gas[planet_number][i] = NH3; + temp = rnd(30); + gas_percent[planet_number][i] = temp; + total_percent += temp; + ++i; + } + n = i++; /* Save index for nitrogen. */ + + if (rnd(3) == 1) /* Give it a shot of carbon dioxide. */ + { + gas[planet_number][i] = CO2; + temp = rnd(30); + gas_percent[planet_number][i] = temp; + total_percent += temp; + ++i; + } + + /* Now do oxygen. */ + gas[planet_number][i] = O2; + temp = rnd(20) + 10; + gas_percent[planet_number][i] = temp; + total_percent += temp; + + /* Give the rest to nitrogen. */ + gas[planet_number][n] = N2; + gas_percent[planet_number][n] = 100 - total_percent; + + continue; + } + + /* Pressure class depends primarily on gravity. Calculate + an approximate value and randomize it. */ + pc = g[planet_number]/10; + die_size = pc/4; if (die_size < 2) die_size = 2; + n_rolls = rnd(3) + rnd(3) + rnd(3); + for (i = 1; i <= n_rolls; i++) + { + if (rnd(100) > 50) + pc = pc + rnd(die_size); + else + pc = pc - rnd(die_size); + } + + if (gas_giant) + { + while (pc < 11) pc += rnd(3); + while (pc > 29) pc -= rnd(3); + } + else + { + while (pc < 0) pc += rnd(3); + while (pc > 12) pc -= rnd(3); + } + + if (grav < 10) pc = 0; + /* Planet's gravity is too low to retain an atmosphere. */ + if (tc < 2 || tc > 27) pc = 0; + /* Planets outside this temperature range have no atmosphere. */ + + pressure_class[planet_number] = pc; + + /* Generate gases, if any, in the atmosphere. */ + for (i = 1; i <= 4; i++) /* Initialize. */ + { + gas[planet_number][i] = 0; + gas_percent[planet_number][i] = 0; + } + if (pc == 0) goto done_gases; /* No atmosphere. */ + + /* Convert planet's temperature class to a value between 1 and 9. + We will use it as the start index into the list of 13 potential + gases. */ + first_gas = 100*tc/225; + if (first_gas < 1) first_gas = 1; + if (first_gas > 9) first_gas = 9; + + /* The following algorithm is something I tweaked until it + worked well. */ + num_gases_wanted = (rnd(4) + rnd(4))/2; + num_gases_found = 0; + gas_quantity = 0; + +get_gases: + for (i = first_gas; i <= first_gas + 4; i++) + { + if (num_gases_wanted == num_gases_found) break; + + if (i == HE) /* Treat Helium specially. */ + { + if (rnd(3) > 1) continue; /* Don't want too many He planets. */ + if (tc > 5) continue; /* Too hot for helium. */ + ++num_gases_found; + gas[planet_number][num_gases_found] = HE; + temp = rnd(20); + gas_percent[planet_number][num_gases_found] = temp; + gas_quantity += temp; + } + else /* Not Helium. */ + { + if (rnd(3) == 3) continue; + ++num_gases_found; + gas[planet_number][num_gases_found] = i; + if (i == O2) + temp = rnd(50); /* Oxygen is self-limiting. */ + else + temp = rnd(100); + gas_percent[planet_number][num_gases_found] = temp; + gas_quantity += temp; + } + } + + if (num_gases_found == 0) goto get_gases; /* Try again. */ + + /* Now convert gas quantities to percentages. */ + total_percent = 0; + for (i = 1; i <= num_gases_found; i++) + { + gas_percent[planet_number][i] = + 100 * gas_percent[planet_number][i] / gas_quantity; + total_percent += gas_percent[planet_number][i]; + } + + /* Give leftover to first gas. */ + gas_percent[planet_number][1] += 100 - total_percent; + + done_gases: + + /* Get mining difficulty. Basically, mining difficulty is + proportional to planetary diameter with randomization and an + occasional big surprise. Actual values will range between 0.30 + and 10.00. Again, the actual value will be multiplied by 100 + to allow use of integer arithmetic. */ + mining_dif = 0; + while (mining_dif < 30 || mining_dif > 1000) + mining_dif = (rnd(3) + rnd(3) + rnd(3) - rnd(4)) * rnd(dia) + + rnd(20) + rnd(20); + + mining_difficulty[planet_number] = mining_dif; + } + + /* Copy planet data to structure. */ + potential_home_system = FALSE; + current_planet = first_planet; + for (i = 1; i <= num_planets; i++) + { + /* Initialize all bytes of record to zero. */ + cp = (char *) current_planet; + for (j = 0; j < sizeof (struct planet_data); j++) + *cp++ = 0; + + current_planet->diameter = diameter[i]; + current_planet->gravity = g[i]; + current_planet->mining_difficulty = mining_difficulty[i]; + current_planet->temperature_class = temperature_class[i]; + current_planet->pressure_class = pressure_class[i]; + + current_planet->special = special[i]; + if (special[i] == 1) + { + home_planet = current_planet; + potential_home_system = TRUE; + } + + for (n = 0; n < 4; n++) + { + current_planet->gas[n] = gas[i][n+1]; + current_planet->gas_percent[n] = gas_percent[i][n+1]; + } + + ++current_planet; + } + + if (! potential_home_system) return; + + /* If this is a potential home system, make sure it passes certain + tests. */ + current_planet = first_planet; + potential = 0; + for (i = 1; i <= num_planets; i++) + { + n = LSN (current_planet, home_planet); + + potential += 20000L / + ((long) (n + 3) * (long) (50 + current_planet->mining_difficulty)); + + ++current_planet; + } + + if (potential > 53 && potential < 57) + ; + else + potential_home_system = FALSE; +} + + + +int LSN (current_planet, home_planet) + +struct planet_data *current_planet, *home_planet; + +{ + /* This routine provides an approximate LSN for a planet. It assumes + that oxygen is required and any gas that does not appear on the + home planet is poisonous. */ + + int i, j, k, ls_needed, poison; + + ls_needed = 0; + + j = current_planet->temperature_class - home_planet->temperature_class; + if (j < 0) j = -j; + ls_needed = 2 * j; /* Temperature class. */ + + j = current_planet->pressure_class - home_planet->pressure_class; + if (j < 0) j = -j; + ls_needed += 2 * j; /* Pressure class. */ + + /* Check gases. Assume oxygen is not present. */ + ls_needed += 2; + for (j = 0; j < 4; j++) /* Check gases on planet. */ + { + if (current_planet->gas[j] == 0) continue; + + if (current_planet->gas[j] == O2) ls_needed -= 2; + + poison = TRUE; + for (k = 0; k < 4; k++) /* Compare with home planet. */ + { + if (current_planet->gas[j] == home_planet->gas[k]) + { + poison = FALSE; + break; + } + } + if (poison) ls_needed += 2; + } + + return ls_needed; +} diff --git a/src/MapGalaxy.c b/src/MapGalaxy.c new file mode 100644 index 0000000..0899d9d --- /dev/null +++ b/src/MapGalaxy.c @@ -0,0 +1,183 @@ + +/* This program will create an ASCII map of the galaxy and write the result + to file "galaxy.map". It will paginate the output based on how many + columns your printer or display can handle. Pages are separated by + formfeed characters. If you do not like the results, you can always + edit the output file with any text editor. */ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int star_here[MAX_DIAMETER][MAX_DIAMETER]; + +struct galaxy_data galaxy; + +extern int num_stars; + +extern struct star_data *star_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, x, y, z, line, x_count, n_columns, x_increment, + page_count, page, left_x, galactic_diameter, star_index; + + FILE *outfile; + + struct star_data *star; + + + /* Check for valid command line. */ + if (argc != 1) + { + fprintf (stderr, "\n\tUsage: MapGalaxy\n\n"); + fprintf (stderr, "\tResults will be written to file galaxy.map\n\n"); + exit (-1); + } + + /* Get all the raw data. */ + get_galaxy_data (); + get_star_data (); + + galactic_diameter = 2 * galaxy.radius; + + /* Determine number of pages that will be needed to contain the + complete map. */ + printf ("\nHow many columns (eg. 80 or 132) can your printer or display handle? "); + fflush (stdout); + scanf ("%d", &n_columns); + + x_increment = (n_columns - 4) / 6; /* 4 columns for left margin + plus 6 per star. */ + page_count = (2 * galaxy.radius + x_increment - 1) / x_increment; + + printf ("\nI will generate %d page(s).\n\n", page_count); + + /* For each star, set corresponding element of star_here[] to index + into star array. */ + for (x = 0; x < galactic_diameter; x++) /* Initialize array. */ + for (y = 0; y < galactic_diameter; y++) + star_here[x][y] = -1; + + star = star_base; + for (star_index = 0; star_index < num_stars; star_index++) + { + x = star->x; + y = star->y; + star_here[x][y] = star_index; + ++star; + } + + /* Create output file. */ + outfile = fopen ("galaxy.map", "w"); + if (outfile == NULL) + { + fprintf (stderr, "\n\tCannot create file galaxy.map!\n"); + exit (-1); + } + + /* Outermost loop will count pages. */ + left_x = 0; + for (page = 1; page <= page_count; page++) + { + /* Next-to-outermost loop will control y-coordinates. */ + for (y = 2*galaxy.radius - 1; y >= 0; y--) + { + /* Next-to-innermost loop will count the 4 lines that make up + each star box. Fifth and sixth lines are generated only at + the very bottom of the page. */ + for (line = 1; line <= 6; line++) + { + x = left_x; + + /* Do left margin of first page. */ + if (x == 0 && page == 1) + { + switch (line) + { + case 1: fprintf (outfile, " -"); break; + case 2: fprintf (outfile, " |"); break; + case 3: fprintf (outfile, "%2d |", y); break; + case 4: if (n_columns < 100) fprintf (outfile, " |"); + break; + case 5: if (y == 0) fprintf (outfile, " Y -"); break; + case 6: if (y == 0) fprintf (outfile, " X "); break; + } + } + + /* Innermost loop will control x-coordinate. */ + for (x_count = 1; x_count <= x_increment; x_count++) + { + if (x == galactic_diameter) break; + + star_index = star_here[x][y]; + star = (struct star_data *) star_base; + if (star_index > 0) star += star_index; + + switch (line) + { + case 1: + fprintf (outfile, "------"); + break; + + case 2: + if (star_index >= 0) + { + z =star->z; + if (z < 10) + fprintf (outfile, "%3d |", z); + else + fprintf (outfile, "%4d |", z); + } + else + fprintf (outfile, " |"); + break; + + case 3: + if (star_index >= 0) + fprintf (outfile, " %c%c%c |", + type_char[star->type], + color_char[star->color], + size_char[star->size]); + else + fprintf (outfile, " |"); + break; + + case 4: + if (n_columns < 100) fprintf (outfile, " |"); + break; + + case 5: + if (y == 0) fprintf (outfile, "------"); + break; + + case 6: + if (y == 0) fprintf (outfile, " %2d ", x); + break; + } + + ++x; + } + + if ( (line < 4) || (line == 4 && n_columns < 100) ) + fprintf (outfile, "\n"); /* End of line. */ + + if (y == 0 && line == 5) fprintf (outfile, "\n"); + } + } + + fprintf (outfile, "\n\f"); /* Formfeed character. */ + left_x += x_increment; + } + + /* Clean up and exit. */ + fclose (outfile); + exit (0); +} diff --git a/src/Near.c b/src/Near.c new file mode 100644 index 0000000..44cb69e --- /dev/null +++ b/src/Near.c @@ -0,0 +1,241 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number; + +extern int ignore_field_distorters; + +extern FILE *log_file; +struct galaxy_data galaxy; +struct species_data *species; +struct nampla_data *nampla_base; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, species_index, species_printed, nampla_index, + ship_index, industry; + + long x, y, z, max_distance, max_distance_squared, + delta_x, delta_y, delta_z, distance_squared; + + char answer[256]; + + struct nampla_data *nampla; + struct ship_data *ship; + + + ignore_field_distorters = TRUE; + log_file = stdout; + + /* Check for valid command line. */ + if (argc == 2) + max_distance = (long) atoi (argv[1]); + else if (argc == 5) + { + x = (long) atoi (argv[1]); + y = (long) atoi (argv[2]); + z = (long) atoi (argv[3]); + max_distance = (long) atoi (argv[4]); + } + else + { + fprintf (stderr, "\n\tUsage: Near [x y z] distance\n\n"); + exit (-1); + } + + max_distance_squared = max_distance * max_distance; + + get_galaxy_data (); + get_star_data (); + get_planet_data (); + get_species_data (); + +again: + + if (argc == 2) + { + printf ("Enter x y z OR sn to scan for species n (-1 to quit): "); + fflush (stdout); + fgets (answer, sizeof (answer), stdin); + i = sscanf (answer, "%d", &x); + + if (i == 0) + { + i = sscanf (answer, "s%d", &species_number); + if (i == 1) + { + species_index = species_number - 1; + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + printf ("Scan for SP %s:\n", species->name); + + scan (x, y, z); + } + goto again; + } + + if (x < 0) goto done; + + sscanf (answer, "%d %d %d", &x, &y, &z); + } + + /* Display scan. */ + printf ("Ships and populated planets within %ld parsecs of %ld %ld %ld:\n", + max_distance, x, y, z); + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (! data_in_memory[species_index]) continue; + + species_number = species_index + 1; + species = &spec_data[species_index]; + + species_printed = FALSE; + + /* Set dest_x for all ships to zero. We will use this to prevent + multiple listings of a ship. */ + ship = ship_data[species_index]; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship->dest_x = 0; + ++ship; + } + + /* Check all namplas for this species. */ + nampla = namp_data[species_index] - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if ((nampla->status & POPULATED) == 0) continue; + + delta_x = x - nampla->x; + delta_y = y - nampla->y; + delta_z = z - nampla->z; + distance_squared = (delta_x * delta_x) + (delta_y * delta_y) + + (delta_z * delta_z); + + if (distance_squared > max_distance_squared) continue; + + if (! species_printed) + { + printf (" Species #%d, SP %s:\n", species_number, + species->name); + species_printed = TRUE; + } + + printf (" %2d %2d %2d #%d", nampla->x, nampla->y, nampla->z, + nampla->pn); + + if (nampla->status & HOME_PLANET) + printf (" Home planet"); + else if (nampla->status & MINING_COLONY) + printf (" Mining colony"); + else if (nampla->status & RESORT_COLONY) + printf (" Resort colony"); + else + printf (" Normal colony"); + + printf (" PL %s, ", nampla->name); + + industry = nampla->mi_base + nampla->ma_base; + printf ("EB = %d.%d", industry/10, industry%10); + + printf (", %d Yrds", nampla->shipyards); + + for (i = 0; i < MAX_ITEMS; i++) + { + if (nampla->item_quantity[i] > 0) + printf (", %d %s", nampla->item_quantity[i], item_abbr[i]); + } + + if (nampla->hidden) printf (", HIDING!"); + + printf ("\n"); + + /* List ships at this planet. */ + ship = ship_data[species_index] - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->dest_x != 0) continue; /* Already listed. */ + + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + + printf (" %s", ship_name (ship)); + + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + printf (", %d %s", ship->item_quantity[i], + item_abbr[i]); + } + + printf ("\n"); + + ship->dest_x = 99; /* Do not list this ship again. */ + } + } + + ship = ship_data[species_index] - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) continue; + + if (ship->dest_x != 0) continue; /* Already listed above. */ + + delta_x = x - ship->x; + delta_y = y - ship->y; + delta_z = z - ship->z; + distance_squared = (delta_x * delta_x) + (delta_y * delta_y) + + (delta_z * delta_z); + + if (distance_squared > max_distance_squared) continue; + + if (! species_printed) + { + printf (" Species #%d, SP %s:\n", species_number, + species->name); + species_printed = TRUE; + } + + printf (" %2d %2d %2d", ship->x, ship->y, ship->z); + + printf (" %s", ship_name(ship)); + + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + printf (", %d %s", ship->item_quantity[i], + item_abbr[i]); + } + + printf ("\n"); + } + } + + if (argc == 2) goto again; + +done: + + /* Clean up and exit. */ + free_species_data (); + exit (0); +} diff --git a/src/NewGalaxy.c b/src/NewGalaxy.c new file mode 100644 index 0000000..08dc32b --- /dev/null +++ b/src/NewGalaxy.c @@ -0,0 +1,411 @@ +/* This program will generate a completely new galaxy and write the results + to files "galaxy.dat", "stars.dat" and "planets.dat". */ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number; + +struct galaxy_data galaxy; + +extern unsigned long last_random; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int d, i, n, galaxy_file, star_file, planet_file, using_defaults; + + int x, y, z, real_x, real_y, real_z, desired_num_stars, + galactic_diameter, sq_distance_from_center; + + int st_index, pl_index, star_type, star_color, star_size, + d_num_species, star_num_planets; + + int num_stars, galactic_radius, num_planets, max_planets, + num_wormholes; + + long volume, l_radius, chance_of_star, num_bytes, star_data_size, + planet_data_size, dx, dy, dz, distance_squared; + + char *cp, star_here[MAX_DIAMETER][MAX_DIAMETER]; + + struct star_data *current_star, *star_base, *star, *worm_star; + struct planet_data *planet_base, *planet; + + + /* Check for valid command line. */ + if (argc == 1) + using_defaults = FALSE; + else if (argc == 2 && argv[1][0] != '?') + { + d_num_species = atoi (argv[1]); + using_defaults = TRUE; + } + else + { + fprintf (stderr, "\n Usage: NewGalaxy [num_species]\n\n"); + fprintf (stderr, " This program will create files 'galaxy.dat', 'stars.dat' and 'planets.dat'.\n"); + fprintf (stderr, " If num_species is given, then defaults will be used for everything else.\n\n"); + exit (0); + } + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get number of species. */ + again1: + if (! using_defaults) + { + printf ("\nHow many species will be in the game? "); fflush (stdout); + scanf ("%d", &d_num_species); + } + if (d_num_species < MIN_SPECIES || d_num_species > MAX_SPECIES) + { + printf ("\n A game must have between %d and %d species, inclusive. Try again.\n", + MIN_SPECIES, MAX_SPECIES); + using_defaults = FALSE; + goto again1; + } + + /* Get approximate number of star systems to generate. */ + n = (d_num_species * STANDARD_NUMBER_OF_STAR_SYSTEMS) + / STANDARD_NUMBER_OF_SPECIES; + again2: + if (using_defaults) + { + printf ("For %d species, there should be about %d stars.\n", + d_num_species, n); + desired_num_stars = n; + } + else + { + printf ("\nFor %d species, a game needs about %d star systems.\n", + d_num_species, n); + printf ("Approximately how many star systems do you want me to generate? "); + fflush (stdout); + scanf ("%d", &desired_num_stars); + } + if (desired_num_stars < MIN_STARS || desired_num_stars > MAX_STARS) + { + printf ("\n A game must have between %d and %d star systems, inclusive. Try again.\n", + MIN_STARS, MAX_STARS); + using_defaults = FALSE; + goto again2; + } + + /* Get size of galaxy to generate. Use long values to prevent loss of + data by compilers that use 16-bit ints. */ + volume = (long) desired_num_stars + * (long) STANDARD_GALACTIC_RADIUS + * (long) STANDARD_GALACTIC_RADIUS + * (long) STANDARD_GALACTIC_RADIUS + / (long) STANDARD_NUMBER_OF_STAR_SYSTEMS; + l_radius = 2L; + while (l_radius * l_radius * l_radius < volume) ++l_radius; + again3: + galactic_radius = l_radius; + if (! using_defaults) + { + printf ("\nFor %d stars, the galaxy should have a radius of about %d parsecs.\n", + desired_num_stars, galactic_radius); + printf ("What radius (in parsecs) do you want the galaxy to have? "); + fflush (stdout); + scanf ("%d", &galactic_radius); + } + if (galactic_radius < MIN_RADIUS || galactic_radius > MAX_RADIUS) + { + printf ("\n Radius must be between %d and %d parsecs, inclusive. Try again.\n", + MIN_RADIUS, MAX_RADIUS); + using_defaults = FALSE; + goto again3; + } + galactic_diameter = 2 * galactic_radius; + + /* Get the number of cubic parsecs within a sphere with a radius of + galactic_radius parsecs. Again, use long values to prevent loss + of data by compilers that use 16-bit ints. */ + volume = (4L * 314L * (long) galactic_radius + * (long) galactic_radius + * (long) galactic_radius) + / 300L; + + /* The probability of a star system existing at any particular + set of x,y,z coordinates is one in chance_of_star. */ + chance_of_star = volume / (long) desired_num_stars; + if (chance_of_star < 50) + { + printf ("\n Galactic radius is too small for %d stars. Please try again.\n\n", + desired_num_stars); + goto again1; + } + if (chance_of_star > 3200) + { + printf ("\n Galactic radius is too large for %d stars. Please try again.\n\n", + desired_num_stars); + goto again1; + } + + /* Initialize star location data. */ + for (x = 0; x < galactic_diameter; x++) + for (y = 0; y < galactic_diameter; y++) + star_here[x][y] = -1; + + /* Get locations of stars. */ + num_stars = 0; + while (num_stars < desired_num_stars) + { + x = rnd (galactic_diameter) - 1; + y = rnd (galactic_diameter) - 1; + z = rnd (galactic_diameter) - 1; + + real_x = x - galactic_radius; + real_y = y - galactic_radius; + real_z = z - galactic_radius; + + sq_distance_from_center = + (real_x * real_x) + (real_y * real_y) + (real_z * real_z); + if (sq_distance_from_center >= galactic_radius*galactic_radius) + continue; + + /* Coordinate is within the galactic boundary. */ + if (star_here[x][y] < 0) + { + star_here[x][y] = z; /* z-coordinate. */ + ++num_stars; + if (num_stars == MAX_STARS) break; + } + } + + /* Create output file for galaxy. */ + galaxy_file = creat ("galaxy.dat", 0600); + if (galaxy_file < 0) + { + fprintf (stderr, "\n Cannot create file galaxy.dat!\n"); + exit (-1); + } + + galaxy.d_num_species = d_num_species; + galaxy.num_species = 0; + galaxy.radius = galactic_radius; + galaxy.turn_number = 0; + + num_bytes = write (galaxy_file, &galaxy, sizeof (struct galaxy_data)); + if (num_bytes != sizeof (struct galaxy_data)) + { + fprintf (stderr, "\n\tCannot write data to file 'galaxy.dat'!\n\n"); + exit (-1); + } + + close (galaxy_file); + + /* Allocate enough memory for star and planet data. */ + star_data_size = (long) num_stars * (long) sizeof(struct star_data); + star_base = (struct star_data *) malloc (star_data_size); + if (star_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for star data!\n\n"); + exit (-1); + } + + max_planets = 9 * num_stars; /* Maximum number possible. */ + planet_data_size = (long) max_planets * (long) sizeof(struct planet_data); + planet_base = (struct planet_data *) malloc (planet_data_size); + if (planet_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for planet data!\n\n"); + exit (-1); + } + + fprintf (stdout, "\nGenerating star number "); fflush (stdout); + + st_index = 0; + pl_index = 0; + star = star_base; + planet = planet_base; + for (x = 0; x < galactic_diameter; x++) + for (y = 0; y < galactic_diameter; y++) + { + if (star_here[x][y] >= 0) + { + /* Initialize all bytes of record to zero. */ + cp = (char *) star; + for (i = 0; i < sizeof (struct star_data); i++) + *cp++ = 0; + + /* Set coordinates. */ + star->x = x; + star->y = y; + star->z = star_here[x][y]; + + /* Determine type of star. Make MAIN_SEQUENCE the most common + star type. */ + star_type = rnd(GIANT+6); + if (star_type > GIANT) star_type = MAIN_SEQUENCE; + star->type = star_type; + + /* Color and size of star are totally random. */ + star_color = rnd(RED); + star->color = star_color; + star_size = rnd(10) - 1; + star->size = star_size; + + /* Determine the number of planets in orbit around the star. + The algorithm is something I tweaked until I liked it. + It's weird, but it works. */ + d = RED + 2 - star_color; + /* Size of die. Big stars (blue, blue-white) roll bigger + dice. Smaller stars (orange, red) roll smaller dice. */ + n = star_type; if (n > 2) n -= 1; + /* Number of rolls: dwarves have 1 roll, degenerates and + main sequence stars have 2 rolls, and giants have 3 rolls. */ + star_num_planets = -2; + for (i=1; i<=n; i++) star_num_planets += rnd(d); + while (star_num_planets > 9) /* Trim down if too many. */ + star_num_planets -= rnd(3); + if (star_num_planets < 1) star_num_planets = 1; + star->num_planets = star_num_planets; + + /* Determine pl_index of first planet in file "planets.dat". */ + star->planet_index = pl_index; + + /* Generate planets and write to file "planets.dat". */ + current_star = star; + generate_planets (planet, star_num_planets); + + star->home_system = FALSE; + star->worm_here = FALSE; + + /* Update pointers and indices. */ + pl_index += star_num_planets; + planet += star_num_planets; + ++st_index; + ++star; + + if (st_index % 10 == 0) + fprintf (stdout, "\b\b\b\b%4d", st_index); fflush (stdout); + } + } + + fprintf (stdout, "\b\b\b\b%4d\n", st_index); + + /* Allocate natural wormholes. */ + num_wormholes = 0; + star = star_base - 1; + for (i = 0; i < num_stars; i++) + { + ++star; + + if (star->home_system) continue; + if (star->worm_here) continue; + + if (rnd(100) < 92) continue; + + /* There is a wormhole here. Get coordinates of other end. */ + while (TRUE) + { + n = rnd(num_stars); + worm_star = star_base + n - 1; + if (worm_star == star) continue; + if (worm_star->home_system) continue; + if (worm_star->worm_here) continue; + + break; + } + + /* Eliminate wormholes less than 20 parsecs in length. */ + dx = (long) star->x - (long) worm_star->x; + dy = (long) star->y - (long) worm_star->y; + dz = (long) star->z - (long) worm_star->z; + distance_squared = (dx * dx) + (dy * dy) + (dz * dz); + if (distance_squared < 400) continue; + + star->worm_here = TRUE; + star->worm_x = worm_star->x; + star->worm_y = worm_star->y; + star->worm_z = worm_star->z; + + worm_star->worm_here = TRUE; + worm_star->worm_x = star->x; + worm_star->worm_y = star->y; + worm_star->worm_z = star->z; + + ++num_wormholes; + } + + /* Create output file for stars. */ + star_file = creat ("stars.dat", 0600); + if (star_file < 0) + { + fprintf (stderr, "\n Cannot create file stars.dat!\n"); + exit (-1); + } + + num_bytes = write (star_file, &num_stars, sizeof(num_stars)); + if (num_bytes != sizeof(num_stars)) + { + fprintf (stderr, "\n Cannot write star count to file stars.dat!\n"); + exit (-1); + } + + /* Write the result to the file "stars.dat". */ + num_bytes = write (star_file, star_base, num_stars * sizeof(struct star_data)); + if (num_bytes != num_stars * sizeof(struct star_data)) + { + fprintf (stderr, "\n Cannot write star data to file stars.dat!\n"); + exit (-1); + } + + close (star_file); + + num_planets = pl_index; + printf ("\nThis galaxy contains a total of %d stars and ", num_stars); + printf ("%d planets.\n", num_planets); + printf (" The galaxy contains %d natural wormholes.\n\n", num_wormholes); + + if (st_index != num_stars) + fprintf (stderr, "\n Internal consistency check #1 failed!!!\n\n"); + + /* Create output file for planets. */ + planet_file = creat ("planets.dat", 0600); + if (planet_file < 0) + { + fprintf (stderr, "\n Cannot create file planets.dat!\n"); + exit (-1); + } + + /* Write planet data to file "planets.dat". */ + num_bytes = write (planet_file, &num_planets, sizeof(num_planets)); + if (num_bytes != sizeof(num_planets)) + { + fprintf (stderr, "\n Cannot write number of planets to file planets.dat!\n"); + exit (-1); + } + + planet = planet_base; + for (i = 0; i < num_planets; i++) + { + num_bytes = write (planet_file, planet, sizeof(struct planet_data)); + if (num_bytes != sizeof(struct planet_data)) + { + fprintf (stderr, "\n Cannot write planet data to file planets.dat!\n"); + exit (-1); + } + ++planet; + } + + close (planet_file); + + free (star_base); + free (planet_base); + + exit (0); +} diff --git a/src/NoOrders.c b/src/NoOrders.c new file mode 100644 index 0000000..998a24d --- /dev/null +++ b/src/NoOrders.c @@ -0,0 +1,642 @@ + +/* This program will generate default orders for a species if no explicit + orders have been provided. */ + +#define THIS_IS_MAIN + +#include "fh.h" + + +struct galaxy_data galaxy; +struct planet_data *planet, *home_planet; +struct species_data *species; +struct nampla_data *nampla_base; +struct ship_data *ship_base; + +int x, y, z, species_number, species_index; + +FILE *orders_file; + +extern int num_locs, truncate_name, num_stars; +extern unsigned long last_random; +extern struct sp_loc_data loc[MAX_LOCATIONS]; +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, k, ship_index, locations_fd, my_loc_index, + nampla_index, its_loc_index, tonnage, found, alien_number, + alien_index, array_index, bit_number, ls_needed, + production_penalty; + + char filename[32], *random_name(), message_line[132]; + + long n, nn, raw_material_units, production_capacity, balance, + current_base, CUs_needed, IUs_needed, AUs_needed, EUs, + bit_mask; + + FILE *message_file, *log_file; + + struct species_data *alien; + struct nampla_data *nampla, *home_nampla, *temp_nampla; + struct ship_data *ship; + struct sp_loc_data *locations_base, *my_loc, *its_loc; + + + /* Check for valid command line. */ + if (argc != 1) + { + fprintf (stderr, "\n\tUsage: NoOrders\n\n"); + exit (0); + } + + /* Seed random number generator. */ + last_random = time(NULL); + j = 907; + for (i = 0; i < j; i++) rnd(100); + + /* Get all necessary data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + get_species_data (); + get_location_data (); + + truncate_name = TRUE; + + /* Major loop. Check each species in the game. */ + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + species_index = species_number - 1; + + /* Check if this species is still in the game. */ + if (! data_in_memory[species_index]) continue; + + /* Check if we have orders. */ + sprintf (filename, "sp%02d.ord\0", species_number); + i = open (filename, 0); + if (i >= 0) + { + close (i); + continue; + } + + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + ship_base = ship_data[species_index]; + home_nampla = nampla_base; + home_planet = planet_base + (int) home_nampla->planet_index; + + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + ship->special = 0; + } + + /* Print message for gamemaster. */ + printf ("Generating orders for species #%02d, SP %s...\n", + species_number, species->name); + + /* Open message file. */ + sprintf (filename, "noorders.txt\0"); + message_file = fopen (filename, "r"); + if (message_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + + /* Open log file. */ + sprintf (filename, "sp%02d.log", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + + /* Copy message to log file. */ + while (fgets(message_line, 131, message_file) != NULL) + fputs (message_line, log_file); + + fclose (message_file); + fclose (log_file); + + /* Open orders file for writing. */ + sprintf (filename, "sp%02d.ord", species_number); + orders_file = fopen (filename, "w"); + if (orders_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for writing!\n\n", filename); + exit (-1); + } + + /* Issue PRE-DEPARTURE orders. */ + fprintf (orders_file, "START PRE-DEPARTURE\n"); + fprintf (orders_file, "; Place pre-departure orders here.\n\n"); + + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + nampla = nampla_base + nampla_index; + if (nampla->pn == 99) continue; + + /* Generate auto-installs for colonies that were loaded via + the DEVELOP command. */ + if (nampla->auto_IUs) + fprintf (orders_file, "\tInstall\t%d IU\tPL %s\n", + nampla->auto_IUs, nampla->name); + if (nampla->auto_AUs) + fprintf (orders_file, "\tInstall\t%d AU\tPL %s\n", + nampla->auto_AUs, nampla->name); + if (nampla->auto_IUs || nampla->auto_AUs) + fprintf (orders_file, "\n"); + + nampla->item_quantity[CU] -= nampla->auto_IUs + nampla->auto_AUs; + + /* Generate auto UNLOAD orders for transports at this nampla. */ + for (j = 0; j < species->num_ships; j++) + { + ship = ship_base + j; + if (ship->pn == 99) continue; + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + if (ship->class != TR) continue; + if (ship->item_quantity[CU] < 1) continue; + + /* New colonies will never be started automatically unless + ship was loaded via a DEVELOP order. */ + if (ship->loading_point != 0) + { + /* Check if transport is at specified unloading point. */ + n = ship->unloading_point; + if (n == nampla_index + || (n == 9999 && nampla_index == 0)) + goto unload_ship; + } + + if ((nampla->status & POPULATED) == 0) continue; + + if ((nampla->mi_base + nampla->ma_base) >= 2000) continue; + + if (nampla->x == nampla_base->x + && nampla->y == nampla_base->y + && nampla->z == nampla_base->z) continue; /* Home sector. */ + +unload_ship: + + n = ship->loading_point; + if (n == 9999) n = 0; /* Home planet. */ + if (n == nampla_index) + continue; /* Ship was just loaded here. */ + + fprintf (orders_file, "\tUnload\tTR%d%s %s\n\n", ship->tonnage, + ship_type[ship->type], ship->name); + + nampla->item_quantity[CU] = 0; + + ship->special = ship->loading_point; + n = nampla - nampla_base; + if (n == 0) n = 9999; + ship->unloading_point = n; + } + + if (nampla->status & HOME_PLANET) continue; + if (nampla->item_quantity[CU] == 0) continue; + if (nampla->item_quantity[IU] == 0 + && nampla->item_quantity[AU] == 0) continue; + + if (nampla->item_quantity[IU] > 0) + fprintf (orders_file, "\tInstall\t0 IU\tPL %s\n", nampla->name); + if (nampla->item_quantity[AU] > 0) + fprintf (orders_file, "\tInstall\t0 AU\tPL %s\n\n", nampla->name); + } + + fprintf (orders_file, "END\n\n"); + + fprintf (orders_file, "START JUMPS\n"); + fprintf (orders_file, "; Place jump orders here.\n\n"); + + /* Initialize to make sure ships are not given more than one JUMP order. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + ship->just_jumped = FALSE; + } + + /* Generate auto-jumps for ships that were loaded via the DEVELOP + command or which were UNLOADed because of the AUTO command. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + if (ship->pn == 99) continue; + if (ship->just_jumped) continue; + + j = ship->special; + if (j) + { + if (j == 9999) j = 0; /* Home planet. */ + temp_nampla = nampla_base + j; + + fprintf (orders_file, "\tJump\t%s, PL %s\t; ", ship_name (ship), + temp_nampla->name); + + print_mishap_chance (ship, temp_nampla->x, temp_nampla->y, + temp_nampla->z); + + fprintf (orders_file, "\n\n"); + + ship->just_jumped = TRUE; + + continue; + } + + n = ship->unloading_point; + if (n) + { + if (n == 9999) n = 0; /* Home planet. */ + + temp_nampla = nampla_base + n; + + if (temp_nampla->x == ship->x && temp_nampla->y == ship->y + && temp_nampla->z == ship->z) continue; + + fprintf (orders_file, "\tJump\t%s, PL %s\t; ", ship_name (ship), + temp_nampla->name); + + print_mishap_chance (ship, temp_nampla->x, temp_nampla->y, + temp_nampla->z); + + fprintf (orders_file, "\n\n"); + + ship->just_jumped = TRUE; + } + } + + /* Generate JUMP orders for all TR1s. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + if (ship->status == UNDER_CONSTRUCTION) continue; + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + if (ship->just_jumped) continue; + + if (ship->class == TR && ship->tonnage == 1 + && ship->type == FTL) + { + fprintf (orders_file, "\tJump\tTR1 %s, ", ship->name); + closest_unvisited_star (ship); + fprintf (orders_file, + "\n\t\t\t; Age %d, now at %d %d %d, ", + ship->age, ship->x, ship->y, ship->z); + + print_mishap_chance (ship, x, y, z); + + ship->dest_x = x; + ship->dest_y = y; + ship->dest_z = z; + + fprintf (orders_file, "\n\n"); + + ship->just_jumped = TRUE; + } + } + + fprintf (orders_file, "END\n\n"); + + fprintf (orders_file, "START PRODUCTION\n"); + + /* Generate a PRODUCTION order for each planet that can produce. */ + for (nampla_index = species->num_namplas - 1; nampla_index >= 0; + nampla_index--) + { + nampla = nampla_base + nampla_index; + if (nampla->pn == 99) continue; + + if (nampla->mi_base == 0 && (nampla->status & RESORT_COLONY) == 0) continue; + if (nampla->ma_base == 0 && (nampla->status & MINING_COLONY) == 0) continue; + + fprintf (orders_file, " PRODUCTION PL %s\n", nampla->name); + + if (nampla->status & MINING_COLONY) + { + fprintf (orders_file, + " ; The above PRODUCTION order is required for this mining colony, even\n"); + fprintf (orders_file, + " ; if no other production orders are given for it.\n"); + } + else if (nampla->status & RESORT_COLONY) + { + fprintf (orders_file, + " ; The above PRODUCTION order is required for this resort colony, even\n"); + fprintf (orders_file, + " ; though no other production orders can be given for it.\n"); + } + else + { + fprintf (orders_file, + " ; Place production orders here for planet %s.\n\n", + nampla->name); + } + + /* Build IUs and AUs for incoming ships with CUs. */ + if (nampla->IUs_needed) + fprintf (orders_file, "\tBuild\t%d IU\n", nampla->IUs_needed); + if (nampla->AUs_needed) + fprintf (orders_file, "\tBuild\t%d AU\n", nampla->AUs_needed); + if (nampla->IUs_needed || nampla->AUs_needed) + fprintf (orders_file, "\n"); + + if (nampla->status & MINING_COLONY) continue; + if (nampla->status & RESORT_COLONY) continue; + + /* See if there are any RMs to recycle. */ + n = nampla->special / 5; + if (n > 0) + fprintf (orders_file, "\tRecycle\t%d RM\n\n", 5*n); + + /* Generate DEVELOP commands for ships arriving here because of + AUTO command. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + + k = ship->special; + if (k == 0) continue; + if (k == 9999) k = 0; /* Home planet. */ + + if (nampla != nampla_base + k) continue; + + k = ship->unloading_point; + if (k == 9999) k = 0; + temp_nampla = nampla_base + k; + + fprintf (orders_file, "\tDevelop\tPL %s, TR%d%s %s\n\n", + temp_nampla->name, ship->tonnage, ship_type[ship->type], + ship->name); + } + + /* Give orders to continue construction of unfinished ships and + starbases. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (orders_file, + "\tContinue\t%s, %d\t; Left to pay = %d\n\n", + ship_name (ship), ship->remaining_cost, + ship->remaining_cost); + + continue; + } + + if (ship->type != STARBASE) continue; + + j = (species->tech_level[MA] / 2) - ship->tonnage; + if (j < 1) continue; + + fprintf (orders_file, + "\tContinue\tBAS %s, %d\t; Current tonnage = %s\n\n", + ship->name, 100 * j, commas (10000 * (long) ship->tonnage)); + } + + /* Generate DEVELOP command if this is a colony with an + economic base less than 200. */ + n = nampla->mi_base + nampla->ma_base + nampla->IUs_needed + + nampla->AUs_needed; + if ((nampla->status & COLONY) && n < 2000 + && nampla->pop_units > 0) + { + if (nampla->pop_units > (2000L-n)) + nn = 2000L-n; + else + nn = nampla->pop_units; + + fprintf (orders_file, "\tDevelop\t%ld\n\n", + 2L * nn); + + nampla->IUs_needed += nn; + } + + /* For home planets and any colonies that have an economic base of + at least 200, check if there are other colonized planets in + the same sector that are not self-sufficient. If so, DEVELOP + them. */ + if (n >= 2000 || (nampla->status & HOME_PLANET)) + { + for (i = 1; i < species->num_namplas; i++) /* Skip HP. */ + { + if (i == nampla_index) continue; + + temp_nampla = nampla_base + i; + + if (temp_nampla->pn == 99) continue; + if (temp_nampla->x != nampla->x) continue; + if (temp_nampla->y != nampla->y) continue; + if (temp_nampla->z != nampla->z) continue; + + n = temp_nampla->mi_base + temp_nampla->ma_base + + temp_nampla->IUs_needed + temp_nampla->AUs_needed; + + if (n == 0) continue; + + nn = temp_nampla->item_quantity[IU] + + temp_nampla->item_quantity[AU]; + if (nn > temp_nampla->item_quantity[CU]) + nn = temp_nampla->item_quantity[CU]; + n += nn; + if (n >= 2000L) continue; + nn = 2000L - n; + + if (nn > nampla->pop_units) nn = nampla->pop_units; + + fprintf (orders_file, "\tDevelop\t%ld\tPL %s\n\n", + 2L * nn, temp_nampla->name); + + temp_nampla->AUs_needed += nn; + } + } + } + + fprintf (orders_file, "END\n\n"); + + fprintf (orders_file, "START POST-ARRIVAL\n"); + fprintf (orders_file, "; Place post-arrival orders here.\n\n"); + + /* Generate an AUTO command. */ + fprintf (orders_file, "\tAuto\n\n"); + + /* Generate SCAN orders for all TR1s in sectors that current species + does not inhabit. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + if (ship->pn == 99) continue; + if (ship->status == UNDER_CONSTRUCTION) continue; + if (ship->class != TR) continue; + if (ship->tonnage != 1) continue; + if (ship->type != FTL) continue; + if (ship->dest_x == -1) continue; /* Not jumping anywhere. */ + + found = FALSE; + for (j = 1; j < species->num_namplas; j++) /* Skip home sector. */ + { + nampla = nampla_base + j; + if (nampla->pn == 99) continue; + if (nampla->x != ship->dest_x) continue; + if (nampla->y != ship->dest_y) continue; + if (nampla->z != ship->dest_z) continue; + + if (nampla->status & POPULATED) + { + found = TRUE; + break; + } + } + if (! found) fprintf (orders_file, "\tScan\tTR1 %s\n", ship->name); + } + + fprintf (orders_file, "END\n\n"); + + /* Clean up for this species. */ + fclose (orders_file); + } + + /* Clean up and exit. */ + free_species_data (); + exit (0); +} + + +print_mishap_chance (ship, destx, desty, destz) + +struct ship_data *ship; +int destx, desty, destz; + +{ + int mishap_GV, mishap_age; + + long x, y, z, mishap_chance, success_chance; + + + if (destx == -1) + { + fprintf (orders_file, "Mishap chance = ???"); + return; + } + + mishap_GV = species->tech_level[GV]; + mishap_age = ship->age; + + x = destx; + y = desty; + z = destz; + mishap_chance = ( 100 * ( + ((x - ship->x) * (x - ship->x)) + + ((y - ship->y) * (y - ship->y)) + + ((z - ship->z) * (z - ship->z)) + ) ) / mishap_GV; + + if (mishap_age > 0 && mishap_chance < 10000) + { + success_chance = 10000L - mishap_chance; + success_chance -= (2L * (long) mishap_age * success_chance)/100L; + mishap_chance = 10000L - success_chance; + } + + if (mishap_chance > 10000) mishap_chance = 10000; + + fprintf (orders_file, "mishap chance = %ld.%02ld%%", + mishap_chance/100L, mishap_chance%100L); +} + + + +closest_unvisited_star (ship) + +struct ship_data *ship; + +{ + int i, found, species_array_index, species_bit_number; + + long shx, shy, shz, stx, sty, stz, closest_distance, temp_distance, + species_bit_mask; + + struct star_data *star, *closest_star; + + + /* Get array index and bit mask. */ + species_array_index = (species_number - 1) / 32; + species_bit_number = (species_number - 1) % 32; + species_bit_mask = 1 << species_bit_number; + + shx = ship->x; + shy = ship->y; + shz = ship->z; + + x = -1; + closest_distance = 999999; + + found = FALSE; + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + /* Check if bit is already set. */ + if (star->visited_by[species_array_index] & species_bit_mask) continue; + + stx = star->x; + sty = star->y; + stz = star->z; + + temp_distance = + ((shx - stx) * (shx - stx)) + + ((shy - sty) * (shy - sty)) + + ((shz - stz) * (shz - stz)); + + if (temp_distance < closest_distance) + { + x = stx; + y = sty; + z = stz; + closest_distance = temp_distance; + closest_star = star; + found = TRUE; + } + } + + if (found) + { + fprintf (orders_file, "%d %d %d", x, y, z); + closest_star->visited_by[species_array_index] |= species_bit_mask; + /* So that we don't send more than one ship to the same place. */ + } + else + fprintf (orders_file, "???"); + + return; +} diff --git a/src/PostArrival.c b/src/PostArrival.c new file mode 100644 index 0000000..40462fb --- /dev/null +++ b/src/PostArrival.c @@ -0,0 +1,395 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int post_arrival_phase = TRUE; + +int x, y, z, pn, nampla_index, ship_index, first_pass, species_number, + species_index; + +int verbose_mode, test_mode; + +extern int star_data_modified, planet_data_modified; +extern struct star_data *star_base; +extern struct planet_data *planet_base; + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + + +extern int end_of_file, truncate_name, log_stdout, + ignore_field_distorters, just_opened_file; +extern char input_line[256], *input_line_pointer; +extern FILE *input_file, *log_file; +extern unsigned long last_random; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, found, num_species, sp_num[MAX_SPECIES], sp_index, + command, do_all_species; + + char filename[32], keyword[4]; + + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get commonly used data. */ + get_galaxy_data (); + get_transaction_data (); + + ignore_field_distorters = TRUE; + + /* Check arguments. If an argument is -p, then do two passes. In the + first pass, display results and prompt the GM, allowing him to + abort if necessary before saving results to disk. All other + arguments must be species numbers. If no species numbers are + specified, then do all species. */ + num_species = 0; + first_pass = FALSE; + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-p") == 0) + first_pass = TRUE; + else if (strcmp (argv[i], "-t") == 0) + test_mode = TRUE; + else if (strcmp (argv[i], "-v") == 0) + verbose_mode = TRUE; + else + { + n = atoi (argv[i]); + if (n < 1 || n > galaxy.num_species) + { + fprintf (stderr, + "\n '%s' is not a valid argument!\n", argv[i]); + exit (-1); + } + sp_num[num_species++] = n; + } + } + + if (num_species == 0) + { + num_species = galaxy.num_species; + for (i = 0; i < num_species; i++) + sp_num[i] = i+1; + do_all_species = TRUE; + } + else + do_all_species = FALSE; + + /* Two passes through all orders will be done. The first pass will + check for errors and abort if any are found. Results will be written + to disk only on the second pass. */ + +start_pass: + + if (first_pass) printf ("\nStarting first pass...\n\n"); + + get_star_data (); + get_planet_data (); + get_species_data (); + + /* Main loop. For each species, take appropriate action. */ + for (sp_index = 0; sp_index < num_species; sp_index++) + { + species_number = sp_num[sp_index]; + species_index = species_number - 1; + + found = data_in_memory[species_index]; + if (! found) + { + if (do_all_species) + { + if (first_pass) printf ("\n Skipping species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n Cannot get data for species #%d!\n", + species_number); + exit (-1); + } + } + + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + ship_base = ship_data[species_index]; + + /* Do some initializations. */ + species->auto_orders = FALSE; + + /* Open orders file for this species. */ + sprintf (filename, "sp%02d.ord\0", species_number); + input_file = fopen (filename, "r"); + if (input_file == NULL) + { + if (do_all_species) + { + if (first_pass) printf ("\n No orders for species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + } + + end_of_file = FALSE; + + just_opened_file = TRUE; /* Tell parse.c to skip mail header, + if any. */ +find_start: + + /* Search for START POST-ARRIVAL order. */ + found = FALSE; + while (! found) + { + command = get_command(); + if (command == MESSAGE) + { + /* Skip MESSAGE text. It may contain a line that starts + with "start". */ + while (TRUE) + { + command = get_command(); + if (command < 0) + { + fprintf (stderr, + "WARNING: Unterminated MESSAGE command in file %s!\n", + filename); + break; + } + + if (command == ZZZ) goto find_start; + } + } + + if (command < 0) + break; /* End of file. */ + + if (command != START) + continue; + + /* Get the first three letters of the keyword and convert to + upper case. */ + skip_whitespace(); + for (i = 0; i < 3; i++) + { + keyword[i] = toupper (*input_line_pointer); + ++input_line_pointer; + } + keyword[3] = '\0'; + + if (strcmp(keyword, "POS") == 0) found = TRUE; + } + + if (! found) + { + if (first_pass) printf ("\nNo post-arrival orders for species #%d, SP %s.\n", + species_number, species->name); + goto done_orders; + } + + /* Open log file. Use stdout for first pass. */ + log_stdout = FALSE; /* We will control value of log_file from here. */ + if (first_pass) + { + log_file = stdout; + } + else + { + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + log_string ("\nPost-arrival orders:\n"); + } + + /* For each ship, set dest_z to zero. If a starbase is used as a + gravitic telescope, it will be set to non-zero. This will + prevent more than one TELESCOPE order per turn per starbase. */ + ship = ship_base; + for (i = 0; i < species->num_ships; i++) + { + ship->dest_z = 0; + ++ship; + } + + /* Handle post-arrival orders for this species. */ + do_postarrival_orders (); + + data_modified[species_index] = TRUE; + + /* If this is the second pass, close the log file. */ + if (! first_pass) fclose (log_file); + +done_orders: + + fclose (input_file); + } + + if (first_pass) + { + printf ("\nFinal chance to abort safely!\n"); + gamemaster_abort_option (); + first_pass = FALSE; + free_species_data (); + free (star_base); /* In case data was modified. */ + free (planet_base); /* In case data was modified. */ + + printf ("\nStarting second pass...\n\n"); + + goto start_pass; + } + + save_species_data (); + save_transaction_data (); + if (star_data_modified) save_star_data (); + if (planet_data_modified) save_planet_data (); + free_species_data (); + free (star_base); + free (planet_base); + exit (0); +} + + + +do_postarrival_orders () + +{ + int i, command; + + + if (first_pass) + printf ("\nStart of post-arrival orders for species #%d, SP %s...\n", + species_number, species->name); + + truncate_name = TRUE; /* For these commands, do not display age + or landed/orbital status of ships. */ + + while (TRUE) + { + command = get_command(); + + if (command == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Unknown or missing command.\n"); + continue; + } + + if (end_of_file || command == END) + { + if (first_pass) + printf ("End of post-arrival orders for species #%d, SP %s.\n", + species_number, species->name); + + if (first_pass) gamemaster_abort_option (); + + break; /* END for this species. */ + } + + switch (command) + { + case ALLY: + do_ALLY_command (); + break; + + case AUTO: + species->auto_orders = TRUE; + log_string (" An AUTO order was executed.\n"); + break; + + case DEEP: + do_DEEP_command (); + break; + + case DESTROY: + do_DESTROY_command (); + break; + + case ENEMY: + do_ENEMY_command (); + break; + + case LAND: + do_LAND_command (); + break; + + case MESSAGE: + do_MESSAGE_command (); + break; + + case NAME: + do_NAME_command (); + break; + + case NEUTRAL: + do_NEUTRAL_command (); + break; + + case ORBIT: + do_ORBIT_command (); + break; + + case REPAIR: + do_REPAIR_command (); + break; + + case SCAN: + do_SCAN_command (); + break; + + case SEND: + do_SEND_command (); + break; + + case TEACH: + do_TEACH_command (); + break; + +/* case TECH: + do_TECH_command (); + break; +*/ + case TRANSFER: + do_TRANSFER_command (); + break; + + case TELESCOPE: + do_TELESCOPE_command (); + break; + + case TERRAFORM: + do_TERRAFORM_command (); + break; + + default: + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid post-arrival command.\n"); + } + } +} diff --git a/src/PreDeparture.c b/src/PreDeparture.c new file mode 100644 index 0000000..7666975 --- /dev/null +++ b/src/PreDeparture.c @@ -0,0 +1,382 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int post_arrival_phase = FALSE; + +int x, y, z, pn, nampla_index, ship_index, first_pass, species_number, + species_index; + +int test_mode, verbose_mode; + +extern int star_data_modified, planet_data_modified; +extern struct star_data *star_base; +extern struct planet_data *planet_base; + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + + +extern int end_of_file, truncate_name, log_stdout, + ignore_field_distorters, just_opened_file; +extern char input_line[256], *input_line_pointer; +extern unsigned long last_random; +extern FILE *input_file, *log_file; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, found, num_species, sp_num[MAX_SPECIES], sp_index, + command, do_all_species; + + char filename[32], keyword[4]; + + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get commonly used data. */ + get_galaxy_data (); + get_transaction_data (); + + ignore_field_distorters = TRUE; + + /* Check arguments. If an argument is -p, then do two passes. In the + first pass, display results and prompt the GM, allowing him to + abort if necessary before saving results to disk. If an argument + is -t, then set test mode. All other arguments must be species + numbers. If no species numbers are specified, then do all species. */ + num_species = 0; + first_pass = FALSE; + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-p") == 0) + first_pass = TRUE; + else if (strcmp (argv[i], "-t") == 0) + test_mode = TRUE; + else if (strcmp (argv[i], "-v") == 0) + verbose_mode = TRUE; + else + { + n = atoi (argv[i]); + if (n < 1 || n > galaxy.num_species) + { + fprintf (stderr, + "\n '%s' is not a valid argument!\n", argv[i]); + exit (-1); + } + sp_num[num_species++] = n; + } + } + + if (num_species == 0) + { + num_species = galaxy.num_species; + for (i = 0; i < num_species; i++) + sp_num[i] = i+1; + do_all_species = TRUE; + } + else + do_all_species = FALSE; + + /* Two passes through all orders will be done. The first pass will + check for errors and abort if any are found. Results will be written + to disk only on the second pass. */ + +start_pass: + + if (first_pass) printf ("\nStarting first pass...\n\n"); + + get_species_data (); + get_star_data (); + get_planet_data (); + + /* Main loop. For each species, take appropriate action. */ + for (sp_index = 0; sp_index < num_species; sp_index++) + { + species_number = sp_num[sp_index]; + species_index = species_number - 1; + + found = data_in_memory[species_index]; + if (! found) + { + if (do_all_species) + { + if (first_pass) printf ("\n Skipping species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n Cannot get data for species #%d!\n", + species_number); + exit (-1); + } + } + + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + ship_base = ship_data[species_index]; + + /* Open orders file for this species. */ + sprintf (filename, "sp%02d.ord\0", species_number); + input_file = fopen (filename, "r"); + if (input_file == NULL) + { + if (do_all_species) + { + if (first_pass) printf ("\n No orders for species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + } + + end_of_file = FALSE; + + just_opened_file = TRUE; /* Tell parse.c to skip mail header, + if any. */ +find_start: + + /* Search for START PRE-DEPARTURE order. */ + found = FALSE; + while (! found) + { + command = get_command(); + if (command == MESSAGE) + { + /* Skip MESSAGE text. It may contain a line that starts + with "start". */ + while (TRUE) + { + command = get_command(); + if (command < 0) + { + fprintf (stderr, + "WARNING: Unterminated MESSAGE command in file %s!\n", + filename); + break; + } + + if (command == ZZZ) goto find_start; + } + } + + if (command < 0) + break; /* End of file. */ + + if (command != START) + continue; + + /* Get the first three letters of the keyword and convert to + upper case. */ + skip_whitespace(); + for (i = 0; i < 3; i++) + { + keyword[i] = toupper (*input_line_pointer); + ++input_line_pointer; + } + keyword[3] = '\0'; + + if (strcmp(keyword, "PRE") == 0) found = TRUE; + } + + if (! found) + { + if (first_pass) printf ("\nNo pre-departure orders for species #%d, SP %s.\n", + species_number, species->name); + goto done_orders; + } + + /* Open log file. Use stdout for first pass. */ + log_stdout = FALSE; /* We will control value of log_file from here. */ + if (first_pass) + { + log_file = stdout; + } + else + { + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + log_string ("\nPre-departure orders:\n"); + } + + /* Handle predeparture orders for this species. */ + do_predeparture_orders (); + + data_modified[species_index] = TRUE; + + if (first_pass) goto done_orders; + + /* If this is the second pass, close the log file. */ + if (! first_pass) fclose (log_file); + +done_orders: + + fclose (input_file); + } + + if (first_pass) + { + printf ("\nFinal chance to abort safely!\n"); + gamemaster_abort_option (); + first_pass = FALSE; + free_species_data (); + free (star_base); /* In case data was modified. */ + + printf ("\nStarting second pass...\n\n"); + + goto start_pass; + } + + save_species_data (); + save_transaction_data (); + if (star_data_modified) save_star_data (); + if (planet_data_modified) save_planet_data (); + free_species_data (); + free (star_base); + free (planet_base); + exit (0); +} + + + +do_predeparture_orders () + +{ + int i, command, old_test_mode; + + + if (first_pass) + printf ("\nStart of pre-departure orders for species #%d, SP %s...\n", + species_number, species->name); + + truncate_name = TRUE; /* For these commands, do not display age + or landed/orbital status of ships. */ + + while (TRUE) + { + command = get_command(); + + if (command == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Unknown or missing command.\n"); + continue; + } + + if (end_of_file || command == END) + { + if (first_pass) + printf ("End of pre-departure orders for species #%d, SP %s.\n", + species_number, species->name); + + if (first_pass) gamemaster_abort_option (); + + break; /* END for this species. */ + } + + switch (command) + { + case ALLY: + do_ALLY_command (); + break; + + case BASE: + do_BASE_command (); + break; + + case DEEP: + do_DEEP_command (); + break; + + case DESTROY: + do_DESTROY_command (); + break; + + case DISBAND: + do_DISBAND_command (); + break; + + case ENEMY: + do_ENEMY_command (); + break; + + case INSTALL: + do_INSTALL_command (); + break; + + case LAND: + do_LAND_command (); + break; + + case MESSAGE: + do_MESSAGE_command (); + break; + + case NAME: + do_NAME_command (); + break; + + case NEUTRAL: + do_NEUTRAL_command (); + break; + + case ORBIT: + do_ORBIT_command (); + break; + + case REPAIR: + do_REPAIR_command (); + break; + + case SCAN: + /* Scan is okay in test mode for pre-departure. */ + old_test_mode = test_mode; + test_mode = FALSE; + do_SCAN_command (); + test_mode = old_test_mode; + break; + + case SEND: + do_SEND_command (); + break; + + case TRANSFER: + do_TRANSFER_command (); + break; + + case UNLOAD: + do_UNLOAD_command (); + break; + + default: + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid pre-departure command.\n"); + } + } +} diff --git a/src/Production.c b/src/Production.c new file mode 100644 index 0000000..61ab0dd --- /dev/null +++ b/src/Production.c @@ -0,0 +1,433 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int nampla_index, ship_index, first_pass, doing_production, species_number, + species_index, x, y, z, pn, next_nampla_index; + +int test_mode, verbose_mode; + +char production_done[1000]; +short sp_tech_level[6]; + + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet, *home_planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla, *next_nampla; +struct ship_data *ship_base, *ship; + + +extern int star_data_modified, planet_data_modified; +extern int truncate_name, end_of_file, log_stdout, num_intercepts, + ignore_field_distorters, just_opened_file; +extern long last_random; +extern char input_line[256], *input_line_pointer; + +extern FILE *input_file, *log_file; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, found, num_species, sp_num[MAX_SPECIES], sp_index, + command, do_all_species; + + char filename[32], keyword[4]; + + + /* Seed random number generator. */ + last_random = time(NULL); + n = rnd(100) + rnd(200) + rnd(300); + for (i = 0; i < n; i++) rnd(10); + + /* Get commonly used data. */ + get_galaxy_data (); + get_transaction_data (); + + ignore_field_distorters = TRUE; + + /* Check arguments. If an argument is -p, then do two passes. In the + first pass, display results and prompt the GM, allowing him to + abort if necessary before saving results to disk. All other + arguments must be species numbers. If no species numbers are + specified, then do all species. */ + num_species = 0; + first_pass = FALSE; + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-p") == 0) + first_pass = TRUE; + else if (strcmp (argv[i], "-t") == 0) + test_mode = TRUE; + else if (strcmp (argv[i], "-v") == 0) + verbose_mode = TRUE; + else + { + n = atoi (argv[i]); + if (n < 1 || n > galaxy.num_species) + { + fprintf (stderr, + "\n '%s' is not a valid argument!\n", argv[i]); + exit (-1); + } + sp_num[num_species++] = n; + } + } + + if (num_species == 0) + { + num_species = galaxy.num_species; + for (i = 0; i < num_species; i++) + sp_num[i] = i+1; + do_all_species = TRUE; + } + else + do_all_species = FALSE; + + /* Two passes through all orders will be done. The first pass will + check for errors and abort if any are found. Results will be written + to disk only on the second pass. */ + +start_pass: + + if (first_pass) printf ("\nStarting first pass...\n\n"); + + get_species_data (); + get_star_data (); + get_planet_data (); + + /* Main loop. For each species, take appropriate action. */ + for (sp_index = 0; sp_index < num_species; sp_index++) + { + species_number = sp_num[sp_index]; + species_index = species_number - 1; + + found = data_in_memory[species_index]; + if (! found) + { + if (do_all_species) + { + if (first_pass) printf ("\n Skipping species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n Cannot get data for species #%d!\n", + species_number); + exit (-1); + } + } + + species = &spec_data[species_index]; + nampla_base = namp_data[species_index]; + ship_base = ship_data[species_index]; + + home_planet = planet_base + (int) nampla_base->planet_index; + + /* Open orders file for this species. */ + sprintf (filename, "sp%02d.ord\0", species_number); + input_file = fopen (filename, "r"); + if (input_file == NULL) + { + if (do_all_species) + { + if (first_pass) printf ("\n No orders for species #%d.\n", species_number); + continue; + } + else + { + fprintf (stderr, "\n\tCannot open '%s' for reading!\n\n", filename); + exit (-1); + } + } + + end_of_file = FALSE; + + just_opened_file = TRUE; /* Tell parse.c to skip mail header, + if any. */ +find_start: + + /* Search for START PRODUCTION order. */ + found = FALSE; + while (! found) + { + command = get_command(); + if (command == MESSAGE) + { + /* Skip MESSAGE text. It may contain a line that starts + with "start". */ + while (TRUE) + { + command = get_command(); + if (command < 0) + { + fprintf (stderr, + "WARNING: Unterminated MESSAGE command in file %s!\n", + filename); + break; + } + + if (command == ZZZ) goto find_start; + } + } + + if (command < 0) + break; /* End of file. */ + + if (command != START) + continue; + + /* Get the first three letters of the keyword and convert to + upper case. */ + skip_whitespace(); + for (i = 0; i < 3; i++) + { + keyword[i] = toupper (*input_line_pointer); + ++input_line_pointer; + } + keyword[3] = '\0'; + + if (strcmp(keyword, "PRO") == 0) found = TRUE; + } + + if (! found) + { + if (first_pass) printf ("\nNo production orders for species #%d, SP %s.\n", + species_number, species->name); + goto done_orders; + } + + /* Open log file. Use stdout for first pass. */ + log_stdout = FALSE; /* We will control value of log_file from here. */ + if (first_pass) + { + log_file = stdout; + } + else + { + /* Open log file for appending. */ + sprintf (filename, "sp%02d.log\0", species_number); + log_file = fopen (filename, "a"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + fprintf (log_file, "\nProduction orders:\n"); + fprintf (log_file, "\n Number of economic units at start of production: %ld\n\n", species->econ_units); + } + + /* Initialize "done" arrays. They will be used to prevent more + than one corresponding order per planet. */ + if (species->num_namplas > 1000) + { + fprintf (stderr, "\n\n\tInternal error. xxx_done array overflow!/n/n"); + exit (-1); + } + + for (i = 0; i < species->num_namplas; i++) production_done[i] = FALSE; + + /* Do other initializations. */ + for (i = 0; i < species->num_namplas; i++) + { + nampla = nampla_base + i; + nampla->auto_IUs = 0; + nampla->auto_AUs = 0; + nampla->IUs_needed = 0; + nampla->AUs_needed = 0; + } + + /* Handle production orders for this species. */ + num_intercepts = 0; + for (i = 0; i < 6; i++) sp_tech_level[i] = species->tech_level[i]; + do_production_orders (); + for (i = 0; i < 6; i++) species->tech_level[i] = sp_tech_level[i]; + + for (i = 0; i < num_intercepts; i++) + handle_intercept (i); + + data_modified[species_index] = TRUE; + + /* If this is the second pass, close the log file. */ + if (! first_pass) fclose (log_file); + +done_orders: + + fclose (input_file); + } + + if (first_pass) + { + printf ("\nFinal chance to abort safely!\n"); + gamemaster_abort_option (); + first_pass = FALSE; + free_species_data (); + free (star_base); /* In case data was modified. */ + free (planet_base); /* In case data was modified. */ + + printf ("\nStarting second pass...\n\n"); + + goto start_pass; + } + + save_species_data (); + free_species_data (); + if (planet_data_modified) save_planet_data (); + free (planet_base); + save_transaction_data (); + exit (0); +} + + + +do_production_orders () + +{ + int i, command; + + + truncate_name = TRUE; /* For these commands, do not display age + or landed/orbital status of ships. */ + + + if (first_pass) + printf ("\nStart of production orders for species #%d, SP %s...\n", + species_number, species->name); + + doing_production = FALSE; /* This will be set as soon as production + actually starts. */ + while (TRUE) + { + command = get_command(); + + if (command == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Unknown or missing command.\n"); + continue; + } + + if (end_of_file || command == END) + { + /* Handle planets that were not given PRODUCTION orders. */ + next_nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++next_nampla; + + if (production_done[i]) continue; + + production_done[i] = TRUE; + + if (next_nampla->status & DISBANDED_COLONY) continue; + + if (next_nampla->mi_base + next_nampla->ma_base == 0) continue; + + next_nampla_index = i; + + do_PRODUCTION_command (TRUE); + } + + transfer_balance (); /* Terminate production for + last planet for this species. */ + + if (first_pass) + { + gamemaster_abort_option (); + printf ("\nEnd of production orders for species #%d, SP %s.\n", + species_number, species->name); + } + + break; /* END for this species. */ + } + + switch (command) + { + case ALLY: + do_ALLY_command (); + break; + + case AMBUSH: + do_AMBUSH_command (); + break; + + case BUILD: + do_BUILD_command (FALSE, FALSE); + break; + + case CONTINUE: + do_BUILD_command (TRUE, FALSE); + break; + + case DEVELOP: + do_DEVELOP_command (); + break; + + case ENEMY: + do_ENEMY_command (); + break; + + case ESTIMATE: + do_ESTIMATE_command (); + break; + + case HIDE: + do_HIDE_command (); + break; + + case IBUILD: + do_BUILD_command (FALSE, TRUE); + break; + + case ICONTINUE: + do_BUILD_command (TRUE, TRUE); + break; + + case INTERCEPT: + do_INTERCEPT_command (); + break; + + case NEUTRAL: + do_NEUTRAL_command (); + break; + + case PRODUCTION: + do_PRODUCTION_command (FALSE); + break; + + case RECYCLE: + do_RECYCLE_command (); + break; + + case RESEARCH: + do_RESEARCH_command (); + break; + + case SHIPYARD: + do_SHIPYARD_command (); + break; + + case UPGRADE: + do_UPGRADE_command (); + break; + + default: + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid production command.\n"); + } + } +} diff --git a/src/Report.c b/src/Report.c new file mode 100644 index 0000000..9ce827f --- /dev/null +++ b/src/Report.c @@ -0,0 +1,1621 @@ + +/* This program will generate reports for all species in the game and + write them to separate files. Each report will consist of a log of the + events of the previous turn, plus status information for the current + turn. */ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int x, y, z, printing_alien, species_number, fleet_percent_cost; +int test_mode, verbose_mode; + +char ship_already_listed[5000]; + +FILE *report_file; + +struct galaxy_data galaxy; +struct planet_data *planet, *home_planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla1_base, *nampla2_base; +struct ship_data *ship_base, *ship1_base, *ship2_base; + +extern int num_locs, log_stdout, ignore_field_distorters, + truncate_name, num_stars; +extern FILE *log_file; + +extern struct sp_loc_data loc[MAX_LOCATIONS]; +extern struct star_data *star_base; +extern struct planet_data *planet_base; + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, k, ship_index, locations_fd, my_loc_index, its_loc_index, + industry, turn_number, alien_number, species_fd, + header_printed, alien_can_hide, do_this_species, sp_index, + array_index, bit_number, we_have_colony_here, nampla_index, + we_have_planet_here, found, ls_needed, production_penalty, + temp_ignore_field_distorters; + + char filename[32], log_line[256], temp1[16], temp2[128]; + + long n, nn, bit_mask; + + struct species_data *alien; + struct nampla_data *nampla, *alien_nampla, *our_nampla, + *temp_nampla; + struct ship_data *ship, *ship2, *alien_ship; + struct sp_loc_data *locations_base, *my_loc, *its_loc; + + + /* Check for options, if any. */ + test_mode = FALSE; + verbose_mode = FALSE; + for (i = 1; i < argc; i++) + { + if (strcmp (argv[i], "-t") == 0) test_mode = TRUE; + if (strcmp (argv[i], "-v") == 0) verbose_mode = TRUE; + } + + /* Get all necessary data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + get_species_data (); + get_location_data (); + + turn_number = galaxy.turn_number; + + /* Generate a report for each species. */ + alien_number = 0; /* Pointers to alien data not yet assigned. */ + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + /* Check if we are doing all species, or just one or more specified + ones. */ + do_this_species = TRUE; + if (argc > 1) + { + do_this_species = FALSE; + for (i = 1; i < argc; i++) + { + j = atoi(argv[i]); + if (species_number == j) + { + do_this_species = TRUE; + break; + } + } + } + + if (! do_this_species) continue; + + /* Check if this species is still in the game. */ + if (! data_in_memory[species_number - 1]) + { + if (argc == 1) + continue; /* This species is no longer in the game. */ + + fprintf (stderr, "\n\tCannot open data file for species #%d!\n\n", + species_number); + exit (-1); + } + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + nampla1_base = nampla_base; + ship_base = ship_data[species_number - 1]; + ship1_base = ship_base; + home_planet = planet_base + (long) nampla1_base->planet_index; + + /* Print message for gamemaster. */ + if (verbose_mode) + printf ("Generating turn %d report for species #%d, SP %s...\n", + turn_number, species_number, species->name); + + /* Open report file for writing. */ + sprintf (filename, "sp%02d.rpt.t%d", species_number, turn_number); + report_file = fopen (filename, "w"); + if (report_file == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for writing!\n\n", filename); + exit (-1); + } + + /* Copy log file, if any, to output file. */ + sprintf (filename, "sp%02d.log", species_number); + log_file = fopen (filename, "r"); + if (log_file != NULL) + { + if (turn_number > 1) + fprintf (report_file, "\n\n\t\t\tEVENT LOG FOR TURN %d\n", + turn_number - 1); + + while (fgets(log_line, 256, log_file) != NULL) + fputs (log_line, report_file); + + fprintf (report_file, "\n\n"); + + fclose (log_file); + } + + /* Print header for status report. */ + fprintf (report_file, + "\n\t\t\t SPECIES STATUS\n\n\t\t\tSTART OF TURN %d\n\n", + turn_number); + + fprintf (report_file, "Species name: %s\n", species->name); + fprintf (report_file, "Government name: %s\n", species->govt_name); + fprintf (report_file, "Government type: %s\n", species->govt_type); + + fprintf (report_file, "\nTech Levels:\n"); + for (i = 0; i < 6; i++) + { + fprintf (report_file, " %s = %d", tech_name[i], + species->tech_level[i]); + if (species->tech_knowledge[i] > species->tech_level[i]) + fprintf (report_file, "/%d", species->tech_knowledge[i]); + fprintf (report_file, "\n"); + } + + fprintf (report_file, "\nAtmospheric Requirement: %d%%-%d%% %s", + (int) species->required_gas_min, + (int) species->required_gas_max, + gas_string[species->required_gas]); + fprintf (report_file, "\nNeutral Gases:"); + for (i = 0; i < 6; i++) + { + if (i != 0) fprintf (report_file, ","); + fprintf (report_file, " %s", gas_string[species->neutral_gas[i]]); + } + fprintf (report_file, "\nPoisonous Gases:"); + for (i = 0; i < 6; i++) + { + if (i != 0) fprintf (report_file, ","); + fprintf (report_file, " %s", gas_string[species->poison_gas[i]]); + } + fprintf (report_file, "\n"); + + /* List fleet maintenance cost and its percentage of total + production. */ + fleet_percent_cost = species->fleet_percent_cost; + + fprintf (report_file, + "\nFleet maintenance cost = %ld (%d.%02d%% of total production)\n", + species->fleet_cost, fleet_percent_cost/100, + fleet_percent_cost%100); + + if (fleet_percent_cost > 10000) fleet_percent_cost = 10000; + + /* List species that have been met. */ + n = 0; + log_file = report_file; /* Use log utils for this. */ + log_stdout = FALSE; + header_printed = FALSE; + for (sp_index = 0; sp_index < galaxy.num_species; sp_index++) + { + if (! data_in_memory[sp_index]) continue; + + array_index = (sp_index) / 32; + bit_number = (sp_index) % 32; + bit_mask = 1 << bit_number; + if ((species->contact[array_index] & bit_mask) == 0) continue; + + if (! header_printed) + { + log_string ("\nSpecies met: "); + header_printed = TRUE; + } + + if (n > 0) log_string (", "); + log_string ("SP "); log_string (spec_data[sp_index].name); + ++n; + } + if (n > 0) log_char ('\n'); + + /* List declared allies. */ + n = 0; + header_printed = FALSE; + for (sp_index = 0; sp_index < galaxy.num_species; sp_index++) + { + if (! data_in_memory[sp_index]) continue; + + array_index = (sp_index) / 32; + bit_number = (sp_index) % 32; + bit_mask = 1 << bit_number; + if ((species->ally[array_index] & bit_mask) == 0) continue; + if ((species->contact[array_index] & bit_mask) == 0) continue; + + if (! header_printed) + { + log_string ("\nAllies: "); + header_printed = TRUE; + } + + if (n > 0) log_string (", "); + log_string ("SP "); log_string (spec_data[sp_index].name); + ++n; + } + if (n > 0) log_char ('\n'); + + /* List declared enemies that have been met. */ + n = 0; + header_printed = FALSE; + for (sp_index = 0; sp_index < galaxy.num_species; sp_index++) + { + if (! data_in_memory[sp_index]) continue; + + array_index = (sp_index) / 32; + bit_number = (sp_index) % 32; + bit_mask = 1 << bit_number; + if ((species->enemy[array_index] & bit_mask) == 0) continue; + if ((species->contact[array_index] & bit_mask) == 0) continue; + + if (! header_printed) + { + log_string ("\nEnemies: "); + header_printed = TRUE; + } + + if (n > 0) log_string (", "); + log_string ("SP "); log_string (spec_data[sp_index].name); + ++n; + } + if (n > 0) log_char ('\n'); + + fprintf (report_file, "\nEconomic units = %ld\n", species->econ_units); + + /* Initialize flag. */ + for (i = 0; i < species->num_ships; i++) + ship_already_listed[i] = FALSE; + + /* Print report for each producing planet. */ + nampla = nampla1_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->pn == 99) continue; + if (nampla->mi_base == 0 && nampla->ma_base == 0 + && (nampla->status & HOME_PLANET) == 0) continue; + + planet = planet_base + (long) nampla->planet_index; + fprintf (report_file, + "\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n"); + do_planet_report (nampla, ship1_base, species); + } + + /* Give only a one-line listing for other planets. */ + printing_alien = FALSE; + header_printed = FALSE; + nampla = nampla1_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->pn == 99) continue; + if (nampla->mi_base > 0 || nampla->ma_base > 0 + || (nampla->status & HOME_PLANET) != 0) continue; + + if (! header_printed) + { + fprintf (report_file, + "\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n"); + fprintf (report_file, "\n\nOther planets and ships:\n\n"); + header_printed = TRUE; + } + fprintf (report_file, "%4d%3d%3d #%d\tPL %s", nampla->x, + nampla->y, nampla->z, nampla->pn, nampla->name); + + for (j = 0; j < MAX_ITEMS; j++) + { + if (nampla->item_quantity[j] > 0) + fprintf (report_file, ", %d %s", + nampla->item_quantity[j], item_abbr[j]); + } + fprintf (report_file, "\n"); + + /* Print any ships at this planet. */ + ship = ship1_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship_already_listed[ship_index]) continue; + + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + + fprintf (report_file, "\t\t%s", ship_name (ship)); + for (j = 0; j < MAX_ITEMS; j++) + { + if (ship->item_quantity[j] > 0) + fprintf (report_file, ", %d %s", + ship->item_quantity[j], item_abbr[j]); + } + fprintf (report_file, "\n"); + + ship_already_listed[ship_index] = TRUE; + } + } + + /* Report ships that are not associated with a planet. */ + ship = ship1_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + ship->special = 0; + + if (ship_already_listed[ship_index]) continue; + + ship_already_listed[ship_index] = TRUE; + + if (ship->pn == 99) continue; + + if (! header_printed) + { + fprintf (report_file, + "\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n"); + fprintf (report_file, "\n\nOther planets and ships:\n\n"); + header_printed = TRUE; + } + + if (ship->status == JUMPED_IN_COMBAT || ship->status == FORCED_JUMP) + fprintf (report_file, " ?? ?? ??\t%s", ship_name (ship)); + else if (test_mode && ship->arrived_via_wormhole) + fprintf (report_file, " ?? ?? ??\t%s", ship_name (ship)); + else + fprintf (report_file, "%4d%3d%3d\t%s", + ship->x, ship->y, ship->z, ship_name (ship)); + + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + fprintf (report_file, ", %d %s", + ship->item_quantity[i], item_abbr[i]); + } + fprintf (report_file, "\n"); + + if (ship->status == JUMPED_IN_COMBAT + || ship->status == FORCED_JUMP) continue; + + if (test_mode && ship->arrived_via_wormhole) continue; + + /* Print other ships at the same location. */ + ship2 = ship; + for (i = ship_index + 1; i < species->num_ships; i++) + { + ++ship2; + + if (ship_already_listed[i]) continue; + if (ship2->pn == 99) continue; + if (ship2->x != ship->x) continue; + if (ship2->y != ship->y) continue; + if (ship2->z != ship->z) continue; + + fprintf (report_file, "\t\t%s", ship_name (ship2)); + for (j = 0; j < MAX_ITEMS; j++) + { + if (ship2->item_quantity[j] > 0) + fprintf (report_file, ", %d %s", + ship2->item_quantity[j], item_abbr[j]); + } + fprintf (report_file, "\n"); + + ship_already_listed[i] = TRUE; + } + } + + fprintf (report_file, + "\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + /* Report aliens at locations where current species has inhabited + planets or ships. */ + printing_alien = TRUE; + locations_base = &loc[0]; + my_loc = locations_base - 1; + for (my_loc_index = 0; my_loc_index < num_locs; my_loc_index++) + { + ++my_loc; + if (my_loc->s != species_number) continue; + + header_printed = FALSE; + its_loc = locations_base - 1; + for (its_loc_index = 0; its_loc_index < num_locs; its_loc_index++) + { + ++its_loc; + if (its_loc->s == species_number) continue; + if (my_loc->x != its_loc->x) continue; + if (my_loc->y != its_loc->y) continue; + if (my_loc->z != its_loc->z) continue; + + /* There is an alien here. Check if pointers for data for + this alien have been assigned yet. */ + if (its_loc->s != alien_number) + { + alien_number = its_loc->s; + if (! data_in_memory[alien_number - 1]) + { + fprintf (stderr, "\n\nWarning! Data for alien #%d is needed but is not in memory!\n\n", + alien_number); + continue; + } + alien = &spec_data[alien_number - 1]; + nampla2_base = namp_data[alien_number - 1]; + ship2_base = ship_data[alien_number - 1]; + } + + /* Check if we have a named planet in this system. If so, + use it when you print the header. */ + we_have_planet_here = FALSE; + nampla = nampla1_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->x != my_loc->x) continue; + if (nampla->y != my_loc->y) continue; + if (nampla->z != my_loc->z) continue; + if (nampla->pn == 99) continue; + + we_have_planet_here = TRUE; + our_nampla = nampla; + + break; + } + + /* Print all inhabited alien namplas at this location. */ + alien_nampla = nampla2_base - 1; + for (i = 0; i < alien->num_namplas; i++) + { + ++alien_nampla; + + if (my_loc->x != alien_nampla->x) continue; + if (my_loc->y != alien_nampla->y) continue; + if (my_loc->z != alien_nampla->z) continue; + if ((alien_nampla->status & POPULATED) == 0) continue; + + /* Check if current species has a colony on the same + planet. */ + we_have_colony_here = FALSE; + nampla = nampla1_base - 1; + for (j = 0; j < species->num_namplas; j++) + { + ++nampla; + + if (alien_nampla->x != nampla->x) continue; + if (alien_nampla->y != nampla->y) continue; + if (alien_nampla->z != nampla->z) continue; + if (alien_nampla->pn != nampla->pn) continue; + if ((nampla->status & POPULATED) == 0) continue; + + we_have_colony_here = TRUE; + + break; + } + + if (alien_nampla->hidden && ! we_have_colony_here) + continue; + + if (! header_printed) + { + fprintf (report_file, + "\n\nAliens at x = %d, y = %d, z = %d", + my_loc->x, my_loc->y, my_loc->z); + + if (we_have_planet_here) + fprintf (report_file, " (PL %s star system)", + our_nampla->name); + + fprintf (report_file, ":\n"); + header_printed = TRUE; + } + + industry = alien_nampla->mi_base + alien_nampla->ma_base; + + if (alien_nampla->status & MINING_COLONY) + sprintf (temp1, "%s", "Mining colony"); + else if (alien_nampla->status & RESORT_COLONY) + sprintf (temp1, "%s", "Resort colony"); + else if (alien_nampla->status & HOME_PLANET) + sprintf (temp1, "%s", "Home planet"); + else if (industry > 0) + sprintf (temp1, "%s", "Colony planet"); + else + sprintf (temp1, "%s", "Uncolonized planet"); + + sprintf (temp2, " %s PL %s (pl #%d)", temp1, + alien_nampla->name, alien_nampla->pn); + n = 53 - strlen (temp2); + for (j = 0; j < n; j++) strcat (temp2, " "); + fprintf (report_file, "%sSP %s\n", temp2, alien->name); + + j = industry; + if (industry < 100) + industry = (industry + 5)/10; + else + industry = ((industry + 50)/100) * 10; + + if (j == 0) + fprintf (report_file, + " (No economic base.)\n"); + else + fprintf (report_file, + " (Economic base is approximately %d.)\n", + industry); + + /* If current species has a colony on the same + planet, report any PDs and any shipyards. */ + if (we_have_colony_here) + { + if (alien_nampla->item_quantity[PD] == 1) + fprintf (report_file, + " (There is 1 %s on the planet.)\n", + item_name[PD]); + else if (alien_nampla->item_quantity[PD] > 1) + fprintf (report_file, + " (There are %ld %ss on the planet.)\n", + alien_nampla->item_quantity[PD], + item_name[PD]); + + if (alien_nampla->shipyards == 1) + fprintf (report_file, + " (There is 1 shipyard on the planet.)\n"); + else if (alien_nampla->shipyards > 1) + fprintf (report_file, + " (There are %d shipyards on the planet.)\n", + alien_nampla->shipyards); + } + + /* Also report if alien colony is actively hiding. */ + if (alien_nampla->hidden) + fprintf (report_file, + " (Colony is actively hiding from alien observation.)\n"); + } + + /* Print all alien ships at this location. */ + alien_ship = ship2_base - 1; + for (i = 0; i < alien->num_ships; i++) + { + ++alien_ship; + + if (alien_ship->pn == 99) continue; + if (my_loc->x != alien_ship->x) continue; + if (my_loc->y != alien_ship->y) continue; + if (my_loc->z != alien_ship->z) continue; + + /* An alien ship cannot hide if it lands on the + surface of a planet populated by the current + species. */ + alien_can_hide = TRUE; + nampla = nampla1_base - 1; + for (j = 0; j < species->num_namplas; j++) + { + ++nampla; + + if (alien_ship->x != nampla->x) continue; + if (alien_ship->y != nampla->y) continue; + if (alien_ship->z != nampla->z) continue; + if (alien_ship->pn != nampla->pn) continue; + if (nampla->status & POPULATED) + { + alien_can_hide = FALSE; + break; + } + } + + if (alien_can_hide && alien_ship->status == ON_SURFACE) + continue; + + if (alien_can_hide && alien_ship->status == UNDER_CONSTRUCTION) + continue; + + if (! header_printed) + { + fprintf (report_file, + "\n\nAliens at x = %d, y = %d, z = %d", + my_loc->x, my_loc->y, my_loc->z); + + if (we_have_planet_here) + fprintf (report_file, " (PL %s star system)", + our_nampla->name); + + fprintf (report_file, ":\n"); + header_printed = TRUE; + } + + print_ship (alien_ship, alien, alien_number); + } + } + } + + printing_alien = FALSE; + + if (test_mode) goto done_report; + + /* Generate order section. */ + truncate_name = TRUE; + temp_ignore_field_distorters = ignore_field_distorters; + ignore_field_distorters = TRUE; + + fprintf (report_file, + "\n\n* * * * * * * * * * * * * * * * * * * * * * * * *\n"); + + fprintf (report_file, + "\n\nORDER SECTION. Remove these two lines and everything above\n"); + fprintf (report_file, " them, and submit only the orders below.\n\n"); + + fprintf (report_file, "START COMBAT\n"); + fprintf (report_file, "; Place combat orders here.\n\n"); + fprintf (report_file, "END\n\n"); + + fprintf (report_file, "START PRE-DEPARTURE\n"); + fprintf (report_file, "; Place pre-departure orders here.\n\n"); + + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + nampla = nampla_base + nampla_index; + if (nampla->pn == 99) continue; + + /* Generate auto-installs for colonies that were loaded via + the DEVELOP command. */ + if (nampla->auto_IUs) + fprintf (report_file, "\tInstall\t%d IU\tPL %s\n", + nampla->auto_IUs, nampla->name); + if (nampla->auto_AUs) + fprintf (report_file, "\tInstall\t%d AU\tPL %s\n", + nampla->auto_AUs, nampla->name); + if (nampla->auto_IUs || nampla->auto_AUs) + fprintf (report_file, "\n"); + + if (! species->auto_orders) continue; + + /* Generate auto UNLOAD orders for transports at this nampla. */ + for (j = 0; j < species->num_ships; j++) + { + ship = ship_base + j; + if (ship->pn == 99) continue; + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + if (ship->class != TR) continue; + if (ship->item_quantity[CU] < 1) continue; + + /* New colonies will never be started automatically unless + ship was loaded via a DEVELOP order. */ + if (ship->loading_point != 0) + { + /* Check if transport is at specified unloading point. */ + n = ship->unloading_point; + if (n == nampla_index + || (n == 9999 && nampla_index == 0)) + goto unload_ship; + } + + if ((nampla->status & POPULATED) == 0) continue; + + if ((nampla->mi_base + nampla->ma_base) >= 2000) continue; + + if (nampla->x == nampla_base->x + && nampla->y == nampla_base->y + && nampla->z == nampla_base->z) continue; /* Home sector. */ + +unload_ship: + + n = ship->loading_point; + if (n == 9999) n = 0; /* Home planet. */ + if (n == nampla_index) + continue; /* Ship was just loaded here. */ + + fprintf (report_file, "\tUnload\tTR%d%s %s\n\n", ship->tonnage, + ship_type[ship->type], ship->name); + + ship->special = ship->loading_point; + n = nampla - nampla_base; + if (n == 0) n = 9999; + ship->unloading_point = n; + } + } + + fprintf (report_file, "END\n\n"); + + fprintf (report_file, "START JUMPS\n"); + fprintf (report_file, "; Place jump orders here.\n\n"); + + /* Generate auto-jumps for ships that were loaded via the DEVELOP + command or which were UNLOADed because of the AUTO command. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + ship->just_jumped = FALSE; + + if (ship->pn == 99) continue; + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + + j = ship->special; + if (j) + { + if (j == 9999) j = 0; /* Home planet. */ + temp_nampla = nampla_base + j; + + fprintf (report_file, "\tJump\t%s, PL %s\t; Age %d, ", + ship_name (ship), temp_nampla->name, ship->age); + + print_mishap_chance (ship, temp_nampla->x, temp_nampla->y, + temp_nampla->z); + + fprintf (report_file, "\n\n"); + + ship->just_jumped = TRUE; + + continue; + } + + n = ship->unloading_point; + if (n) + { + if (n == 9999) n = 0; /* Home planet. */ + + temp_nampla = nampla_base + n; + + fprintf (report_file, "\tJump\t%s, PL %s\t; ", ship_name (ship), + temp_nampla->name); + + print_mishap_chance (ship, temp_nampla->x, temp_nampla->y, + temp_nampla->z); + + fprintf (report_file, "\n\n"); + + ship->just_jumped = TRUE; + } + } + + if (! species->auto_orders) goto jump_end; + + /* Generate JUMP orders for all ships that have not yet been + given orders. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + if (ship->just_jumped) continue; + if (ship->status == UNDER_CONSTRUCTION) continue; + if (ship->status == JUMPED_IN_COMBAT) continue; + if (ship->status == FORCED_JUMP) continue; + + if (ship->type == FTL) + { + fprintf (report_file, "\tJump\t%s, ", ship_name (ship)); + if (ship->class == TR && ship->tonnage == 1) + { + closest_unvisited_star (ship); + fprintf (report_file, + "\n\t\t\t; Age %d, now at %d %d %d, ", + ship->age, ship->x, ship->y, ship->z); + + if (ship->status == IN_ORBIT) + fprintf (report_file, "O%d, ", ship->pn); + else if (ship->status == ON_SURFACE) + fprintf (report_file, "L%d, ", ship->pn); + else + fprintf (report_file, "D, "); + + print_mishap_chance (ship, x, y, z); + } + else + { + fprintf (report_file, + "???\t; Age %d, now at %d %d %d", + ship->age, ship->x, ship->y, ship->z); + + if (ship->status == IN_ORBIT) + fprintf (report_file, ", O%d", ship->pn); + else if (ship->status == ON_SURFACE) + fprintf (report_file, ", L%d", ship->pn); + else + fprintf (report_file, ", D"); + + x = 9999; + } + + fprintf (report_file, "\n"); + + /* Save destination so that we can check later if it needs + to be scanned. */ + if (x == 9999) + ship->dest_x = -1; + else + { + ship->dest_x = x; + ship->dest_y = y; + ship->dest_z = z; + } + } + } + +jump_end: + fprintf (report_file, "END\n\n"); + + fprintf (report_file, "START PRODUCTION\n\n"); + + fprintf (report_file, "; Economic units at start of turn = %ld\n\n", + species->econ_units); + + /* Generate a PRODUCTION order for each planet that can produce. */ + for (nampla_index = species->num_namplas - 1; nampla_index >= 0; + nampla_index--) + { + nampla = nampla1_base + nampla_index; + if (nampla->pn == 99) continue; + + if (nampla->mi_base == 0 && (nampla->status & RESORT_COLONY) == 0) continue; + if (nampla->ma_base == 0 && (nampla->status & MINING_COLONY) == 0) continue; + + fprintf (report_file, " PRODUCTION PL %s\n", nampla->name); + + if (nampla->status & MINING_COLONY) + { + fprintf (report_file, + " ; The above PRODUCTION order is required for this mining colony, even\n"); + fprintf (report_file, + " ; if no other production orders are given for it. This mining colony\n"); + fprintf (report_file, + " ; will generate %ld economic units this turn.\n", nampla->use_on_ambush); + } + else if (nampla->status & RESORT_COLONY) + { + fprintf (report_file, + " ; The above PRODUCTION order is required for this resort colony, even\n"); + fprintf (report_file, + " ; though no other production orders can be given for it. This resort\n"); + fprintf (report_file, + " ; colony will generate %ld economic units this turn.\n", nampla->use_on_ambush); + } + else + { + fprintf (report_file, + " ; Place production orders here for planet %s", + nampla->name); + fprintf (report_file, " (sector %d %d %d #%d).\n", nampla->x, + nampla->y, nampla->z, nampla->pn); + fprintf (report_file, + " ; Avail pop = %ld, shipyards = %d, to spend = %ld", + nampla->pop_units, nampla->shipyards, nampla->use_on_ambush); + + n = nampla->use_on_ambush; + if (nampla->status & HOME_PLANET) + { + if (species->hp_original_base != 0) + fprintf (report_file, " (max = %ld)", 5*n); + else + fprintf (report_file, " (max = no limit)"); + } + else + fprintf (report_file, " (max = %ld)", 2*n); + + fprintf (report_file, ".\n\n"); + } + + /* Build IUs and AUs for incoming ships with CUs. */ + if (nampla->IUs_needed) + fprintf (report_file, "\tBuild\t%d IU\n", nampla->IUs_needed); + if (nampla->AUs_needed) + fprintf (report_file, "\tBuild\t%d AU\n", nampla->AUs_needed); + if (nampla->IUs_needed || nampla->AUs_needed) + fprintf (report_file, "\n"); + + if (! species->auto_orders) continue; + if (nampla->status & MINING_COLONY) continue; + if (nampla->status & RESORT_COLONY) continue; + + /* See if there are any RMs to recycle. */ + n = nampla->special / 5; + if (n > 0) + fprintf (report_file, "\tRecycle\t%d RM\n\n", 5*n); + + /* Generate DEVELOP commands for ships arriving here because of + AUTO command. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + + k = ship->special; + if (k == 0) continue; + if (k == 9999) k = 0; /* Home planet. */ + + if (nampla != nampla_base + k) continue; + + k = ship->unloading_point; + if (k == 9999) k = 0; + temp_nampla = nampla_base + k; + + fprintf (report_file, "\tDevelop\tPL %s, TR%d%s %s\n\n", + temp_nampla->name, ship->tonnage, ship_type[ship->type], + ship->name); + } + + /* Give orders to continue construction of unfinished ships and + starbases. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (report_file, + "\tContinue\t%s, %d\t; Left to pay = %d\n\n", + ship_name (ship), ship->remaining_cost, + ship->remaining_cost); + + continue; + } + + if (ship->type != STARBASE) continue; + + j = (species->tech_level[MA] / 2) - ship->tonnage; + if (j < 1) continue; + + fprintf (report_file, + "\tContinue\tBAS %s, %d\t; Current tonnage = %s\n\n", + ship->name, 100 * j, commas (10000 * (long) ship->tonnage)); + } + + /* Generate DEVELOP command if this is a colony with an economic + base less than 200. */ + n = nampla->mi_base + nampla->ma_base + nampla->IUs_needed + + nampla->AUs_needed; + nn = nampla->item_quantity[CU]; + for (i = 0; i < species->num_ships; i++) + { + /* Get CUs on transports at planet. */ + ship = ship_base + i; + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + nn += ship->item_quantity[CU]; + } + n += nn; + if ((nampla->status & COLONY) && n < 2000L + && nampla->pop_units > 0) + { + if (nampla->pop_units > (2000L-n)) + nn = 2000L-n; + else + nn = nampla->pop_units; + + fprintf (report_file, "\tDevelop\t%ld\n\n", 2L*nn); + + nampla->IUs_needed += nn; + } + + /* For home planets and any colonies that have an economic base of + at least 200, check if there are other colonized planets in + the same sector that are not self-sufficient. If so, DEVELOP + them. */ + if (n >= 2000L || (nampla->status & HOME_PLANET)) + { + /* Skip home planet. */ + for (i = 1; i < species->num_namplas; i++) + { + if (i == nampla_index) continue; + + temp_nampla = nampla_base + i; + + if (temp_nampla->pn == 99) continue; + if (temp_nampla->x != nampla->x) continue; + if (temp_nampla->y != nampla->y) continue; + if (temp_nampla->z != nampla->z) continue; + + n = temp_nampla->mi_base + temp_nampla->ma_base + + temp_nampla->IUs_needed + temp_nampla->AUs_needed; + + if (n == 0) continue; + + nn = temp_nampla->item_quantity[IU] + + temp_nampla->item_quantity[AU]; + if (nn > temp_nampla->item_quantity[CU]) + nn = temp_nampla->item_quantity[CU]; + n += nn; + if (n >= 2000L) continue; + nn = 2000L - n; + + if (nn > nampla->pop_units) nn = nampla->pop_units; + + fprintf (report_file, "\tDevelop\t%ld\tPL %s\n\n", + 2L * nn, temp_nampla->name); + + temp_nampla->AUs_needed += nn; + } + } + } + + fprintf (report_file, "END\n\n"); + + fprintf (report_file, "START POST-ARRIVAL\n"); + fprintf (report_file, "; Place post-arrival orders here.\n\n"); + + if (! species->auto_orders) goto post_end; + + /* Generate an AUTO command. */ + fprintf (report_file, "\tAuto\n\n"); + + /* Generate SCAN orders for all TR1s that are jumping to + sectors which current species does not inhabit. */ + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + if (ship->pn == 99) continue; + if (ship->status == UNDER_CONSTRUCTION) continue; + if (ship->class != TR) continue; + if (ship->tonnage != 1) continue; + if (ship->type != FTL) continue; + + found = FALSE; + for (j = 0; j < species->num_namplas; j++) + { + if (ship->dest_x == -1) break; + + nampla = nampla_base + j; + if (nampla->pn == 99) continue; + if (nampla->x != ship->dest_x) continue; + if (nampla->y != ship->dest_y) continue; + if (nampla->z != ship->dest_z) continue; + + if (nampla->status & POPULATED) + { + found = TRUE; + break; + } + } + if (! found) fprintf (report_file, "\tScan\tTR1 %s\n", ship->name); + } + +post_end: + fprintf (report_file, "END\n\n"); + + fprintf (report_file, "START STRIKES\n"); + fprintf (report_file, "; Place strike orders here.\n\n"); + fprintf (report_file, "END\n"); + + truncate_name = FALSE; + ignore_field_distorters = temp_ignore_field_distorters; + + done_report: + + /* Clean up for this species. */ + fclose (report_file); + } + + /* Clean up and exit. */ + free_species_data (); + exit (0); +} + + + +do_planet_report (nampla, s_base, species) + +struct species_data *species; +struct nampla_data *nampla; +struct ship_data *s_base; + +{ + int i, j, ship_index, header_printed, ls_needed, production_penalty; + + long n1, n2, n3, raw_material_units, production_capacity, + available_to_spend, n, ib, ab, current_base, md, denom; + + struct ship_data *ship; + + + /* Print type of planet, name and coordinates. */ + fprintf (report_file, "\n\n"); + + if (nampla->status & HOME_PLANET) + fprintf (report_file, "HOME PLANET"); + else if (nampla->status & MINING_COLONY) + fprintf (report_file, "MINING COLONY"); + else if (nampla->status & RESORT_COLONY) + fprintf (report_file, "RESORT COLONY"); + else if (nampla->status & POPULATED) + fprintf (report_file, "COLONY PLANET"); + else fprintf (report_file, "PLANET"); + + fprintf (report_file, ": PL %s", nampla->name); + + fprintf (report_file, + "\n Coordinates: x = %d, y = %d, z = %d, planet number %d\n", + nampla->x, nampla->y, nampla->z, nampla->pn); + + if (nampla->status & HOME_PLANET) + { + ib = nampla->mi_base; + ab = nampla->ma_base; + current_base = ib + ab; + if (current_base < species->hp_original_base) + { + n = species->hp_original_base - current_base; /* Number of CUs needed. */ + + md = home_planet->mining_difficulty; + + denom = 100 + md; + j = (100 * (n + ib) - (md * ab) + denom/2) / denom; + i = n - j; + + if (i < 0) + { + j = n; + i = 0; + } + if (j < 0) + { + i = n; + j = 0; + } + + fprintf (report_file, + "\nWARNING! Home planet has not yet completely recovered from bombardment!\n"); + fprintf (report_file, + " %d IUs and %d AUs will have to be installed for complete recovery.\n", + i, j); + } + } + + if ( ! (nampla->status & POPULATED) ) + goto do_inventory; + + /* Print available population. */ + if (nampla->status & (MINING_COLONY | RESORT_COLONY)) + ; + else + fprintf (report_file, "\nAvailable population units = %ld\n", + nampla->pop_units); + + if (nampla->siege_eff != 0) + { + fprintf (report_file, + "\nWARNING! This planet is currently under siege and will remain\n"); + fprintf (report_file, + " under siege until the combat phase of the next turn!\n"); + } + + if (nampla->use_on_ambush > 0) + fprintf (report_file, + "\nIMPORTANT! This planet has made preparations for an ambush!\n"); + + if (nampla->hidden) + fprintf (report_file, + "\nIMPORTANT! This planet is actively hiding from alien observation!\n"); + + /* Print what will be produced this turn. */ + raw_material_units = + (10L * (long) species->tech_level[MI] * (long) nampla->mi_base) + / (long) planet->mining_difficulty; + production_capacity = + ((long) species->tech_level[MA] * (long) nampla->ma_base) / 10L; + + ls_needed = life_support_needed (species, home_planet, planet); + + if (ls_needed == 0) + production_penalty = 0; + else + production_penalty = (100 * ls_needed) / species->tech_level[LS]; + + fprintf (report_file, "\nProduction penalty = %d%% (LSN = %d)\n", + production_penalty, ls_needed); + + fprintf (report_file, "\nEconomic efficiency = %d%%\n", + planet->econ_efficiency); + + raw_material_units + -= (production_penalty * raw_material_units) / 100; + + raw_material_units + = (((long) planet->econ_efficiency * raw_material_units) + 50) / 100; + + production_capacity + -= (production_penalty * production_capacity) / 100; + + production_capacity + = (((long) planet->econ_efficiency * production_capacity) + 50) / 100; + + if (nampla->mi_base > 0) + { + fprintf (report_file, "\nMining base = %d.%d", nampla->mi_base/10, + nampla->mi_base%10); + fprintf (report_file, " (MI = %d, MD = %d.%02d)\n", + species->tech_level[MI], planet->mining_difficulty/100, + planet->mining_difficulty%100); + + /* For mining colonies, print economic units that will be produced. */ + if (nampla->status & MINING_COLONY) + { + n1 = (2 * raw_material_units) / 3; + n2 = ((fleet_percent_cost * n1) + 5000) / 10000; + n3 = n1 - n2; + fprintf (report_file, + " This mining colony will generate %ld - %ld = %ld economic units this turn.\n", + n1, n2, n3); + + nampla->use_on_ambush = n3; /* Temporary use only. */ + } + else + { + fprintf (report_file, + " %ld raw material units will be produced this turn.\n", + raw_material_units); + } + } + + if (nampla->ma_base > 0) + { + if (nampla->status & RESORT_COLONY) fprintf (report_file, "\n"); + + fprintf (report_file, "Manufacturing base = %d.%d", + nampla->ma_base/10, nampla->ma_base%10); + fprintf (report_file, " (MA = %d)\n", species->tech_level[MA]); + + /* For resort colonies, print economic units that will be produced. */ + if (nampla->status & RESORT_COLONY) + { + n1 = (2 * production_capacity) / 3; + n2 = ((fleet_percent_cost * n1) + 5000) / 10000; + n3 = n1 - n2; + fprintf (report_file, + " This resort colony will generate %ld - %ld = %ld economic units this turn.\n", + n1, n2, n3); + + nampla->use_on_ambush = n3; /* Temporary use only. */ + } + else + { + fprintf (report_file, + " Production capacity this turn will be %ld.\n", + production_capacity); + } + } + + if (nampla->item_quantity[RM] > 0) + fprintf (report_file, "\n%ss (%s,C%d) carried over from last turn = %ld\n", + item_name[RM], item_abbr[RM], item_carry_capacity[RM], + nampla->item_quantity[RM]); + + /* Print what can be spent this turn. */ + raw_material_units += nampla->item_quantity[RM]; + if (raw_material_units > production_capacity) + { + available_to_spend = production_capacity; + nampla->special = raw_material_units - production_capacity; + /* Excess raw material units that may be recycled in AUTO mode. */ + } + else + { + available_to_spend = raw_material_units; + nampla->special = 0; + } + + /* Don't print spendable amount for mining and resort colonies. */ + n1 = available_to_spend; + n2 = ((fleet_percent_cost * n1) + 5000) / 10000; + n3 = n1 - n2; + if ( ! (nampla->status & MINING_COLONY) + && ! (nampla->status & RESORT_COLONY)) + { + fprintf (report_file, + "\nTotal available for spending this turn = %ld - %ld = %ld\n", + n1, n2, n3); + nampla->use_on_ambush = n3; /* Temporary use only. */ + + fprintf (report_file, + "\nShipyard capacity = %d\n", nampla->shipyards); + } + +do_inventory: + + header_printed = FALSE; + + for (i = 0; i < MAX_ITEMS; i++) + { + if (nampla->item_quantity[i] > 0 && i != RM) + { + if (! header_printed) + { + header_printed = TRUE; + fprintf (report_file, "\nPlanetary inventory:\n"); + } + + fprintf (report_file, " %ss (%s,C%d) = %d", + item_name[i], item_abbr[i], + item_carry_capacity[i], nampla->item_quantity[i]); + if (i == PD) + fprintf (report_file, " (warship equivalence = %ld tons)", + 50 * nampla->item_quantity[PD]); + fprintf (report_file, "\n"); + } + } + + /* Print all ships that are under construction on, on the surface of, + or in orbit around this planet. */ + printing_alien = FALSE; + header_printed = FALSE; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship = s_base + ship_index; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != ship->pn) continue; + if (ship->class != BA) continue; + + if (! header_printed) + { + fprintf (report_file, "\nShips at PL %s:\n", nampla->name); + print_ship_header(); + } + header_printed = TRUE; + + print_ship (ship, species, species_number); + + ship_already_listed[ship_index] = TRUE; + } + + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship = s_base + ship_index; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != ship->pn) continue; + if (ship->class != TR) continue; + + if (! header_printed) + { + fprintf (report_file, "\nShips at PL %s:\n", nampla->name); + print_ship_header(); + } + header_printed = TRUE; + + print_ship (ship, species, species_number); + + ship_already_listed[ship_index] = TRUE; + } + + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship = s_base + ship_index; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != ship->pn) continue; + if (ship_already_listed[ship_index]) continue; + + if (! header_printed) + { + fprintf (report_file, "\nShips at PL %s:\n", nampla->name); + print_ship_header(); + } + header_printed = TRUE; + + print_ship (ship, species, species_number); + + ship_already_listed[ship_index] = TRUE; + } +} + + + +print_ship_header () +{ + fprintf (report_file, " Name "); + if (printing_alien) + fprintf (report_file, " Species\n"); + else + fprintf (report_file, " Cap. Cargo\n"); + fprintf (report_file, " ---------------------------------------"); + fprintf (report_file, "-------------------------------------\n"); +} + + +extern char full_ship_id[64]; + +print_ship (ship, species, species_number) + +struct species_data *species; +struct ship_data *ship; +int species_number; + +{ + int i, n, length, capacity, need_comma; + + + if (printing_alien) + ignore_field_distorters = FALSE; + else + ignore_field_distorters = TRUE; + + fprintf (report_file, " %s", ship_name (ship)); + + length = strlen (full_ship_id); + if (printing_alien) + n = 50; + else + n = 46; + + for (i = 0; i < (n - length); i++) + putc (' ', report_file); + + if (ship->class == BA) + capacity = 10 * (int) ship->tonnage; + else if (ship->class == TR) + capacity = (10 + ((int) ship->tonnage / 2)) * (int) ship->tonnage; + else + capacity = ship->tonnage; + + if (printing_alien) + fprintf (report_file, " "); + else + { + fprintf (report_file, "%4d ", capacity); + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (report_file, "Left to pay = %d\n", ship->remaining_cost); + return; + } + } + + if (printing_alien) + { + if (ship->status == ON_SURFACE + || ship->item_quantity[FD] != ship->tonnage) + fprintf (report_file, "SP %s", species->name); + else + fprintf (report_file, "SP %d", distorted (species_number)); + } + else + { + need_comma = FALSE; + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + { + if (need_comma) putc (',', report_file); + fprintf (report_file, "%d %s", + ship->item_quantity[i], item_abbr[i]); + need_comma = TRUE; + } + } + } + + putc ('\n', report_file); +} + + +print_mishap_chance (ship, destx, desty, destz) + +struct ship_data *ship; +int destx, desty, destz; + +{ + int mishap_GV, mishap_age; + + long x, y, z, mishap_chance, success_chance; + + + if (destx == 9999) + { + fprintf (report_file, "Mishap chance = ???"); + return; + } + + mishap_GV = species->tech_level[GV]; + mishap_age = ship->age; + + x = destx; + y = desty; + z = destz; + mishap_chance = ( 100 * ( + ((x - ship->x) * (x - ship->x)) + + ((y - ship->y) * (y - ship->y)) + + ((z - ship->z) * (z - ship->z)) + ) ) / mishap_GV; + + if (mishap_age > 0 && mishap_chance < 10000) + { + success_chance = 10000L - mishap_chance; + success_chance -= (2L * (long) mishap_age * success_chance)/100L; + mishap_chance = 10000L - success_chance; + } + + if (mishap_chance > 10000) mishap_chance = 10000; + + fprintf (report_file, "mishap chance = %ld.%02ld%%", + mishap_chance/100L, mishap_chance%100L); +} + + +closest_unvisited_star (ship) + +struct ship_data *ship; + +{ + int i, found, species_array_index, species_bit_number; + + long shx, shy, shz, stx, sty, stz, closest_distance, temp_distance, + species_bit_mask; + + struct star_data *star, *closest_star; + + + /* Get array index and bit mask. */ + species_array_index = (species_number - 1) / 32; + species_bit_number = (species_number - 1) % 32; + species_bit_mask = 1 << species_bit_number; + + shx = ship->x; + shy = ship->y; + shz = ship->z; + + x = 9999; + closest_distance = 999999; + + found = FALSE; + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + /* Check if bit is already set. */ + if (star->visited_by[species_array_index] & species_bit_mask) continue; + + stx = star->x; + sty = star->y; + stz = star->z; + + temp_distance = + ((shx - stx) * (shx - stx)) + + ((shy - sty) * (shy - sty)) + + ((shz - stz) * (shz - stz)); + + if (temp_distance < closest_distance) + { + x = stx; + y = sty; + z = stz; + closest_distance = temp_distance; + closest_star = star; + found = TRUE; + } + } + + if (found) + { + fprintf (report_file, "%d %d %d", x, y, z); + closest_star->visited_by[species_array_index] |= species_bit_mask; + /* So that we don't send more than one ship to the same place. */ + } + else + fprintf (report_file, "???"); +} diff --git a/src/ScanSpXYZ.c b/src/ScanSpXYZ.c new file mode 100644 index 0000000..00fa329 --- /dev/null +++ b/src/ScanSpXYZ.c @@ -0,0 +1,164 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number; + +struct galaxy_data galaxy; +struct star_data *star; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern FILE *log_file; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + char x, y, z; + + struct species_data sp; + + + /* Check for valid command line. */ + if (argc != 5) + { + fprintf (stderr, "\n\tUsage: ScanSpXYZ species_number x y z\n\n"); + exit (-1); + } + + species_number = atoi (argv[1]); + x = atoi (argv[2]); + y = atoi (argv[3]); + z = atoi (argv[4]); + log_file = stdout; + + /* Get commonly used data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + + /* Read data for this species from disk. */ + if (! get_spec_data (species_number, &sp, FALSE, FALSE)) + { + fprintf (stderr, "\n\n\tCannot open data file for species #%d!\n\n", + species_number); + exit (-1); + } + + /* Display scan. */ + fprintf (log_file, "Scan for SP %s:\n", sp.name); + species = &sp; + scan (x, y, z); + + /* Release memory used for this species. */ + if (sp.num_ships > 0) free (ship_base); + free (nampla_base); + + exit (0); +} + + + +/* The following routine will read species data from disk and return + TRUE if it succeeds. If the file does not exist, it will return FALSE. */ + +int get_spec_data (spec_number, spec, + need_extra_namplas, need_extra_ships) + +int spec_number, need_extra_namplas, need_extra_ships; +struct species_data *spec; + +{ + int spec_fd, extra_namplas, extra_ships; + + long n, num_bytes; + + char filename[16]; + + + /* First, check if extras are needed. */ + if (need_extra_namplas) + extra_namplas = NUM_EXTRA_NAMPLAS; + else + extra_namplas = 0; + + if (need_extra_ships) + extra_ships = NUM_EXTRA_SHIPS; + else + extra_ships = 0; + + /* Open the species data file. */ + sprintf (filename, "sp%02d.dat\0", spec_number); + spec_fd = open (filename, 0); + if (spec_fd < 0) + { + spec->pn = 0; /* Extinct! */ + return FALSE; + } + + /* Read in species data. */ + num_bytes = read (spec_fd, spec, sizeof(struct species_data)); + if (num_bytes != sizeof(struct species_data)) + { + fprintf (stderr, "\n\tCannot read species record in file '%s'!\n\n", + filename); + exit (-1); + } + + /* Allocate enough memory for all namplas. */ + num_bytes = (spec->num_namplas + extra_namplas) * sizeof (struct nampla_data); + nampla_base = (struct nampla_data *) malloc (num_bytes); + if (nampla_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for nampla data!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + num_bytes = spec->num_namplas * sizeof (struct nampla_data); + n = read (spec_fd, nampla_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read nampla data into memory!\n\n"); + exit (-1); + } + + /* Allocate enough memory for all ships. */ + if ((spec->num_ships + extra_ships) > 0) + { + num_bytes = (spec->num_ships + extra_ships) * sizeof (struct ship_data); + ship_base = (struct ship_data *) malloc (num_bytes); + if (ship_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for ship data!\n\n"); + exit (-1); + } + } + + if (spec->num_ships > 0) + { + /* Read it all into memory. */ + num_bytes = (long) spec->num_ships * sizeof (struct ship_data); + n = read (spec_fd, ship_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read ship data into memory!\n\n"); + exit (-1); + } + } + + close (spec_fd); + + return TRUE; +} diff --git a/src/Set.c b/src/Set.c new file mode 100644 index 0000000..1daebd4 --- /dev/null +++ b/src/Set.c @@ -0,0 +1,1116 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number, species_index, data_was_modified, + num_arguments, abbr_type, abbr_index, sub_light, + tonnage, next_arg; + +char **argument, *ship_name(), input_abbr[32]; + + +struct galaxy_data galaxy; +struct star_data *star; +struct planet_data *planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern int num_stars, num_planets; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + num_arguments = argc; + argument = argv; + + data_was_modified = FALSE; + + /* Find out what we're dealing with. */ + if (argc > 2 && isdigit(argv[1][0]) && ! isdigit(argv[2][0])) + set_species (); + else if (argc > 4 && isdigit(argv[1][0]) && isdigit(argv[2][0]) + && isdigit(argv[3][0]) && ! isdigit(argv[4][0])) + set_star (); + else if (argc > 5 && isdigit(argv[1][0]) && isdigit(argv[2][0]) + && isdigit(argv[3][0]) && isdigit(argv[4][0])) + set_planet (); + + fprintf (stderr, "\n\tUsage:\n\t\tSet n args... for species\n\t\tSet n n n args... for star\n\t\tSet n n n n args... for planet.\n\n"); + exit (-1); +} + +set_species() + +{ + long n; + + + species_number = atoi (argument[1]); + species_index = species_number - 1; + + get_species (); + + next_arg = 2; + +next_item: + + get_class_abbr (argument[next_arg++]); + if (abbr_type == PLANET_ID) + set_nampla (); + else if (abbr_type == SHIP_CLASS) + set_ship (); + else if (abbr_type == TECH_ID) + { + printf ("SP %s, %s tech level = %d", species->name, + tech_name[abbr_index], species->tech_level[abbr_index]); + + if (next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + species->tech_level[abbr_index] = n; + + data_was_modified = TRUE; + } + } + + printf (".\n"); + } + else if (strcmp (input_abbr, "EU") == 0) + { + printf ("SP %s has %ld economic units", species->name, + species->econ_units); + + if (next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + species->econ_units = n; + + data_was_modified = TRUE; + } + } + + printf (".\n"); + } + else if (strcmp (input_abbr, "HP") == 0) + { + printf ("SP %s hp_original_base = %ld", species->name, + species->hp_original_base); + + if (next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + species->hp_original_base = n; + + data_was_modified = TRUE; + } + } + + printf (".\n"); + } + else + { + fprintf (stderr, "\n\tInvalid argument: '%s'!\n\n", argument[--next_arg]); + exit (-1); + } + + if (next_arg < num_arguments) goto next_item; + + if (data_was_modified) save_species (); + + free (nampla_base); + if (species->num_ships > 0) free (ship_base); + + exit (0); +} + + + +set_nampla () + +{ + int i, found; + + long n; + + + found = FALSE; + for (i = 0; i < species->num_namplas; i++) + { + nampla = nampla_base + i; + + if (strcasecmp (argument[next_arg], nampla->name) == 0) + { + found = TRUE; + break; + } + } + + if (! found) + { + fprintf (stderr, "\n\tInvalid planet name: '%s'!\n\n", argument[next_arg]); + exit (-1); + } + + ++next_arg; + +again: + + get_class_abbr (argument[next_arg]); + switch (abbr_type) + { + case ITEM_CLASS: + + printf ("SP %s, PL %s, %ld %ss", species->name, nampla->name, + nampla->item_quantity[abbr_index], item_name[abbr_index]); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + nampla->item_quantity[abbr_index] = n; + + data_was_modified = TRUE; + } + } + + break; + + + default: + + if (strcasecmp (argument[next_arg], "x") == 0) + { + printf ("SP %s, PL %s, x = %d", species->name, nampla->name, + nampla->x); + + ++next_arg; + + break; + } + else if (strcasecmp (argument[next_arg], "y") == 0) + { + printf ("SP %s, PL %s, y = %d", species->name, nampla->name, + nampla->y); + + ++next_arg; + + break; + } + else if (strcasecmp (argument[next_arg], "z") == 0) + { + printf ("SP %s, PL %s, z = %d", species->name, nampla->name, + nampla->z); + + ++next_arg; + + break; + } + else if (strcasecmp (argument[next_arg], "pn") == 0) + { + printf ("SP %s, PL %s, pn = %d", species->name, nampla->name, + nampla->pn); + + ++next_arg; + + break; + } + else if (strcasecmp (argument[next_arg], "sy") == 0) + { + printf ("SP %s, PL %s, %d shipyards", species->name, nampla->name, + nampla->shipyards); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + nampla->shipyards = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "ib") == 0) + { + printf ("SP %s, PL %s, mining base = %d", species->name, nampla->name, + nampla->mi_base); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + nampla->mi_base = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "ab") == 0) + { + printf ("SP %s, PL %s, manufacturing base = %d", species->name, nampla->name, + nampla->ma_base); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + nampla->ma_base = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "ap") == 0) + { + printf ("SP %s, PL %s, available population = %d", species->name, nampla->name, + nampla->pop_units); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + nampla->pop_units = n; + + data_was_modified = TRUE; + } + } + + break; + } + else + return; + } + + printf (".\n"); + + if (next_arg < num_arguments) goto again; + + return; +} + + + +set_ship () + +{ + int i, found; + + long n; + + + found = FALSE; + for (i = 0; i < species->num_ships; i++) + { + ship = ship_base + i; + + if (strcasecmp (argument[next_arg], ship->name) == 0) + { + found = TRUE; + break; + } + } + + if (! found) + { + fprintf (stderr, "\n\tInvalid ship name: '%s'!\n\n", argument[next_arg]); + exit (-1); + } + + ++next_arg; + +again: + + get_class_abbr (argument[next_arg]); + switch (abbr_type) + { + case ITEM_CLASS: + + printf ("SP %s, %s, %ld %ss", species->name, ship_name (ship), + ship->item_quantity[abbr_index], item_name[abbr_index]); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->item_quantity[abbr_index] = n; + + data_was_modified = TRUE; + } + } + + break; + + + default: + + if (strcasecmp (argument[next_arg], "x") == 0) + { + printf ("SP %s, %s, x = %d", species->name, ship_name(ship), + ship->x); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->x = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "y") == 0) + { + printf ("SP %s, %s, y = %d", species->name, ship_name(ship), + ship->y); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->y = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "z") == 0) + { + printf ("SP %s, %s, z = %d", species->name, ship_name(ship), + ship->z); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->z = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "pn") == 0) + { + printf ("SP %s, %s, pn = %d", species->name, ship_name(ship), + ship->pn); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->pn = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "lp") == 0) + { + printf ("SP %s, %s, loading_point = %d", species->name, + ship_name(ship), ship->loading_point); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->loading_point = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "up") == 0) + { + printf ("SP %s, %s, unloading_point = %d", species->name, + ship_name(ship), ship->unloading_point); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->unloading_point = n; + + data_was_modified = TRUE; + } + } + + break; + } + else if (strcasecmp (argument[next_arg], "ag") == 0) + { + printf ("SP %s, %s, age = %d turns", species->name, ship_name(ship), + ship->age); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + ship->age = n; + + data_was_modified = TRUE; + } + } + + break; + } + else + return; + } + + printf (".\n"); + + if (next_arg < num_arguments) goto again; + + return; +} + + + +set_star() + +{ + int i, x, y, z, found; + + long n; + + + x = atoi (argument[1]); + y = atoi (argument[2]); + z = atoi (argument[3]); + + get_star_data (); + + /* Get star. Check if planet exists. */ + found = FALSE; + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + if (star->x != x) continue; + if (star->y != y) continue; + if (star->z != z) continue; + + found = TRUE; + + break; + } + + if (! found ) + { + fprintf (stderr, "\n\tThere is no star at %d %d %d!\n\n", + x, y, z); + exit (-1); + } + + next_arg = 4; + +next_item: + + if (strcasecmp (argument[next_arg], "np") == 0) + { + printf ("For star at %d %d %d, num planets = %d", + x, y, z, star->num_planets); + + ++next_arg; + } + else + { + fprintf (stderr, "\n\tInvalid argument: '%s'!\n\n", argument[next_arg]); + exit (-1); + } + + printf (".\n"); + + if (next_arg < num_arguments) goto next_item; + + if (data_was_modified) save_star_data (); + + free (star_base); + + exit (0); +} + + + +set_planet() + +{ + int i, x, y, z, pn, found; + + long n; + + + x = atoi (argument[1]); + y = atoi (argument[2]); + z = atoi (argument[3]); + pn = atoi (argument[4]); + + get_star_data (); + get_planet_data (); + + /* Get star. Check if planet exists. */ + found = FALSE; + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + if (star->x != x) continue; + if (star->y != y) continue; + if (star->z != z) continue; + + if (pn > star->num_planets) break; + + found = TRUE; + + break; + } + + if (! found ) + { + fprintf (stderr, "\n\tThere is no planet at %d %d %d %d!\n\n", + x, y, z, pn); + exit (-1); + } + + planet = planet_base + star->planet_index + pn - 1; + + next_arg = 5; + +next_item: + + if (strcasecmp (argument[next_arg], "md") == 0) + { + printf ("For planet #%d at %d %d %d, mining difficulty = %d", + pn, x, y, z, planet->mining_difficulty); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + planet->mining_difficulty = n; + + data_was_modified = TRUE; + } + } + } + else if (strcasecmp (argument[next_arg], "ee") == 0) + { + printf ("For planet #%d at %d %d %d, economic efficiency = %d", + pn, x, y, z, planet->econ_efficiency); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + planet->econ_efficiency = n; + + data_was_modified = TRUE; + } + } + } + else if (strcasecmp (argument[next_arg], "pc") == 0) + { + printf ("For planet #%d at %d %d %d, pressure class = %d", + pn, x, y, z, planet->pressure_class ); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + planet->pressure_class = n; + + data_was_modified = TRUE; + } + } + } + else if (strcasecmp (argument[next_arg], "tc") == 0) + { + printf ("For planet #%d at %d %d %d, temperature class = %d", + pn, x, y, z, planet->temperature_class ); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + planet->temperature_class = n; + + data_was_modified = TRUE; + } + } + } + else if (strcasecmp (argument[next_arg], "gv") == 0) + { + printf ("For planet #%d at %d %d %d, gravity = %d", + pn, x, y, z, planet->gravity); + + if (++next_arg < num_arguments) + { + if (isdigit (argument[next_arg][0])) + { + n = atol (argument[next_arg++]); + printf (", changed to %ld", n); + + planet->gravity = n; + + data_was_modified = TRUE; + } + } + } + else + { + fprintf (stderr, "\n\tInvalid argument: '%s'!\n\n", argument[next_arg]); + exit (-1); + } + + printf (".\n"); + + if (next_arg < num_arguments) goto next_item; + + if (data_was_modified) save_planet_data (); + + free (planet_base); + + exit (0); +} + + + +get_species () + +{ + int species_fd; + + long n, num_bytes; + + char filename[16]; + + + species = &spec_data[species_index]; + + /* Open the species data file. */ + sprintf (filename, "sp%02d.dat\0", species_number); + species_fd = open (filename, 0); + if (species_fd < 0) + { + fprintf (stderr, "\n\tInvalid species number!\n\n"); + exit (-1); + } + + /* Read in species data. */ + num_bytes = read (species_fd, species, sizeof(struct species_data)); + if (num_bytes != sizeof(struct species_data)) + { + fprintf (stderr, "\n\tCannot read species record in file '%s'!\n\n", + filename); + exit (-1); + } + + /* Allocate enough memory for all namplas. */ + num_bytes = ((long) species->num_namplas) * sizeof (struct nampla_data); + nampla_base = (struct nampla_data *) malloc (num_bytes); + if (nampla_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for nampla data!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + num_bytes = (long) species->num_namplas * sizeof (struct nampla_data); + n = read (species_fd, nampla_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read nampla data into memory!\n\n"); + exit (-1); + } + + if (species->num_ships > 0) + { + /* Allocate enough memory for all ships. */ + num_bytes = ((long) species->num_ships) * sizeof (struct ship_data); + ship_base = (struct ship_data *) malloc (num_bytes); + if (ship_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for ship data!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + num_bytes = (long) species->num_ships * sizeof (struct ship_data); + n = read (species_fd, ship_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read ship data into memory!\n\n"); + exit (-1); + } + } + + close (species_fd); +} + + + +save_species () + +{ + int species_fd; + + long n, num_bytes; + + char filename[16]; + + + /* Create the new species data file. */ + sprintf (filename, "sp%02d.dat\0", species_number); + species_fd = creat (filename, 0600); + if (species_fd < 0) + { + fprintf (stderr, "\n Cannot create new version of file '%s'!\n", + filename); + exit (-1); + } + + /* Write species data. */ + num_bytes = write (species_fd, species, sizeof(struct species_data)); + if (num_bytes != sizeof(struct species_data)) + { + fprintf (stderr, "\n\tCannot write species record to file '%s'!\n\n", + filename); + exit (-1); + } + + /* Write nampla data. */ + num_bytes = (long) species->num_namplas * sizeof (struct nampla_data); + n = write (species_fd, nampla_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot write nampla data to disk!\n\n"); + exit (-1); + } + + if (species->num_ships > 0) + { + /* Write ship data. */ + num_bytes = (long) species->num_ships * sizeof (struct ship_data); + n = write (species_fd, ship_base, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot write ship data to disk!\n\n"); + exit (-1); + } + } + + close (species_fd); +} + + + +/* Get a class abbreviation and return TECH_ID, ITEM_CLASS, SHIP_CLASS, + PLANET_ID, SPECIES_ID or ALLIANCE_ID as appropriate, or UNKNOWN if it + cannot be identified. Also, set "abbr_type" to this value. If it is + TECH_ID, ITEM_CLASS or SHIP_CLASS, "abbr_index" will contain the + abbreviation index. If it is a ship, "tonnage" will contain tonnage/10,000, + and "sub_light" will be TRUE or FALSE. (Tonnage value returned is based + ONLY on abbreviation.) */ + +int get_class_abbr (arg) + +char *arg; + +{ + int i; + + char *digit_start; + + + abbr_type = UNKNOWN; + + if (! isalnum (*arg)) return UNKNOWN; + input_abbr[0] = toupper(*arg); + ++arg; + + if (! isalnum (*arg)) return UNKNOWN; + input_abbr[1] = toupper(*arg); + ++arg; + + input_abbr[2] = '\0'; + + /* Check for IDs that are followed by one or more digits or letters. */ + i = 2; + digit_start = arg; + while (isalnum (*arg)) + { + input_abbr[i++] = *arg++; + input_abbr[i] = '\0'; + } + + /* Check tech ID. */ + for (i = 0; i < 6; i++) + { + if (strcmp(input_abbr, tech_abbr[i]) == 0) + { + abbr_index = i; + abbr_type = TECH_ID; + return abbr_type; + } + } + + /* Check item abbreviations. */ + for (i = 0; i < MAX_ITEMS; i++) + { + if (strcmp(input_abbr, item_abbr[i]) == 0) + { + abbr_index = i; + abbr_type = ITEM_CLASS; + return abbr_type; + } + } + + /* Check ship abbreviations. */ + for (i = 0; i < NUM_SHIP_CLASSES; i++) + { + if (strncmp(input_abbr, ship_abbr[i], 2) == 0) + { + arg = digit_start; + abbr_index = i; + tonnage = ship_tonnage[i]; + if (i == TR) + { + tonnage = 0; + while (isdigit(*arg)) + { + tonnage = (10 * tonnage) + (*arg - '0'); + ++arg; + } + } + + if (toupper(*arg) == 'S') + { + sub_light = TRUE; + ++arg; + } + else + sub_light = FALSE; + + if (isalnum (*arg)) break; /* Garbage. */ + + abbr_type = SHIP_CLASS; + return abbr_type; + } + } + + /* Check for planet name. */ + if (strcmp(input_abbr, "PL") == 0) + { + abbr_type = PLANET_ID; + return abbr_type; + } + + /* Check for species name. */ + if (strcmp(input_abbr, "SP") == 0) + { + abbr_type = SPECIES_ID; + return abbr_type; + } + + abbr_type = UNKNOWN; + return abbr_type; +} + + + + +/* This routine will return a pointer to a string containing a complete + ship name, including its orbital/landed status and age. If global + variable "truncate_name" is TRUE, then orbital/landed status and age + will not be included. */ + +int truncate_name = FALSE; +int ignore_field_distorters = FALSE; + +char full_ship_id[64]; + +char *ship_name (ship) + +struct ship_data *ship; + +{ + int effective_age, status, ship_is_distorted; + + char temp[16]; + + + if (ship->item_quantity[FD] == ship->tonnage) + ship_is_distorted = TRUE; + else + ship_is_distorted = FALSE; + + if (ship->status == ON_SURFACE) ship_is_distorted = FALSE; + + if (ignore_field_distorters) ship_is_distorted = FALSE; + + if (ship_is_distorted) + { + if (ship->class == TR) + sprintf (full_ship_id, "%s%d ???\0", ship_abbr[ship->class], + ship->tonnage); + else if (ship->class == BA) + sprintf (full_ship_id, "BAS ???\0"); + else + sprintf (full_ship_id, "%s ???\0", ship_abbr[ship->class]); + } + else if (ship->class == TR) + { + sprintf (full_ship_id, "%s%d%s %s\0", + ship_abbr[ship->class], ship->tonnage, ship_type[ship->type], + ship->name); + } + else + { + sprintf (full_ship_id, "%s%s %s\0", + ship_abbr[ship->class], ship_type[ship->type], ship->name); + } + + if (truncate_name) return &full_ship_id[0]; + + strcat (full_ship_id, " ("); + + effective_age = ship->age; + if (effective_age < 0) effective_age = 0; + + if (! ship_is_distorted) + { + if (ship->status != UNDER_CONSTRUCTION) + { + /* Do age. */ + sprintf (temp, "A%d,\0", effective_age); + strcat (full_ship_id, temp); + } + } + + status = ship->status; + if (ship->pn == 0) status = IN_DEEP_SPACE; /* For combat only. */ + switch (status) + { + case UNDER_CONSTRUCTION: + sprintf (temp, "C\0"); + break; + case IN_ORBIT: + sprintf (temp, "O%d\0", ship->pn); + break; + case ON_SURFACE: + sprintf (temp, "L%d\0", ship->pn); + break; + case IN_DEEP_SPACE: + sprintf (temp, "D\0"); + break; + case FORCED_JUMP: + sprintf (temp, "FJ\0"); + break; + case JUMPED_IN_COMBAT: + sprintf (temp, "WD\0"); + break; + default: + sprintf (temp, "***???***\0"); + fprintf (stderr, "\n\tWARNING!!! Internal error in subroutine 'ship_name'\n\n"); + } + + strcat (full_ship_id, temp); + + if (ship->type == STARBASE) + { + sprintf (temp, ",%ld tons\0", 10000L * (long) ship->tonnage); + strcat (full_ship_id, temp); + } + + strcat (full_ship_id, ")"); + + return &full_ship_id[0]; +} diff --git a/src/ShowGalaxy.c b/src/ShowGalaxy.c new file mode 100644 index 0000000..9582bf9 --- /dev/null +++ b/src/ShowGalaxy.c @@ -0,0 +1,119 @@ + +/* This program will display a crude ASCII map of the galaxy intended to + show the gamemaster the relative positions of home planets, ideal colonies + and all other star systems. The gamemaster should run this program after + running NewGalaxy to make sure that the distribution is not too lopsided. + If it is, run NewGalaxy again until satisfied. In the display, "H" stands + for ideal home planet, "C" stands for ideal colony, and "S" is used for + all other stars. */ + + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number, star_here[MAX_DIAMETER][MAX_DIAMETER]; + +struct galaxy_data galaxy; + +extern struct star_data *star_base; +extern struct planet_data *planet_base; + +extern int num_stars, num_planets; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, n, x, y, z, galactic_diameter, star_index, special; + + long size, star_data_size, planet_data_size; + + struct star_data *star; + struct planet_data *planet; + + /* Check for valid command line. */ + if (argc != 1) + { + fprintf (stderr, "\n\tUsage: ShowGalaxy\n\n"); + exit (-1); + } + + /* Get all the raw data. */ + get_galaxy_data (); + get_star_data (); + get_planet_data (); + + galactic_diameter = 2 * galaxy.radius; + + /* For each star, set corresponding element of star_here[] to index + into star array. */ + for (x = 0; x < galactic_diameter; x++) /* Initialize array. */ + for (y = 0; y < galactic_diameter; y++) + star_here[x][y] = -1; + + star = star_base; + for (star_index = 0; star_index < num_stars; star_index++) + { + x = star->x; + y = star->y; + star_here[x][y] = star_index; + ++star; + } + + for (i = 0; i < galactic_diameter; i++) + printf ("-"); + printf ("\n"); + + /* Outermost loop will control y-coordinates. */ + for (y = galactic_diameter - 1; y >= 0; y--) + { + /* Innermost loop will control x-coordinate. */ + for (x = 0; x <= galactic_diameter; x++) + { + if (x == galactic_diameter) + { + printf ("|\n"); + continue; + } + + star_index = star_here[x][y]; + if (star_index == -1) + { + printf (" "); + continue; + } + + star = star_base; + star += star_index; + + planet = planet_base + (long) star->planet_index; + for (i = 0; i < star->num_planets; i++) + { + special = planet->special; + if (special != 0) break; + + ++planet; + } + + switch (special) + { + case 0: printf ("S"); break; + case 1: printf ("H"); break; + case 2: printf ("C"); break; + default: printf ("%d", planet->special); + } + } + } + + for (i = 0; i < galactic_diameter; i++) + printf ("-"); + printf ("\n"); + + /* Clean up and exit. */ + exit (0); +} diff --git a/src/Stats.c b/src/Stats.c new file mode 100644 index 0000000..f65a5fb --- /dev/null +++ b/src/Stats.c @@ -0,0 +1,335 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +int species_number; + +long power (); + +char input_line[128]; /* Not actually used. */ + + +struct galaxy_data galaxy; +struct planet_data *planet, *home_planet; +struct species_data *species; +struct nampla_data *nampla_base, *nampla; +struct ship_data *ship_base, *ship; + +extern struct planet_data *planet_base; + + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, j, m, n, nampla_index, ship_index, num_ships, avg_tech_level, + all_tech_level[6], n_species, n_warships, n_starbases, + n_transports, avg_pop_pl, n_pop_pl, ls_needed, num_yards, + production_penalty, fleet_percent_cost, num_pop_planets, + min_starbases, max_starbases, min_warships, max_warships, + min_transports, max_transports, min_tech_level[6], + max_tech_level[6], min_pop_pl, max_pop_pl, ntr, nba, nwa, + n_yards, min_yards, max_yards, avg_yards; + + long total_production, raw_material_units, production_capacity, + total_tonnage, total_offensive_power, total_defensive_power, + avg_production, all_production, avg_warship_tons, + all_warship_tons, avg_starbase_tons, all_starbase_tons, + avg_transport_tons, all_transport_tons, n1, n2, n3, + min_production, max_production; + + short tons; + + + /* Check for valid command line. */ + if (argc != 1) + { + fprintf (stderr, "\n\tUsage: Stats\n\n"); + exit (0); + } + + /* Get all necessary data. */ + get_galaxy_data (); + get_planet_data (); + get_species_data (); + + /* Initialize data. */ + n_species = 0; + all_production = 0; + min_production = 1000000000; + max_production = 0; + all_warship_tons = 0; + all_starbase_tons = 0; + all_transport_tons = 0; + n_warships = 0; + min_warships = 32000; + max_warships = 0; + n_starbases = 0; + min_starbases = 32000; + max_starbases = 0; + n_transports = 0; + min_transports = 32000; + max_transports = 0; + n_pop_pl = 0; + min_pop_pl = 32000; + max_pop_pl = 0; + n_yards = 0; + min_yards = 32000; + max_yards = 0; + for (i = 0; i < 6; i++) + { + all_tech_level[i] = 0; + min_tech_level[i] = 32000; + max_tech_level[i] = 0; + } + + /* Print header. */ + printf ("SP Species Tech Levels Total Num Num Num Offen. Defen.\n"); + printf (" # Name MI MA ML GV LS BI Prod. Pls Shps Yrds Power Power\n"); + printf ("-------------------------------------------------------------------------------\n"); + + /* Main loop. For each species, take appropriate action. */ + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + if (! data_in_memory[species_number - 1]) continue; + + ++n_species; + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + /* Get fleet maintenance cost. */ + fleet_percent_cost = species->fleet_percent_cost; + + if (fleet_percent_cost > 10000) fleet_percent_cost = 10000; + + /* Print species data. */ + printf ("%2d", species_number); + printf (" %-15.15s", species->name); + + for (i = 0; i < 6; i++) + { + printf ("%4d", species->tech_level[i]); + all_tech_level[i] += (int) species->tech_level[i]; + if (species->tech_level[i] < min_tech_level[i]) + min_tech_level[i] = species->tech_level[i]; + if (species->tech_level[i] > max_tech_level[i]) + max_tech_level[i] = species->tech_level[i]; + } + + /* Get stats for namplas. */ + total_production = 0; + total_defensive_power = 0; + num_yards = 0; + num_pop_planets = 0; + home_planet = planet_base + (int) nampla_base->planet_index; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->pn == 99) continue; + + num_yards += nampla->shipyards; + n_yards += nampla->shipyards; + + planet = planet_base + (int) nampla->planet_index; + + raw_material_units = + (10L * (long) species->tech_level[MI] * (long) nampla->mi_base) + / (long) planet->mining_difficulty; + + production_capacity = + ((long) species->tech_level[MA] * (long) nampla->ma_base) / 10L; + + ls_needed = life_support_needed (species, home_planet, planet); + + if (ls_needed == 0) + production_penalty = 0; + else + production_penalty = (100 * ls_needed) / species->tech_level[LS]; + + raw_material_units + -= (production_penalty * raw_material_units) / 100; + + raw_material_units + = (((long) planet->econ_efficiency * raw_material_units) + 50) / 100; + + production_capacity + -= (production_penalty * production_capacity) / 100; + + production_capacity + = (((long) planet->econ_efficiency * production_capacity) + 50) / 100; + + if (nampla->status & MINING_COLONY) + n1 = (2 * raw_material_units) / 3; + else if (nampla->status & RESORT_COLONY) + n1 = (2 * production_capacity) / 3; + else + n1 = (production_capacity > raw_material_units) + ? raw_material_units : production_capacity; + + n2 = ((fleet_percent_cost * n1) + 5000) / 10000; + n3 = n1 - n2; + total_production += n3; + + tons = nampla->item_quantity[PD]/200; + if (tons < 1 && nampla->item_quantity[PD] > 0) tons = 1; + total_defensive_power += power (tons); + + if (nampla->status & POPULATED) + { + ++n_pop_pl; + ++num_pop_planets; + } + } + + printf ("%7ld%4d", total_production, num_pop_planets); + + if (total_production < min_production) min_production = total_production; + if (total_production > max_production) max_production = total_production; + + if (num_pop_planets < min_pop_pl) min_pop_pl = num_pop_planets; + if (num_pop_planets > max_pop_pl) max_pop_pl = num_pop_planets; + + if (num_yards < min_yards) min_yards = num_yards; + if (num_yards > max_yards) max_yards = num_yards; + + all_production += total_production; + + /* Get stats for ships. */ + num_ships = 0; + ntr = 0; nba = 0; nwa = 0; + total_tonnage = 0; + total_offensive_power = 0; + ship = ship_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) continue; + + if (ship->status == UNDER_CONSTRUCTION) continue; + + ++num_ships; + total_tonnage += (long) ship->tonnage; + + if (ship->type == STARBASE) + { + total_defensive_power += power (ship->tonnage); + all_starbase_tons += (long) ship->tonnage; + ++n_starbases; ++nba; + } + else if (ship->class == TR) + { + all_transport_tons += (long) ship->tonnage; + ++n_transports; ++ntr; + } + else + { + if (ship->type == SUB_LIGHT) + total_defensive_power += power (ship->tonnage); + else + total_offensive_power += power (ship->tonnage); + all_warship_tons += (long) ship->tonnage; + ++n_warships; ++nwa; + } + } + + if (nwa < min_warships ) min_warships = nwa; + if (nwa > max_warships ) max_warships = nwa; + + if (nba < min_starbases ) min_starbases = nba; + if (nba > max_starbases ) max_starbases = nba; + + if (ntr < min_transports ) min_transports = ntr; + if (ntr > max_transports ) max_transports = ntr; + + total_offensive_power += + ((long) species->tech_level[ML] * total_offensive_power) / 50; + + total_defensive_power += + ((long) species->tech_level[ML] * total_defensive_power) / 50; + + if (species->tech_level[ML] == 0) + { + total_defensive_power = 0; + total_offensive_power = 0; + } + + total_offensive_power /= 10; + total_defensive_power /= 10; + + printf ("%5d", num_ships); + printf ("%5d", num_yards); + printf ("%8ld%8ld\n", total_offensive_power, total_defensive_power); + } + + m = n_species / 2; + printf ("\n"); + for (i = 0; i < 6; i++) + { + avg_tech_level = (all_tech_level[i] + m) / n_species; + printf ("Average %s tech level = %d (min = %d, max = %d)\n", + tech_name[i], avg_tech_level, min_tech_level[i], max_tech_level[i]); + } + + i = ((10* n_warships) + m) / n_species; + printf ("\nAverage number of warships per species = %d.%d (min = %d, max = %d)\n", + i/10, i%10, min_warships, max_warships); + + if (n_warships == 0) n_warships = 1; + avg_warship_tons = (10000L * all_warship_tons) / n_warships; + avg_warship_tons = 1000L * ((avg_warship_tons + 500L) / 1000L); + printf ("Average warship size = %s tons\n", commas (avg_warship_tons)); + + avg_warship_tons = (10000L * all_warship_tons) / n_species; + avg_warship_tons = 1000L * ((avg_warship_tons + 500L) / 1000L); + printf ("Average total warship tonnage per species = %s tons\n", + commas (avg_warship_tons)); + + i = ((10 * n_starbases) + m) / n_species; + printf ("\nAverage number of starbases per species = %d.%d (min = %d, max = %d)\n", + i/10, i%10, min_starbases, max_starbases); + + if (n_starbases == 0) n_starbases = 1; + avg_starbase_tons = (10000L * all_starbase_tons) / n_starbases; + avg_starbase_tons = 1000L * ((avg_starbase_tons + 500L) / 1000L); + printf ("Average starbase size = %s tons\n", commas (avg_starbase_tons)); + + avg_starbase_tons = (10000L * all_starbase_tons) / n_species; + avg_starbase_tons = 1000L * ((avg_starbase_tons + 500L) / 1000L); + printf ("Average total starbase tonnage per species = %s tons\n", + commas (avg_starbase_tons)); + + i = ((10 * n_transports) + m) / n_species; + printf ("\nAverage number of transports per species = %d.%d (min = %d, max = %d)\n", + i/10, i%10, min_transports, max_transports); + + if (n_transports == 0) n_transports = 1; + avg_transport_tons = (10000L * all_transport_tons) / n_transports; + avg_transport_tons = 1000L * ((avg_transport_tons + 500L) / 1000L); + printf ("Average transport size = %s tons\n", commas (avg_transport_tons)); + + avg_transport_tons = (10000L * all_transport_tons) / n_species; + avg_transport_tons = 1000L * ((avg_transport_tons + 500L) / 1000L); + printf ("Average total transport tonnage per species = %s tons\n", + commas (avg_transport_tons)); + + avg_yards = ((10 * n_yards) + m) / n_species; + printf ("\nAverage number of shipyards per species = %d.%d (min = %d, max = %d)\n", + avg_yards/10, avg_yards%10, min_yards, max_yards); + + avg_pop_pl = ((10 * n_pop_pl) + m) / n_species; + printf ("\nAverage number of populated planets per species = %d.%d (min = %d, max = %d)\n", + avg_pop_pl/10, avg_pop_pl%10, min_pop_pl, max_pop_pl); + + avg_production = (all_production + m) / n_species; + printf ("Average total production per species = %ld (min = %ld, max = %ld)\n", + avg_production, min_production, max_production); +} diff --git a/src/TurnNumber.c b/src/TurnNumber.c new file mode 100644 index 0000000..2b1383c --- /dev/null +++ b/src/TurnNumber.c @@ -0,0 +1,29 @@ + +#define THIS_IS_MAIN + +#include "fh.h" + + +struct galaxy_data galaxy; + +main (argc, argv) + +int argc; +char *argv[]; + +{ + /* Check for valid command line. */ + if (argc != 1) + { + fprintf (stderr, "\n\tUsage: TurnNumber\n\n"); + exit (0); + } + + /* Get galaxy data. */ + get_galaxy_data (); + + /* Print the current turn number. */ + printf ("%d\n", galaxy.turn_number); + + exit (0); +} diff --git a/src/add_tran.c b/src/add_tran.c new file mode 100644 index 0000000..321e28b --- /dev/null +++ b/src/add_tran.c @@ -0,0 +1,61 @@ + +/* The following routine will append an interspecies transaction to the file + interspecies.dat. */ + + +#include "fh.h" + + +int trans_fd; +int num_transactions = 0; + + +extern int first_pass; + + +add_transaction (transaction) + +struct trans_data *transaction; + + +{ + long num_bytes; + + + if (first_pass) return; + + + /* If the file is not yet open, open it for appending. */ + if (num_transactions == 0) + { + /* Open for writing. */ + trans_fd = open ("interspecies.dat", 1); + + if (trans_fd < 0) + { + /* File does not exist. Create it. */ + trans_fd = creat ("interspecies.dat", 0600); + if (trans_fd < 0) + { + fprintf (stderr, "\n\tCannot create file interspecies.dat!\n\n"); + exit (-1); + } + } + else + { + /* Position to end-of-file for appending. */ + num_bytes = lseek (trans_fd, 0L, 2); + num_transactions = num_bytes / sizeof(struct trans_data); + } + } + + /* Write transaction to file. */ + num_bytes = write (trans_fd, transaction, sizeof(struct trans_data)); + if (num_bytes != sizeof(struct trans_data)) + { + fprintf (stderr, "\n\tCannot write transaction to file interspecies.dat!\n\n"); + exit (-1); + } + + ++num_transactions; +} diff --git a/src/combat.h b/src/combat.h new file mode 100644 index 0000000..ed48634 --- /dev/null +++ b/src/combat.h @@ -0,0 +1,73 @@ + +#define MAX_BATTLES 50 + /* Maximum number of battle locations for all players. */ + +#define MAX_SHIPS 200 + /* Maximum number of ships at a single battle. */ + +#define MAX_ENGAGE_OPTIONS 20 + /* Maximum number of engagement options that a player may specify + for a single battle. */ + + +struct battle_data +{ + char x, y, z, num_species_here; + char spec_num[MAX_SPECIES]; + char summary_only[MAX_SPECIES]; + char transport_withdraw_age[MAX_SPECIES]; + char warship_withdraw_age[MAX_SPECIES]; + char fleet_withdraw_percentage[MAX_SPECIES]; + char haven_x[MAX_SPECIES]; + char haven_y[MAX_SPECIES]; + char haven_z[MAX_SPECIES]; + char special_target[MAX_SPECIES]; + char hijacker[MAX_SPECIES]; + char can_be_surprised[MAX_SPECIES]; + char enemy_mine[MAX_SPECIES][MAX_SPECIES]; + char num_engage_options[MAX_SPECIES]; + char engage_option[MAX_SPECIES][MAX_ENGAGE_OPTIONS]; + char engage_planet[MAX_SPECIES][MAX_ENGAGE_OPTIONS]; + long ambush_amount[MAX_SPECIES]; +}; + +/* Types of combatants. */ +#define SHIP 1 +#define NAMPLA 2 +#define GENOCIDE_NAMPLA 3 +#define BESIEGED_NAMPLA 4 + +/* Types of special targets. */ +#define TARGET_WARSHIPS 1 +#define TARGET_TRANSPORTS 2 +#define TARGET_STARBASES 3 +#define TARGET_PDS 4 + +/* Types of actions. */ +#define DEFENSE_IN_PLACE 0 +#define DEEP_SPACE_DEFENSE 1 +#define PLANET_DEFENSE 2 +#define DEEP_SPACE_FIGHT 3 +#define PLANET_ATTACK 4 +#define PLANET_BOMBARDMENT 5 +#define GERM_WARFARE 6 +#define SIEGE 7 + +/* Special types. */ +#define NON_COMBATANT 1 + +struct action_data +{ + int num_units_fighting; + int fighting_species_index[MAX_SHIPS]; + int num_shots[MAX_SHIPS]; + int shots_left[MAX_SHIPS]; + long weapon_damage[MAX_SHIPS]; + long shield_strength[MAX_SHIPS]; + long shield_strength_left[MAX_SHIPS]; + long original_age_or_PDs[MAX_SHIPS]; + long bomb_damage[MAX_SHIPS]; + char surprised[MAX_SHIPS]; + char unit_type[MAX_SHIPS]; + char *fighting_unit[MAX_SHIPS]; +}; diff --git a/src/combat_utils.c b/src/combat_utils.c new file mode 100644 index 0000000..a09e455 --- /dev/null +++ b/src/combat_utils.c @@ -0,0 +1,94 @@ + +#include + + +/* Look-up table for ship defensive/offensive power uses ship->tonnage + as an index. Each value is equal to 100 * (ship->tonnage)^1.2. The + 'power' subroutine uses recursion to calculate values for tonnages + over 100. */ +short ship_power[101] = {0, /* Zeroth element not used. */ + 100, 230, 374, 528, 690, 859, 1033, 1213, 1397, 1585, + 1777, 1973, 2171, 2373, 2578, 2786, 2996, 3209, 3424, 3641, + 3861, 4082, 4306, 4532, 4759, 4988, 5220, 5452, 5687, 5923, + 6161, 6400, 6641, 6883, 7127, 7372, 7618, 7866, 8115, 8365, + 8617, 8870, 9124, 9379, 9635, 9893, 10151, 10411, 10672, 10934, + 11197, 11461, 11725, 11991, 12258, 12526, 12795, 13065, 13336, 13608, + 13880, 14154, 14428, 14703, 14979, 15256, 15534, 15813, 16092, 16373, + 16654, 16936, 17218, 17502, 17786, 18071, 18356, 18643, 18930, 19218, + 19507, 19796, 20086, 20377, 20668, 20960, 21253, 21547, 21841, 22136, + 22431, 22727, 23024, 23321, 23619, 23918, 24217, 24517, 24818, 25119 }; + +long power (tonnage) + +short tonnage; + +{ + long result; + short t1, t2; + + if (tonnage > 4068) + { + fprintf (stderr, + "\n\n\tLong integer overflow will occur in call to 'power(tonnage)'!\n"); + fprintf (stderr, "\t\tActual call is power(%d).\n\n", tonnage); + exit (-1); + } + + if (tonnage <= 100) + result = ship_power[tonnage]; + else + { + /* Tonnage is not in table. Break it up into two halves and get + approximate result = 1.149 * (x1 + x2), using recursion if + necessary. */ + t1 = tonnage/2; t2 = tonnage - t1; + result = 1149L * (power(t1) + power(t2)) / 1000L; + } + + return result; +} + + +extern char input_line[]; + +extern FILE *log_file; + +battle_error (species_number) + +int species_number; + +{ + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing BATTLE command!\n"); + return; +} + + +bad_species () +{ + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name!\n"); + return; +} + + + +bad_argument () +{ + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid argument in command.\n"); + return; +} + + + +bad_coordinates () +{ + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid coordinates in command.\n"); + return; +} diff --git a/src/cons_op.c b/src/cons_op.c new file mode 100644 index 0000000..dad9ce3 --- /dev/null +++ b/src/cons_op.c @@ -0,0 +1,38 @@ + +#include "fh.h" +#include "combat.h" + + +int num_combat_options; +char combat_option[1000], combat_location[1000]; + + +consolidate_option (option, location) + +char option, location; + +{ + int i; + + + /* Only attack options go in list. */ + if (option < DEEP_SPACE_FIGHT) + return; + + /* Make sure pre-requisites are already in the list. Bombardment, and + germ warfare must follow a successful planet attack. */ + if (option > PLANET_ATTACK) + consolidate_option (PLANET_ATTACK, location); + + /* Check if option and location are already in list. */ + for (i = 0; i < num_combat_options; i++) + { + if (option == combat_option[i] && location == combat_location[i]) + return; + } + + /* Add new option to list. */ + combat_option[num_combat_options] = option; + combat_location[num_combat_options] = location; + ++num_combat_options; +} diff --git a/src/dis_ship.c b/src/dis_ship.c new file mode 100644 index 0000000..843aedc --- /dev/null +++ b/src/dis_ship.c @@ -0,0 +1,37 @@ + +#include "fh.h" + + +extern struct species_data *species; +extern struct nampla_data *nampla_base; + + + +int disbanded_ship (ship) + +struct ship_data *ship; + +{ + int nampla_index; + + struct nampla_data *nampla; + + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != ship->pn) continue; + if ((nampla->status & DISBANDED_COLONY) == 0) continue; + if (ship->type != STARBASE && ship->status == IN_ORBIT) continue; + + /* This ship is either on the surface of a disbanded colony or is + a starbase orbiting a disbanded colony. */ + return TRUE; + } + + return FALSE; +} diff --git a/src/do_all.c b/src/do_all.c new file mode 100644 index 0000000..3b037a2 --- /dev/null +++ b/src/do_all.c @@ -0,0 +1,85 @@ + +#include "fh.h" + + +extern int first_pass, doing_production, g_spec_number, + num_transactions, species_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla_base; +extern struct ship_data *ship_base; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_ALLIES_command () + +{ + int i, n, contact_word_number, contact_bit_number; + + long cost, contact_mask; + + struct species_data *alien; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (stderr, "\n\n\tMissing PRODUCTION order!\n\n"); + exit (-1); + } + + /* Get name of alien species. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in ALLIES command.\n"); + return; + } + + /* Check if we've met this species. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You cannot use ALLIES on a species you haven't met.\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = 200; + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Log the result. */ + log_string (" A project to determine the potential allies of SP "); + log_string (g_spec_name); + log_string (" was funded at a cost of "); + log_long (cost); + log_string (".\n"); + + if (first_pass) return; + + /* Create an appropriate interspecies transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = ALLIES_ORDER; + transaction[n].number1 = species_number; + transaction[n].number2 = g_spec_number; + strcpy (transaction[n].name1, species->name); + strcpy (transaction[n].name2, g_spec_name); +} diff --git a/src/do_ally.c b/src/do_ally.c new file mode 100644 index 0000000..b67956c --- /dev/null +++ b/src/do_ally.c @@ -0,0 +1,56 @@ + +#include "fh.h" + + +extern int abbr_type, g_spec_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; + + +do_ALLY_command () + +{ + int i, array_index, bit_number; + + long bit_mask; + + + /* Get name of species that is being declared an ally. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing argument in ALLY command.\n"); + return; + } + + /* Get array index and bit mask. */ + array_index = (g_spec_number - 1) / 32; + bit_number = (g_spec_number - 1) % 32; + bit_mask = 1 << bit_number; + + /* Check if we've met this species and make sure it is not an enemy. */ + if ((species->contact[array_index] & bit_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't declare alliance with a species you haven't met.\n"); + return; + } + + /* Set/clear the appropriate bit. */ + species->ally[array_index] |= bit_mask; /* Set ally bit. */ + species->enemy[array_index] &= ~bit_mask; /* Clear enemy bit. */ + + /* Log the result. */ + log_string (" Alliance was declared with "); + if (bit_mask == 0) + log_string ("ALL species"); + else + { + log_string ("SP "); + log_string (g_spec_name); + } + log_string (".\n"); +} diff --git a/src/do_amb.c b/src/do_amb.c new file mode 100644 index 0000000..9310f68 --- /dev/null +++ b/src/do_amb.c @@ -0,0 +1,66 @@ + +#include "fh.h" + + +extern int doing_production, first_pass, abbr_index; +extern long value, balance; +extern char input_line[256]; +extern FILE *log_file; +extern struct nampla_data *nampla; + + +do_AMBUSH_command () +{ + int n, status; + + long cost; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get amount to spend. */ + status = get_value (); + if (status == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing amount.\n"); + return; + } + if (value == 0) value = balance; + if (value == 0) return; + cost = value; + + /* Check if planet is under siege. */ + if (nampla->siege_eff != 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Besieged planet cannot ambush!\n"); + return; + } + + /* Check if sufficient funds are available. */ + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Increment amount spent on ambush. */ + nampla->use_on_ambush += cost; + + /* Log transaction. */ + log_string (" Spent "); + log_long (cost); + log_string (" in preparation for an ambush.\n"); +} diff --git a/src/do_base.c b/src/do_base.c new file mode 100644 index 0000000..e48f224 --- /dev/null +++ b/src/do_base.c @@ -0,0 +1,288 @@ + +#include "fh.h" + + +extern int abbr_type, abbr_index, species_number, + species_index, ship_index, num_stars; +extern long value; +extern char input_line[256], original_line[256], original_name[32], + upper_name[32], *input_line_pointer; + +extern FILE *log_file; +extern struct star_data *star_base, *star; +extern struct species_data *species; +extern struct nampla_data *nampla; +extern struct ship_data *ship, *ship_base; + + +do_BASE_command () + +{ + int i, n, found, su_count, original_count, item_class, name_length, + unused_ship_available, new_tonnage, max_tonnage, new_starbase, + source_is_a_planet, age_new; + + char x, y, z, pn, upper_ship_name[32], *original_line_pointer; + + struct nampla_data *source_nampla; + struct ship_data *source_ship, *starbase, *unused_ship; + + + /* Get number of starbase units to use. */ + i = get_value (); + if (i == 0) + value = 0; + else + { + /* Make sure value is meaningful. */ + if (value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid SU count in BASE command.\n"); + return; + } + } + su_count = value; + original_count = su_count; + + /* Get source of starbase units. */ + original_line_pointer = input_line_pointer; + if (! get_transfer_point ()) + { + input_line_pointer = original_line_pointer; + fix_separator (); /* Check for missing comma or tab. */ + if (! get_transfer_point ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid source location in BASE command.\n"); + return; + } + } + + /* Make sure everything makes sense. */ + if (abbr_type == SHIP_CLASS) + { + source_is_a_planet = FALSE; + source_ship = ship; + + if (source_ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s is still under construction!\n", + ship_name (source_ship)); + return; + } + + if (source_ship->status == FORCED_JUMP + || source_ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + if (su_count == 0) su_count = source_ship->item_quantity[SU]; + if (su_count == 0) return; + if (source_ship->item_quantity[SU] < su_count) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s does not enough starbase units!\n", + ship_name (source_ship)); + return; + } + + x = source_ship->x; y = source_ship->y; z = source_ship->z; + pn = source_ship->pn; + } + else /* Source is a planet. */ + { + source_is_a_planet = TRUE; + source_nampla = nampla; + + if (su_count == 0) su_count = source_nampla->item_quantity[SU]; + if (su_count == 0) return; + if (source_nampla->item_quantity[SU] < su_count) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! PL %s does not have enough starbase units!\n", + source_nampla -> name); + return; + } + + x = source_nampla->x; y = source_nampla->y; z = source_nampla->z; + pn = source_nampla->pn; + } + + /* Get starbase name. */ + if (get_class_abbr () != SHIP_CLASS || abbr_index != BA) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid starbase name.\n"); + return; + } + name_length = get_name (); + + /* Search all ships for name. */ + found = FALSE; + ship = ship_base - 1; + unused_ship_available = FALSE; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) + { + unused_ship_available = TRUE; + unused_ship = ship; + continue; + } + + /* Make upper case copy of ship name. */ + for (i = 0; i < 32; i++) + upper_ship_name[i] = toupper(ship->name[i]); + + /* Compare names. */ + if (strcmp (upper_ship_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (found) + { + if (ship->type != STARBASE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship name already in use.\n"); + return; + } + + if (ship->x != x || ship->y != y || ship->z != z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Starbase units and starbase are not at same X Y Z.\n"); + return; + } + starbase = ship; + new_starbase = FALSE; + } + else + { + if (unused_ship_available) + starbase = unused_ship; + else + { + /* Make sure we have enough memory for new starbase. */ + if (num_new_ships[species_index] == NUM_EXTRA_SHIPS) + { + fprintf (stderr, "\n\n\tInsufficient memory for new starbase!\n\n"); + exit (-1); + } + ++num_new_ships[species_index]; + starbase = ship_base + (int) species->num_ships; + ++species->num_ships; + delete_ship (starbase); /* Initialize everything to zero. */ + } + + /* Initialize non-zero data for new ship. */ + strcpy (starbase->name, original_name); + starbase->x = x; + starbase->y = y; + starbase->z = z; + starbase->pn = pn; + if (pn == 0) + starbase->status = IN_DEEP_SPACE; + else + starbase->status = IN_ORBIT; + starbase->type = STARBASE; + starbase->class = BA; + starbase->tonnage = 0; + starbase->age = -1; + starbase->remaining_cost = 0; + + /* Everything else was set to zero in above call to 'delete_ship'. */ + + new_starbase = TRUE; + } + + /* Make sure that starbase is not being built in the deep space section + of a star system .*/ + if (starbase->pn == 0) + { + star = star_base - 1; + for (i = 0; i < num_stars; i++) + { + ++star; + + if (star->x != x) continue; + if (star->y != y) continue; + if (star->z != z) continue; + + if (star->num_planets < 1) break; + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Starbase cannot be built in deep space if there are planets available!\n"); + if (new_starbase) delete_ship (starbase); + return; + } + } + + /* Make sure species can build a starbase of this size. */ + max_tonnage = species->tech_level[MA] / 2; + new_tonnage = starbase->tonnage + su_count; + if (new_tonnage > max_tonnage && original_count == 0) + { + su_count = max_tonnage - starbase->tonnage; + if (su_count < 1) + { + if (new_starbase) delete_ship (starbase); + return; + } + new_tonnage = starbase->tonnage + su_count; + } + + if (new_tonnage > max_tonnage) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Maximum allowable tonnage exceeded.\n"); + if (new_starbase) delete_ship (starbase); + return; + } + + /* Finish up and log results. */ + log_string (" "); + if (starbase->tonnage == 0) + { + log_string (ship_name (starbase)); + log_string (" was constructed.\n"); + } + else + { + starbase->age = /* Weighted average. */ + ((starbase->age * starbase->tonnage) - su_count) + /new_tonnage; + log_string ("Size of "); log_string (ship_name (starbase)); + log_string (" was increased to "); + log_string (commas (10000L * (long) new_tonnage)); + log_string (" tons.\n"); + } + + starbase->tonnage = new_tonnage; + + if (source_is_a_planet) + source_nampla->item_quantity[SU] -= su_count; + else + source_ship->item_quantity[SU] -= su_count; +} diff --git a/src/do_bat.c b/src/do_bat.c new file mode 100644 index 0000000..d875986 --- /dev/null +++ b/src/do_bat.c @@ -0,0 +1,877 @@ +#include "fh.h" +#include "combat.h" + + +int first_battle = TRUE; +int attacking_ML, defending_ML, deep_space_defense, + ambush_took_place; +char field_distorted[MAX_SPECIES], append_log[MAX_SPECIES], + make_enemy[MAX_SPECIES][MAX_SPECIES]; + + +extern int attacker_here, defender_here, logging_disabled, + strike_phase, prompt_gm; +extern int log_summary, num_combat_options; +extern int truncate_name, num_transactions; +extern int ignore_field_distorters; +extern char combat_option[1000], combat_location[1000]; +extern char x_attacked_y[MAX_SPECIES][MAX_SPECIES]; +extern FILE *log_file, *summary_file; +extern struct galaxy_data galaxy; +extern struct species_data *c_species[MAX_SPECIES]; +extern struct nampla_data *nampla_base, *c_nampla[MAX_SPECIES]; +extern struct ship_data *ship_base, *c_ship[MAX_SPECIES]; + + + +do_battle (bat) + +struct battle_data *bat; + +{ + int i, j, k, species_index, species_number, num_sp, save, + max_rounds, round_number, battle_here, fight_here, + unit_index, option_index, current_species, temp_status, + temp_pn, num_namplas, array_index, bit_number, first_action, + traitor_number, betrayed_number, betrayal, need_comma, + TRUE_value, do_withdraw_check_first; + + short identifiable_units[MAX_SPECIES], + unidentifiable_units[MAX_SPECIES]; + + long n, bit_mask; + + char x, y, z, where, option, filename[32], enemy, + enemy_num[MAX_SPECIES], log_line[256]; + + FILE *combat_log, *species_log; + + struct action_data act; + struct nampla_data *namp, *attacked_nampla; + struct ship_data *sh; + + + ambush_took_place = FALSE; + + /* Open log file for writing. */ + log_file = fopen ("combat.log", "w"); + if (log_file == NULL) + { + fprintf (stderr, "\n\tCannot open 'combat.log' for writing!\n\n"); + exit (-1); + } + + /* Open summary file for writing. */ + summary_file = fopen ("summary.log", "w"); + if (summary_file == NULL) + { + fprintf (stderr, "\n\tCannot open 'summary.log' for writing!\n\n"); + exit (-1); + } + log_summary = TRUE; + + /* Get data for all species present at this battle. */ + num_sp = bat->num_species_here; + for (species_index = 0; species_index < num_sp; ++species_index) + { + species_number = bat->spec_num[species_index]; + c_species[species_index] = &spec_data[species_number - 1]; + c_nampla[species_index] = namp_data[species_number - 1]; + c_ship[species_index] = ship_data[species_number - 1]; + if (data_in_memory[species_number - 1]) + data_modified[species_number - 1] = TRUE; + else + { + fprintf (stderr, "\n\tData for species #%d is needed but is not available!\n\n", + species_number); + exit (-1); + } + + /* Determine number of identifiable and unidentifiable units present. */ + identifiable_units[species_index] = 0; + unidentifiable_units[species_index] = 0; + + namp = c_nampla[species_index] - 1; + for (i = 0; i < c_species[species_index]->num_namplas; i++) + { + ++namp; + + if (namp->x != bat->x) continue; + if (namp->y != bat->y) continue; + if (namp->z != bat->z) continue; + + if (namp->status & POPULATED) ++identifiable_units[species_index]; + } + + sh = c_ship[species_index] - 1; + for (i = 0; i < c_species[species_index]->num_ships; i++) + { + ++sh; + + if (sh->x != bat->x) continue; + if (sh->y != bat->y) continue; + if (sh->z != bat->z) continue; + if (sh->status == UNDER_CONSTRUCTION) continue; + if (sh->status == JUMPED_IN_COMBAT) continue; + if (sh->status == FORCED_JUMP) continue; + + sh->dest_x = 0; /* Not yet exposed. */ + sh->dest_y = 100; /* Shields at 100%. */ + + if (sh->item_quantity[FD] == sh->tonnage) + ++unidentifiable_units[species_index]; + else + ++identifiable_units[species_index]; + } + + if (identifiable_units[species_index] > 0 + || unidentifiable_units[species_index] == 0) + field_distorted[species_index] = FALSE; + else + field_distorted[species_index] = TRUE; + } + + /* Start log of what's happening. */ + if (strike_phase) + log_string ("\nStrike log:\n"); + else + log_string ("\nCombat log:\n"); + first_battle = FALSE; + + log_string ("\n Battle orders were received for sector "); log_int (bat->x); + log_string (", "); log_int (bat->y); log_string (", "); log_int (bat->z); + log_string (". The following species are present:\n\n"); + + /* Convert enemy_mine array from a list of species numbers to an array + of TRUE/FALSE values whose indices are: + + [species_index1][species_index2] + + such that the value will be TRUE if #1 mentioned #2 in an ATTACK + or HIJACK command. The actual TRUE value will be 1 for ATTACK or + 2 for HIJACK. */ + + for (species_index = 0; species_index < num_sp; ++species_index) + { + /* Make copy of list of enemies. */ + for (i = 0; i < MAX_SPECIES; i++) + { + enemy_num[i] = bat->enemy_mine[species_index][i]; + bat->enemy_mine[species_index][i] = FALSE; + } + + for (i = 0; i < MAX_SPECIES; i++) + { + enemy = enemy_num[i]; + if (enemy == 0) break; /* No more enemies in list. */ + + if (enemy < 0) + { + enemy = -enemy; + TRUE_value = 2; /* This is a hijacking. */ + } + else + TRUE_value = 1; /* This is a normal attack. */ + + /* Convert absolute species numbers to species indices that + have been assigned in the current battle. */ + for (j = 0; j < num_sp; j++) + { + if (enemy == bat->spec_num[j]) + bat->enemy_mine[species_index][j] = TRUE_value; + } + } + } + + /* For each species that has been mentioned in an attack order, check + if it can be surprised. A species can only be surprised if it has + not given a BATTLE order and if it is being attacked ONLY by one + or more ALLIES. */ + for (species_index = 0; species_index < num_sp; ++species_index) + { + j = bat->spec_num[species_index] - 1; + array_index = j / 32; + bit_number = j % 32; + bit_mask = 1 << bit_number; + + for (i = 0; i < num_sp; i++) + { + if (i == species_index) continue; + + if (! bat->enemy_mine[species_index][i]) continue; + + if (field_distorted[species_index]) + { + /* Attacker is field-distorted. Surprise not possible. */ + bat->can_be_surprised[i] = FALSE; + continue; + } + + if ((c_species[i]->ally[array_index] & bit_mask)) + betrayal = TRUE; + else + betrayal = FALSE; + + if (betrayal) + { + /* Someone is being attacked by an ALLY. */ + traitor_number = bat->spec_num[species_index]; + betrayed_number = bat->spec_num[i]; + make_enemy[betrayed_number-1][traitor_number-1] = betrayed_number; + auto_enemy (traitor_number, betrayed_number); + } + + if (! bat->can_be_surprised[i]) continue; + + if (! betrayal) /* At least one attacker is not an ally. */ + bat->can_be_surprised[i] = FALSE; + } + } + + /* For each species that has been mentioned in an attack order, see if + there are other species present that have declared it as an ALLY. + If so, have the attacker attack the other species and vice-versa. */ + for (species_index = 0; species_index < num_sp; ++species_index) + { + for (i = 0; i < num_sp; i++) + { + if (i == species_index) continue; + + if (! bat->enemy_mine[species_index][i]) continue; + + j = bat->spec_num[i] - 1; + array_index = j / 32; + bit_number = j % 32; + bit_mask = 1 << bit_number; + + for (k = 0; k < num_sp; k++) + { + if (k == species_index) continue; + if (k == i) continue; + + if (c_species[k]->ally[array_index] & bit_mask) + { + /* Make sure it's not already set (it may already be set + for HIJACK and we don't want to accidentally change + it to ATTACK). */ + if (! bat->enemy_mine[species_index][k]) + bat->enemy_mine[species_index][k] = TRUE; + if (! bat->enemy_mine[k][species_index]) + bat->enemy_mine[k][species_index] = TRUE; + } + } + } + } + + /* If a species did not give a battle order and is not the target of an + attack, set can_be_surprised flag to a special value. */ + for (species_index = 0; species_index < num_sp; ++species_index) + { + if (! bat->can_be_surprised[species_index]) continue; + + bat->can_be_surprised[species_index] = 55; + + for (i = 0; i < num_sp; i++) + { + if (i == species_index) continue; + + if (! bat->enemy_mine[i][species_index]) continue; + + bat->can_be_surprised[species_index] = TRUE; + + break; + } + } + + /* List combatants. */ + for (species_index = 0; species_index < num_sp; ++species_index) + { + species_number = bat->spec_num[species_index]; + + log_string (" SP "); + if (field_distorted[species_index]) + log_int (distorted (species_number)); + else + log_string (c_species[species_index]->name); + if (bat->can_be_surprised[species_index]) + log_string (" does not appear to be ready for combat.\n"); + else + log_string (" is mobilized and ready for combat.\n"); + } + + /* Check if a declared enemy is being ambushed. */ + for (i = 0; i < num_sp; i++) + { + namp = c_nampla[i] - 1; + num_namplas = c_species[i]->num_namplas; + bat->ambush_amount[i] = 0; + for (j = 0; j < num_namplas; j++) + { + ++namp; + + if (namp->x != bat->x) continue; + if (namp->y != bat->y) continue; + if (namp->z != bat->z) continue; + + bat->ambush_amount[i] += namp->use_on_ambush; + } + + if (bat->ambush_amount[i] == 0) continue; + + for (j = 0; j < num_sp; j++) + if (bat->enemy_mine[i][j]) + do_ambush (i, bat); + } + + /* For all species that specified enemies, make the feeling mutual. */ + for (i = 0; i < num_sp; i++) + for (j = 0; j < num_sp; j++) + if (bat->enemy_mine[i][j]) + { + /* Make sure it's not already set (it may already be set for + HIJACK and we don't want to accidentally change it to + ATTACK). */ + if (! bat->enemy_mine[j][i]) bat->enemy_mine[j][i] = TRUE; + } + + /* Create a sequential list of combat options. First check if a + deep space defense has been ordered. If so, then make sure that + first option is DEEP_SPACE_FIGHT. */ + num_combat_options = 0; + for (species_index = 0; species_index < num_sp; ++species_index) + { + for (i = 0; i < bat->num_engage_options[species_index]; i++) + { + option = bat->engage_option[species_index][i]; + if (option == DEEP_SPACE_DEFENSE) + { + consolidate_option (DEEP_SPACE_FIGHT, 0); + goto consolidate; + } + } + } + + consolidate: + for (species_index = 0; species_index < num_sp; ++species_index) + { + for (i = 0; i < bat->num_engage_options[species_index]; i++) + { + option = bat->engage_option[species_index][i]; + where = bat->engage_planet[species_index][i]; + consolidate_option (option, where); + } + } + + /* If ships are given unconditional withdraw orders, they will always have + time to escape if fighting occurs first in a different part of the + sector. The flag "do_withdraw_check_first" will be set only after the + first round of combat. */ + do_withdraw_check_first = FALSE; + + /* Handle each combat option. */ + battle_here = FALSE; + first_action = TRUE; + for (option_index = 0; option_index < num_combat_options; option_index++) + { + option = combat_option[option_index]; + where = combat_location[option_index]; + + /* Fill action arrays with data about ships taking part in current + action. */ + fight_here = fighting_params (option, where, bat, &act); + + /* Check if a fight will take place here. */ + if (! fight_here) continue; + + /* See if anyone is taken by surprise. */ + if (! battle_here) + { + /* Combat is just starting. */ + for (species_index = 0; species_index < num_sp; ++species_index) + { + species_number = bat->spec_num[species_index]; + + if (bat->can_be_surprised[species_index] == 55) continue; + + if (bat->can_be_surprised[species_index]) + { + log_string ("\n SP "); + if (field_distorted[species_index]) + log_int (distorted (species_number)); + else + log_string (c_species[species_index]->name); + log_string (" is taken by surprise!\n"); + } + } + } + + battle_here = TRUE; + + /* Clear out can_be_surprised array. */ + for (i = 0; i < MAX_SPECIES; i++) + bat->can_be_surprised[i] = FALSE; + + /* Determine maximum number of rounds. */ + max_rounds = 10000; /* Something ridiculously large. */ + if (option == DEEP_SPACE_FIGHT && attacking_ML > 0 + && defending_ML > 0 + && deep_space_defense) + { + /* This is the initial deep space fight and the defender wants the + fight to remain in deep space for as long as possible. */ + if (defending_ML > attacking_ML) + max_rounds = defending_ML - attacking_ML; + else + max_rounds = 1; + } + else if (option == PLANET_BOMBARDMENT) + { + /* To determine the effectiveness of the bombardment, we will + simulate ten rounds of combat and add up the damage. */ + max_rounds = 10; + } + else if (option == GERM_WARFARE || option == SIEGE) + { + /* We just need to see who is attacking whom and get the number + of germ warfare bombs being used. */ + max_rounds = 1; + } + + /* Log start of action. */ + if (where == 0) + log_string ("\n The battle begins in deep space, outside the range of planetary defenses...\n"); + else if (option == PLANET_ATTACK) + { + log_string ("\n The battle "); + if (first_action) + log_string ("begins"); + else + log_string ("moves"); + log_string (" within range of planet #"); + log_int (where); + log_string ("...\n"); + } + else if (option == PLANET_BOMBARDMENT) + { + log_string ("\n Bombardment of planet #"); + log_int (where); + log_string (" begins...\n"); + } + else if (option == GERM_WARFARE) + { + log_string ("\n Germ warfare commences against planet #"); + log_int (where); + log_string ("...\n"); + } + else if (option == SIEGE) + { + log_string ("\n Siege of planet #"); + log_int (where); + log_string (" is now in effect...\n\n"); + goto do_combat; + } + + /* List combatants. */ + truncate_name = FALSE; + log_string ("\n Units present:"); + current_species = -1; + for (unit_index = 0; unit_index < act.num_units_fighting; unit_index++) + { + if (act.fighting_species_index[unit_index] != current_species) + { + /* Display species name. */ + i = act.fighting_species_index[unit_index]; + log_string ("\n SP "); + species_number = bat->spec_num[i]; + if (field_distorted[i]) + log_int (distorted (species_number)); + else + log_string (c_species[i]->name); + log_string (": "); + current_species = i; + need_comma = FALSE; + } + + if (act.unit_type[unit_index] == SHIP) + { + sh = (struct ship_data *) act.fighting_unit[unit_index]; + temp_status = sh->status; + temp_pn = sh->pn; + if (option == DEEP_SPACE_FIGHT) + { + sh->status = IN_DEEP_SPACE; + sh->pn = 0; + } + else + { + sh->status = IN_ORBIT; + sh->pn = where; + } + ignore_field_distorters = ! field_distorted[current_species]; + if (sh->special != NON_COMBATANT) + { + if (need_comma) log_string (", "); + log_string (ship_name (sh)); + need_comma = TRUE; + } + ignore_field_distorters = FALSE; + sh->status = temp_status; + sh->pn = temp_pn; + } + else + { + namp = (struct nampla_data *) act.fighting_unit[unit_index]; + if (need_comma) log_string (", "); + log_string ("PL "); + log_string (namp->name); + need_comma = TRUE; + } + } + log_string ("\n\n"); + +do_combat: + + /* Long names are not necessary for the rest of the action. */ + truncate_name = TRUE; + + /* Do combat rounds. Stop if maximum count is reached, or if combat + does not occur when do_round() is called. */ + + round_number = 1; + + log_summary = FALSE; /* do_round() and the routines that it calls + will set this for important stuff. */ + + if (option == PLANET_BOMBARDMENT || option == GERM_WARFARE + || option == SIEGE) + logging_disabled = TRUE; /* Disable logging during simulation. */ + + while (round_number <= max_rounds) + { + if (do_withdraw_check_first) withdrawal_check (bat, &act); + + if (! do_round (option, round_number, bat, &act)) break; + + if (! do_withdraw_check_first) withdrawal_check (bat, &act); + + do_withdraw_check_first = TRUE; + + regenerate_shields (&act); + + ++round_number; + } + + log_summary = TRUE; + logging_disabled = FALSE; + + if (round_number == 1) + { + log_string (" ...But it seems that the attackers had nothing to attack!\n"); + continue; + } + + if (option == PLANET_BOMBARDMENT || option == GERM_WARFARE) + { + for (unit_index = 0; unit_index < act.num_units_fighting; unit_index++) + { + if (act.unit_type[unit_index] == GENOCIDE_NAMPLA) + { + attacked_nampla = (struct nampla_data *) + act.fighting_unit[unit_index]; + j = act.fighting_species_index[unit_index]; + for (i = 0; i < num_sp; i++) + { + if (x_attacked_y[i][j]) + { + species_number = bat->spec_num[i]; + log_string (" SP "); + if (field_distorted[i]) + log_int (distorted (species_number)); + else + log_string (c_species[i]->name); + log_string (" bombards SP "); + log_string (c_species[j]->name); + log_string (" on PL "); + log_string (attacked_nampla->name); + log_string (".\n"); + + if (option == GERM_WARFARE) + do_germ_warfare (i, j, unit_index, bat, &act); + } + } + + /* Determine results of bombardment. */ + if (option == PLANET_BOMBARDMENT) + do_bombardment (unit_index, &act); + } + } + } + else if (option == SIEGE) + do_siege (bat, &act); + + truncate_name = FALSE; + + first_action = FALSE; + } + + if (! battle_here) + { + if (bat->num_species_here == 1) + log_string (" But there was no one to fight with!\n"); + else if (! ambush_took_place) + log_string (" But no one was willing to throw the first punch!\n"); + } + + /* Close combat log and append it to the log files of all species + involved in this battle. */ + if (prompt_gm) + printf ("\n End of battle in sector %d, %d, %d.\n", bat->x, + bat->y, bat->z); + fprintf (log_file, "\n End of battle in sector %d, %d, %d.\n", bat->x, + bat->y, bat->z); + fprintf (summary_file, "\n End of battle in sector %d, %d, %d.\n", + bat->x, bat->y, bat->z); + fclose (log_file); + fclose (summary_file); + + for (species_index = 0; species_index < num_sp; ++species_index) + { + species_number = bat->spec_num[species_index]; + + /* Open combat log file for reading. */ + if (bat->summary_only[species_index]) + combat_log = fopen ("summary.log", "r"); + else + combat_log = fopen ("combat.log", "r"); + + if (combat_log == NULL) + { + fprintf (stderr, "\n\tCannot open combat log for reading!\n\n"); + exit (-1); + } + + /* Open a temporary species log file for appending. */ + sprintf (filename, "sp%02d.temp.log\0", species_number); + species_log = fopen (filename, "a"); + if (species_log == NULL) + { + fprintf (stderr, "\n\tCannot open '%s' for appending!\n\n", filename); + exit (-1); + } + + /* Copy combat log to temporary species log. */ + while (fgets(log_line, 256, combat_log) != NULL) + fputs (log_line, species_log); + + fclose (species_log); + fclose (combat_log); + + append_log[species_number - 1] = TRUE; + + /* Get rid of ships that were destroyed. */ + if (! data_modified[species_number - 1]) continue; + sh = c_ship[species_index] - 1; + for (i = 0; i < c_species[species_index]->num_ships; i++) + { + ++sh; + + if (sh->age < 50) continue; + if (sh->pn == 99) continue; + if (sh->x != bat->x) continue; + if (sh->y != bat->y) continue; + if (sh->z != bat->z) continue; + if (sh->status == UNDER_CONSTRUCTION) continue; + + delete_ship (sh); + } + } +} + + + +do_ambush (ambushing_species_index, bat) + +int ambushing_species_index; +struct battle_data *bat; + +{ + int i, j, n, num_sp, ambushed_species_index, num_ships, + age_increment, species_number, old_truncate_name; + + long friendly_tonnage, enemy_tonnage; + + struct ship_data *sh; + + + + /* Get total ambushing tonnage. */ + friendly_tonnage = 0; + num_ships = c_species[ambushing_species_index]->num_ships; + sh = c_ship[ambushing_species_index] - 1; + for (i = 0; i < num_ships; i++) + { + ++sh; + + if (sh->pn == 99) continue; + if (sh->x != bat->x) continue; + if (sh->y != bat->y) continue; + if (sh->z != bat->z) continue; + if (sh->class != TR && sh->class != BA) + friendly_tonnage += sh->tonnage; + } + + /* Determine which species are being ambushed and get total enemy + tonnage. */ + num_sp = bat->num_species_here; + enemy_tonnage = 0; + for (ambushed_species_index = 0; ambushed_species_index < num_sp; ++ambushed_species_index) + { + if (! bat->enemy_mine[ambushing_species_index][ambushed_species_index]) + continue; + + /* This species is being ambushed. Get total effective tonnage. */ + num_ships = c_species[ambushed_species_index]->num_ships; + sh = c_ship[ambushed_species_index] - 1; + for (i = 0; i < num_ships; i++) + { + ++sh; + + if (sh->pn == 99) continue; + if (sh->x != bat->x) continue; + if (sh->y != bat->y) continue; + if (sh->z != bat->z) continue; + if (sh->class == TR) + enemy_tonnage += sh->tonnage; + else + enemy_tonnage += 10 * sh->tonnage; + } + } + + /* Determine the amount of aging that will be added to each ambushed + ship. */ + if (enemy_tonnage == 0) return; + age_increment = (10L * bat->ambush_amount[ambushing_species_index]) + / enemy_tonnage; + age_increment = (friendly_tonnage * age_increment) / enemy_tonnage; + + ambush_took_place = TRUE; + + if (age_increment < 1) + { + log_string ("\n SP "); + log_string (c_species[ambushing_species_index]->name); + log_string (" attempted an ambush, but the ambush was completely ineffective!\n"); + return; + } + + /* Age each ambushed ship. */ + for (ambushed_species_index = 0; ambushed_species_index < num_sp; ++ambushed_species_index) + { + if (! bat->enemy_mine[ambushing_species_index][ambushed_species_index]) + continue; + + log_string ("\n SP "); + species_number = bat->spec_num[ambushed_species_index]; + if (field_distorted[ambushed_species_index]) + log_int (distorted (species_number)); + else + log_string (c_species[ambushed_species_index]->name); + + log_string (" was ambushed by SP "); + log_string (c_species[ambushing_species_index]->name); + log_string ("!\n"); + + num_ships = c_species[ambushed_species_index]->num_ships; + sh = c_ship[ambushed_species_index] - 1; + for (i = 0; i < num_ships; i++) + { + ++sh; + + if (sh->pn == 99) continue; + if (sh->x != bat->x) continue; + if (sh->y != bat->y) continue; + if (sh->z != bat->z) continue; + + sh->age += age_increment; + if (sh->arrived_via_wormhole) sh->age += age_increment; + + if (sh->age > 49) + { + old_truncate_name = truncate_name; + truncate_name = TRUE; + + log_string (" "); + log_string (ship_name (sh)); + if (field_distorted[ambushed_species_index]) + { + log_string (" = "); + log_string (c_species[ambushed_species_index]->name); + log_char (' '); + n = sh->item_quantity[FD]; + sh->item_quantity[FD] = 0; + log_string (ship_name (sh)); + sh->item_quantity[FD] = n; + } + n = 0; + for (j = 0; j < MAX_ITEMS; j++) + { + if (sh->item_quantity[j] > 0) + { + if (n++ == 0) + log_string (" (cargo: "); + else + log_char (','); + log_int ((int) sh->item_quantity[j]); + log_char (' '); + log_string (item_abbr[j]); + } + } + if (n > 0) log_char (')'); + + log_string (" was destroyed in the ambush!\n"); + + truncate_name = old_truncate_name; + } + } + } +} + + + +/* This routine will find all species that have declared alliance with + both a traitor and betrayed species. It will then set a flag to indicate + that their allegiance should be changed from ALLY to ENEMY. */ + +auto_enemy (traitor_species_number, betrayed_species_number) + +int traitor_species_number, betrayed_species_number; + +{ + int traitor_array_index, betrayed_array_index, bit_number, + species_index; + + long traitor_bit_mask, betrayed_bit_mask; + + + traitor_array_index = (traitor_species_number - 1) / 32; + bit_number = (traitor_species_number - 1) % 32; + traitor_bit_mask = 1 << bit_number; + + betrayed_array_index = (betrayed_species_number - 1) / 32; + bit_number = (betrayed_species_number - 1) % 32; + betrayed_bit_mask = 1 << bit_number; + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if ((spec_data[species_index].ally[traitor_array_index] + & traitor_bit_mask) == 0) continue; + if ((spec_data[species_index].ally[betrayed_array_index] + & betrayed_bit_mask) == 0) continue; + if ((spec_data[species_index].contact[traitor_array_index] + & traitor_bit_mask) == 0) continue; + if ((spec_data[species_index].contact[betrayed_array_index] + & betrayed_bit_mask) == 0) continue; + + make_enemy[species_index][traitor_species_number - 1] = betrayed_species_number; + } +} diff --git a/src/do_bomb.c b/src/do_bomb.c new file mode 100644 index 0000000..1959870 --- /dev/null +++ b/src/do_bomb.c @@ -0,0 +1,191 @@ + +#include "fh.h" +#include "combat.h" + + +long power (); + + +extern struct planet_data *planet_base; +extern struct species_data *c_species[MAX_SPECIES]; +extern struct nampla_data *c_nampla[MAX_SPECIES]; +extern struct ship_data *c_ship[MAX_SPECIES]; + + +do_bombardment (unit_index, act) + +int unit_index; +struct action_data *act; + +{ + int i, new_mi, new_ma, defending_species; + + long n, total_bomb_damage, CS_bomb_damage, new_pop, + initial_base, total_pop, percent_damage; + + struct planet_data *planet; + struct nampla_data *attacked_nampla; + struct ship_data *sh; + + + attacked_nampla = (struct nampla_data *) act->fighting_unit[unit_index]; + planet = planet_base + (long) attacked_nampla->planet_index; + + initial_base = attacked_nampla->mi_base + attacked_nampla->ma_base; + total_pop = initial_base; + + if (attacked_nampla->item_quantity[CU] > 0) total_pop += 1; + + if (total_pop < 1) + { + log_string (" The planet is completely uninhabited. There is nothing to bomb!\n"); + return; + } + + /* Total damage done by ten strike cruisers (ML = 50) in ten rounds + is 100 x 4 x the power value for a single ship. To eliminate the + chance of overflow, the algorithm has been carefully chosen. */ + + CS_bomb_damage = 400 * power (ship_tonnage[CS]); + /* Should be 400 * 4759 = 1,903,600. */ + + total_bomb_damage = act->bomb_damage[unit_index]; + + /* Keep about 2 significant digits. */ + while (total_bomb_damage > 1000) + { + total_bomb_damage /= 10; + CS_bomb_damage /= 10; + } + + if (CS_bomb_damage == 0) + percent_damage = 101; + else + percent_damage = + ((total_bomb_damage * 250000L) / CS_bomb_damage) / total_pop; + + if (percent_damage > 100) percent_damage = 101; + + new_mi = attacked_nampla->mi_base + - (percent_damage * attacked_nampla->mi_base)/100; + + new_ma = attacked_nampla->ma_base + - (percent_damage * attacked_nampla->ma_base)/100; + + new_pop = attacked_nampla->pop_units + - (percent_damage * attacked_nampla->pop_units)/100; + + if (new_mi == attacked_nampla->mi_base + && new_ma == attacked_nampla->ma_base + && new_pop == attacked_nampla->pop_units) + { + log_string (" Damage due to bombardment was insignificant.\n"); + return; + } + + defending_species = act->fighting_species_index[unit_index]; + if (attacked_nampla->status & HOME_PLANET) + { + n = attacked_nampla->mi_base + attacked_nampla->ma_base; + if (c_species[defending_species]->hp_original_base < n) + c_species[defending_species]->hp_original_base = n; + } + + if (new_mi <= 0 && new_ma <= 0 && new_pop <= 0) + { + log_string (" Everyone and everything was completely wiped out!\n"); + + attacked_nampla->mi_base = 0; + attacked_nampla->ma_base = 0; + attacked_nampla->pop_units = 0; + attacked_nampla->siege_eff = 0; + attacked_nampla->shipyards = 0; + attacked_nampla->hiding = 0; + attacked_nampla->hidden = 0; + attacked_nampla->use_on_ambush = 0; + + /* Reset status. */ + if (attacked_nampla->status & HOME_PLANET) + attacked_nampla->status = HOME_PLANET; + else + attacked_nampla->status = COLONY; + + for (i = 0; i < MAX_ITEMS; i++) + attacked_nampla->item_quantity[i] = 0; + + /* Delete any ships that were under construction on the planet. */ + sh = c_ship[defending_species] - 1; + for (i = 0; i < c_species[defending_species]->num_ships; i++) + { + ++sh; + + if (sh->x != attacked_nampla->x) continue; + if (sh->y != attacked_nampla->y) continue; + if (sh->z != attacked_nampla->z) continue; + if (sh->pn != attacked_nampla->pn) continue; + + delete_ship (sh); + } + + return; + } + + log_string (" Mining base of PL "); + log_string (attacked_nampla->name); + log_string (" went from "); + log_int (attacked_nampla->mi_base / 10); + log_char ('.'); + log_int (attacked_nampla->mi_base % 10); + log_string (" to "); + attacked_nampla->mi_base = new_mi; + log_int (new_mi / 10); + log_char ('.'); + log_int (new_mi % 10); + log_string (".\n"); + + log_string (" Manufacturing base of PL "); + log_string (attacked_nampla->name); + log_string (" went from "); + log_int (attacked_nampla->ma_base / 10); + log_char ('.'); + log_int (attacked_nampla->ma_base % 10); + log_string (" to "); + attacked_nampla->ma_base = new_ma; + log_int (new_ma / 10); + log_char ('.'); + log_int (new_ma % 10); + log_string (".\n"); + + attacked_nampla->pop_units = new_pop; + + for (i = 0; i < MAX_ITEMS; i++) + { + n = (percent_damage * attacked_nampla->item_quantity[i]) / 100; + if (n > 0) + { + attacked_nampla->item_quantity[i] -= n; + log_string (" "); log_long (n); log_char (' '); + log_string (item_name[i]); + if (n > 1) + log_string ("s were"); + else + log_string (" was"); + log_string (" destroyed.\n"); + } + } + + n = (percent_damage * (long) attacked_nampla->shipyards) / 100; + if (n > 0) + { + attacked_nampla->shipyards -= n; + log_string (" "); log_long (n); + log_string (" shipyard"); + if (n > 1) + log_string ("s were"); + else + log_string (" was"); + log_string (" also destroyed.\n"); + } + + check_population (attacked_nampla); +} diff --git a/src/do_build.c b/src/do_build.c new file mode 100644 index 0000000..9f55110 --- /dev/null +++ b/src/do_build.c @@ -0,0 +1,1037 @@ + +#include "fh.h" + + + +extern int nampla_index, ship_index, doing_production, tonnage, sub_light, + abbr_index, first_pass, species_number, species_index, + num_transactions, g_spec_number, abbr_type, shipyard_capacity; +extern long value, balance, EU_spending_limit; +extern char input_line[256], original_line[256], original_name[32], + upper_name[32], *input_line_pointer, *ship_name(); +extern FILE *log_file; + +extern struct species_data *species; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship_base, *ship; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_BUILD_command (continuing_construction, interspecies_construction) + +int continuing_construction, interspecies_construction; + +{ + int i, n, class, critical_tech, found, name_length, + siege_effectiveness, cost_given, new_ship, max_tonnage, + tonnage_increase, alien_number, cargo_on_board, + unused_nampla_available, unused_ship_available, capacity, + pop_check_needed, contact_word_number, contact_bit_number, + already_notified[MAX_SPECIES]; + + char upper_ship_name[32], *commas(), *src, *dest, + *original_line_pointer; + + long cost, cost_argument, unit_cost, num_items, pop_reduction, + premium, total_cost, original_num_items, contact_mask, + max_funds_available; + + struct species_data *recipient_species; + struct nampla_data *recipient_nampla, *unused_nampla, + *destination_nampla, *temp_nampla; + struct ship_data *recipient_ship, *unused_ship; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get ready if planet is under siege. */ + if (nampla->siege_eff < 0) + siege_effectiveness = -nampla->siege_eff; + else + siege_effectiveness = nampla->siege_eff; + + /* Get species name and make appropriate tests if this is an interspecies + construction order. */ + if (interspecies_construction) + { + original_line_pointer = input_line_pointer; + if (! get_species_name ()) + { + /* Check for missing comma or tab after species name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + if (! get_species_name ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid species name.\n"); + return; + } + } + recipient_species = &spec_data[g_spec_number - 1]; + + if (species->tech_level[MA] < 25) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! MA tech level must be at least 25 to do interspecies construction.\n"); + return; + } + + /* Check if we've met this species and make sure it is not an enemy. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! You can't do interspecies construction for a species you haven't met.\n"); + return; + } + if (species->enemy[contact_word_number] & contact_mask) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! You can't do interspecies construction for an ENEMY.\n"); + return; + } + } + + /* Get number of items to build. */ + i = get_value (); + + if (i == 0) + goto build_ship; /* Not an item. */ + num_items = value; + original_num_items = value; + + /* Get class of item. */ + class = get_class_abbr (); + + if (class != ITEM_CLASS || abbr_index == RM) + { + /* Players sometimes accidentally use "MI" for "IU" + or "MA" for "AU". */ + if (class == TECH_ID && abbr_index == MI) + abbr_index = IU; + else if (class == TECH_ID && abbr_index == MA) + abbr_index = AU; + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid item class.\n"); + return; + } + } + class = abbr_index; + + if (interspecies_construction) + { + if (class == PD || class == CU) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! You cannot build CUs or PDs for another species.\n"); + return; + } + } + + /* Make sure species knows how to build this item. */ + critical_tech = item_critical_tech[class]; + if (species->tech_level[critical_tech] < item_tech_requirment[class]) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Insufficient tech level to build item.\n"); + return; + } + + /* Get cost of item. */ + if (class == TP) /* Terraforming plant. */ + unit_cost = item_cost[class] / species->tech_level[critical_tech]; + else + unit_cost = item_cost[class]; + + if (num_items == 0) num_items = balance / unit_cost; + if (num_items == 0) return; + + /* Make sure item count is meaningful. */ + if (num_items < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Meaningless item count.\n"); + return; + } + + /* Make sure there is enough available population. */ + pop_reduction = 0; + if (class == CU || class == PD) + { + if (nampla->pop_units < num_items) + { + if (original_num_items == 0) + { + num_items = nampla->pop_units; + if (num_items == 0) return; + } + else + { + if (nampla->pop_units > 0) + { + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, + "! Insufficient available population units. Substituting %ld for %ld.\n", + nampla->pop_units, num_items); + num_items = nampla->pop_units; + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Insufficient available population units.\n"); + return; + } + } + } + pop_reduction = num_items; + } + + /* Calculate total cost and see if planet has enough money. */ +do_cost: + cost = num_items * unit_cost; + if (interspecies_construction) + premium = (cost + 9) / 10; + else + premium = 0; + + cost += premium; + + if (check_bounced (cost)) + { + if (interspecies_construction && original_num_items == 0) + { + --num_items; + if (num_items < 1) return; + goto do_cost; + } + + max_funds_available = species->econ_units; + if (max_funds_available > EU_spending_limit) + max_funds_available = EU_spending_limit; + max_funds_available += balance; + + num_items = max_funds_available / unit_cost; + if (interspecies_construction) num_items -= (num_items + 9) / 10; + + if (num_items > 0) + { + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, "! Insufficient funds. Substituting %ld for %ld.\n", + num_items, original_num_items); + goto do_cost; + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + } + + /* Update planet inventory. */ + nampla->item_quantity[class] += num_items; + nampla->pop_units -= pop_reduction; + + /* Log what was produced. */ + log_string (" "); log_long (num_items); + log_char (' '); log_string (item_name[class]); + + if (num_items > 1) + log_string ("s were"); + else + log_string (" was"); + + if (first_pass && class == PD && siege_effectiveness > 0) + { + log_string (" scheduled for production despite the siege.\n"); + return; + } + else + { + log_string (" produced"); + if (interspecies_construction) + { + log_string (" for SP "); + log_string (recipient_species->name); + } + } + + if (unit_cost != 1 || premium != 0) + { + log_string (" at a cost of "); + log_long (cost); + } + + /* Check if planet is under siege and if production of planetary + defenses was detected. */ + if (class == PD && rnd(100) <= siege_effectiveness) + { + log_string (". However, they were detected and destroyed by the besiegers!!!\n"); + nampla->item_quantity[PD] = 0; + + /* Make sure we don't notify the same species more than once. */ + for (i = 0; i < MAX_SPECIES; i++) already_notified[i] = FALSE; + + for (i = 0; i < num_transactions; i++) + { + /* Find out who is besieging this planet. */ + if (transaction[i].type != BESIEGE_PLANET) continue; + if (transaction[i].x != nampla->x) continue; + if (transaction[i].y != nampla->y) continue; + if (transaction[i].z != nampla->z) continue; + if (transaction[i].pn != nampla->pn) continue; + if (transaction[i].number2 != species_number) continue; + + alien_number = transaction[i].number1; + + if (already_notified[alien_number - 1]) continue; + + /* Define a 'detection' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = DETECTION_DURING_SIEGE; + transaction[n].value = 3; /* Construction of PDs. */ + strcpy (transaction[n].name1, nampla->name); + strcpy (transaction[n].name3, species->name); + transaction[n].number3 = alien_number; + + already_notified[alien_number - 1] = TRUE; + } + return; + } + + if (! interspecies_construction) + { + /* Get destination of transfer, if any. */ + pop_check_needed = FALSE; + temp_nampla = nampla; + found = get_transfer_point (); + destination_nampla = nampla; + nampla = temp_nampla; + if (! found) goto done_transfer; + + if (abbr_type == SHIP_CLASS) /* Destination is 'ship'. */ + { + if (ship->x != nampla->x + || ship->y != nampla->y + || ship->z != nampla->z + || ship->status == UNDER_CONSTRUCTION) goto done_transfer; + + if (ship->class == TR) + capacity = (10 + ((int) ship->tonnage / 2)) * (int) ship->tonnage; + else if (ship->class == BA) + capacity = 10 * ship->tonnage; + else + capacity = ship->tonnage; + + for (i = 0; i < MAX_ITEMS; i++) + capacity -= ship->item_quantity[i] * item_carry_capacity[i]; + + n = num_items; + if (num_items * item_carry_capacity[class] > capacity) + num_items = capacity / item_carry_capacity[class]; + + ship->item_quantity[class] += num_items; + nampla->item_quantity[class] -= num_items; + log_string (" and "); + if (n > num_items) + { + log_long (num_items); + log_string (" of them "); + } + if (num_items == 1) + log_string ("was"); + else + log_string ("were"); + log_string (" transferred to "); + log_string (ship_name(ship)); + + if (class == CU && num_items > 0) + { + if (nampla == nampla_base) + ship->loading_point = 9999; /* Home planet. */ + else + ship->loading_point = (nampla - nampla_base); + } + } + else /* Destination is 'destination_nampla'. */ + { + if (destination_nampla->x != nampla->x + || destination_nampla->y != nampla->y + || destination_nampla->z != nampla->z) goto done_transfer; + + if (nampla->siege_eff != 0) goto done_transfer; + if (destination_nampla->siege_eff != 0) goto done_transfer; + + destination_nampla->item_quantity[class] += num_items; + nampla->item_quantity[class] -= num_items; + log_string (" and transferred to PL "); + log_string (destination_nampla->name); + pop_check_needed = TRUE; + } + + done_transfer: + + log_string (".\n"); + + if (pop_check_needed) check_population (destination_nampla); + + return; + } + + log_string (".\n"); + + /* Check if recipient species has a nampla at this location. */ + found = FALSE; + unused_nampla_available = FALSE; + recipient_nampla = namp_data[g_spec_number - 1] - 1; + for (i = 0; i < recipient_species->num_namplas; i++) + { + ++recipient_nampla; + + if (recipient_nampla->pn == 99) + { + unused_nampla = recipient_nampla; + unused_nampla_available = TRUE; + } + + if (recipient_nampla->x != nampla->x) continue; + if (recipient_nampla->y != nampla->y) continue; + if (recipient_nampla->z != nampla->z) continue; + if (recipient_nampla->pn != nampla->pn) continue; + + found = TRUE; + break; + } + + if (! found) + { + /* Add new nampla to database for the recipient species. */ + if (unused_nampla_available) + recipient_nampla = unused_nampla; + else + { + ++num_new_namplas[species_index]; + if (num_new_namplas[species_index] > NUM_EXTRA_NAMPLAS) + { + fprintf (stderr, "\n\n\tInsufficient memory for new planet name in do_build.c!\n"); + exit (-1); + } + recipient_nampla = namp_data[g_spec_number - 1] + + recipient_species->num_namplas; + recipient_species->num_namplas += 1; + delete_nampla (recipient_nampla); /* Set everything to zero. */ + } + + /* Initialize new nampla. */ + strcpy (recipient_nampla->name, nampla->name); + recipient_nampla->x = nampla->x; + recipient_nampla->y = nampla->y; + recipient_nampla->z = nampla->z; + recipient_nampla->pn = nampla->pn; + recipient_nampla->planet_index = nampla->planet_index; + recipient_nampla->status = COLONY; + } + + /* Transfer the goods. */ + nampla->item_quantity[class] -= num_items; + recipient_nampla->item_quantity[class] += num_items; + data_modified[g_spec_number - 1] = TRUE; + + if (first_pass) return; + + /* Define transaction so that recipient will be notified. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = INTERSPECIES_CONSTRUCTION; + transaction[n].donor = species_number; + transaction[n].recipient = g_spec_number; + transaction[n].value = 1; /* Items, not ships. */ + transaction[n].number1 = num_items; + transaction[n].number2 = class; + transaction[n].number3 = cost; + strcpy (transaction[n].name1, species->name); + strcpy (transaction[n].name2, recipient_nampla->name); + + return; + + +build_ship: + + original_line_pointer = input_line_pointer; + if (continuing_construction) + { + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + } + + if (found) goto check_ship; + input_line_pointer = original_line_pointer; + } + + class = get_class_abbr (); + + if (class != SHIP_CLASS || tonnage < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship class.\n"); + return; + } + class = abbr_index; + + /* Get ship name. */ + name_length = get_name (); + if (name_length < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name.\n"); + return; + } + + /* Search all ships for name. */ + found = FALSE; + ship = ship_base - 1; + unused_ship_available = FALSE; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) + { + unused_ship_available = TRUE; + unused_ship = ship; + continue; + } + + /* Make upper case copy of ship name. */ + for (i = 0; i < 32; i++) + upper_ship_name[i] = toupper(ship->name[i]); + + /* Compare names. */ + if (strcmp (upper_ship_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + +check_ship: + + if (found) + { + /* Check if BUILD was accidentally used instead of CONTINUE. */ + if ((ship->status == UNDER_CONSTRUCTION || ship->type == STARBASE) + && ship->x == nampla->x && ship->y == nampla->y + && ship->z == nampla->z && ship->pn == nampla->pn) + continuing_construction = TRUE; + + if ((ship->status != UNDER_CONSTRUCTION && ship->type != STARBASE) + || (! continuing_construction)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship name already in use.\n"); + return; + } + + new_ship = FALSE; + } + else + { + /* If CONTINUE command was used, the player probably mis-spelled + the name. */ + if (continuing_construction) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name.\n"); + return; + } + + if (unused_ship_available) + ship = unused_ship; + else + { + /* Make sure we have enough memory for new ship. */ + if (num_new_ships[species_index] >= NUM_EXTRA_SHIPS) + { + if (num_new_ships[species_index] == 9999) return; + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, + "!!! You cannot build more than %d ships per turn!\n", + NUM_EXTRA_SHIPS); + num_new_ships[species_index] = 9999; + return; + } + new_ship = TRUE; + ship = ship_base + (int) species->num_ships; + delete_ship (ship); /* Initialize everything to zero. */ + } + + /* Initialize non-zero data for new ship. */ + strcpy (ship->name, original_name); + ship->x = nampla->x; + ship->y = nampla->y; + ship->z = nampla->z; + ship->pn = nampla->pn; + ship->status = UNDER_CONSTRUCTION; + if (class == BA) + { + ship->type = STARBASE; + ship->status = IN_ORBIT; + } + else if (sub_light) + ship->type = SUB_LIGHT; + else + ship->type = FTL; + ship->class = class; + ship->age = -1; + if (ship->type != STARBASE) ship->tonnage = tonnage; + ship->remaining_cost = ship_cost[class]; + if (ship->class == TR) + ship->remaining_cost = ship_cost[TR] * tonnage; + if (ship->type == SUB_LIGHT) + ship->remaining_cost = (3L * (long) ship->remaining_cost) / 4L; + ship->just_jumped = FALSE; + + /* Everything else was set to zero in above call to 'delete_ship'. */ + } + + /* Check if amount to spend was specified. */ + cost_given = get_value (); + cost = value; + cost_argument = value; + + if (cost_given) + { + if (interspecies_construction && (ship->type != STARBASE)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Amount to spend may not be specified.\n"); + return; + } + + if (cost == 0) + { + cost = balance; + if (ship->type == STARBASE) + { + if (cost % ship_cost[BA] != 0) + cost = ship_cost[BA] * (cost / ship_cost[BA]); + } + if (cost < 1) + { + if (new_ship) delete_ship (ship); + return; + } + } + + if (cost < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Amount specified is meaningless.\n"); + if (new_ship) delete_ship (ship); + return; + } + + if (ship->type == STARBASE) + { + if (cost % ship_cost[BA] != 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Amount spent on starbase must be multiple of %d.\n", + ship_cost[BA]); + if (new_ship) delete_ship (ship); + return; + } + } + } + else + { + if (ship->type == STARBASE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Amount to spend MUST be specified for starbase.\n"); + if (new_ship) delete_ship (ship); + return; + } + + cost = ship->remaining_cost; + } + + /* Make sure species can build a ship of this size. */ + max_tonnage = species->tech_level[MA] / 2; + if (ship->type == STARBASE) + { + tonnage_increase = cost/(long) ship_cost[BA]; + tonnage = ship->tonnage + tonnage_increase; + if (tonnage > max_tonnage && cost_argument == 0) + { + tonnage_increase = max_tonnage - ship->tonnage; + if (tonnage_increase < 1) return; + tonnage = ship->tonnage + tonnage_increase; + cost = tonnage_increase * (int) ship_cost[BA]; + } + } + + if (tonnage > max_tonnage) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Maximum allowable tonnage exceeded.\n"); + if (new_ship) delete_ship (ship); + return; + } + + /* Make sure species has gravitics technology if this is an FTL ship. */ + if (ship->type == FTL && species->tech_level[GV] < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Gravitics tech needed to build FTL ship!\n"); + if (new_ship) delete_ship (ship); + return; + } + + /* Make sure amount specified is not an overpayment. */ + if (ship->type != STARBASE && cost > ship->remaining_cost) + cost = ship->remaining_cost; + + /* Make sure planet has sufficient shipyards. */ + if (shipyard_capacity < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Shipyard capacity exceeded!\n"); + if (new_ship) delete_ship (ship); + return; + } + + /* Make sure there is enough money to pay for it. */ + premium = 0; + if (interspecies_construction) + { + if (ship->class == TR || ship->type == STARBASE) + total_cost = ship_cost[ship->class] * tonnage; + else + total_cost = ship_cost[ship->class]; + + if (ship->type == SUB_LIGHT) + total_cost = (3 * total_cost) / 4; + + premium = total_cost / 10; + if (total_cost % 10) ++premium; + } + + if (check_bounced (cost + premium)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + if (new_ship) delete_ship (ship); + return; + } + + --shipyard_capacity; + + /* Test if this is a starbase and if planet is under siege. */ + if (ship->type == STARBASE && siege_effectiveness > 0) + { + log_string (" Your attempt to build "); + log_string (ship_name (ship)); + log_string (" was detected by the besiegers and the starbase was destroyed!!!\n"); + + /* Make sure we don't notify the same species more than once. */ + for (i = 0; i < MAX_SPECIES; i++) already_notified[i] = FALSE; + + for (i = 0; i < num_transactions; i++) + { + /* Find out who is besieging this planet. */ + if (transaction[i].type != BESIEGE_PLANET) continue; + if (transaction[i].x != nampla->x) continue; + if (transaction[i].y != nampla->y) continue; + if (transaction[i].z != nampla->z) continue; + if (transaction[i].pn != nampla->pn) continue; + if (transaction[i].number2 != species_number) continue; + + alien_number = transaction[i].number1; + + if (already_notified[alien_number - 1]) continue; + + /* Define a 'detection' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = DETECTION_DURING_SIEGE; + transaction[n].value = 2; /* Construction of ship/starbase. */ + strcpy (transaction[n].name1, nampla->name); + strcpy (transaction[n].name2, ship_name(ship)); + strcpy (transaction[n].name3, species->name); + transaction[n].number3 = alien_number; + + already_notified[alien_number - 1] = TRUE; + } + + delete_ship (ship); + + return; + } + + /* Finish up and log results. */ + log_string (" "); + if (ship->type == STARBASE) + { + if (ship->tonnage == 0) + { + log_string (ship_name (ship)); + log_string (" was constructed"); + } + else + { + ship->age = /* Weighted average. */ + ((ship->age * ship->tonnage) - tonnage_increase) + /tonnage; + log_string ("Size of "); log_string (ship_name (ship)); + log_string (" was increased to "); + log_string (commas (10000L * (long) tonnage)); + log_string (" tons"); + } + + ship->tonnage = tonnage; + } + else + { + ship->remaining_cost -= cost; + if (ship->remaining_cost == 0) + { + ship->status = ON_SURFACE; /* Construction is complete. */ + if (continuing_construction) + { + if (first_pass && siege_effectiveness > 0) + log_string ("An attempt will be made to finish construction on "); + else + log_string ("Construction finished on "); + log_string (ship_name (ship)); + if (first_pass && siege_effectiveness > 0) + log_string (" despite the siege"); + } + else + { + if (first_pass && siege_effectiveness > 0) + log_string ("An attempt will be made to construct "); + log_string (ship_name (ship)); + if (first_pass && siege_effectiveness > 0) + log_string (" despite the siege"); + else + log_string (" was constructed"); + } + } + else + { + if (continuing_construction) + { + if (first_pass && siege_effectiveness > 0) + log_string ("An attempt will be made to continue construction on "); + else + log_string ("Construction continued on "); + log_string (ship_name (ship)); + if (first_pass && siege_effectiveness > 0) + log_string (" despite the siege"); + } + else + { + if (first_pass && siege_effectiveness > 0) + log_string ("An attempt will be made to start construction on "); + else + log_string ("Construction started on "); + log_string (ship_name (ship)); + if (first_pass && siege_effectiveness > 0) + log_string (" despite the siege"); + } + } + } + log_string (" at a cost of "); log_long (cost + premium); + + if (interspecies_construction) + { + log_string (" for SP "); + log_string (recipient_species->name); + } + + log_char ('.'); + + if (new_ship && (! unused_ship_available)) + { + ++num_new_ships[species_index]; + ++species->num_ships; + } + + /* Check if planet is under siege and if construction was detected. */ + if (! first_pass && rnd(100) <= siege_effectiveness) + { + log_string (" However, the work was detected by the besiegers and the ship was destroyed!!!"); + + /* Make sure we don't notify the same species more than once. */ + for (i = 0; i < MAX_SPECIES; i++) already_notified[i] = FALSE; + + for (i = 0; i < num_transactions; i++) + { + /* Find out who is besieging this planet. */ + if (transaction[i].type != BESIEGE_PLANET) continue; + if (transaction[i].x != nampla->x) continue; + if (transaction[i].y != nampla->y) continue; + if (transaction[i].z != nampla->z) continue; + if (transaction[i].pn != nampla->pn) continue; + if (transaction[i].number2 != species_number) continue; + + alien_number = transaction[i].number1; + + if (already_notified[alien_number - 1]) continue; + + /* Define a 'detection' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = DETECTION_DURING_SIEGE; + transaction[n].value = 2; /* Construction of ship/starbase. */ + strcpy (transaction[n].name1, nampla->name); + strcpy (transaction[n].name2, ship_name(ship)); + strcpy (transaction[n].name3, species->name); + transaction[n].number3 = alien_number; + + already_notified[alien_number - 1] = TRUE; + } + + /* Remove ship from inventory. */ + delete_ship (ship); + } + + log_char ('\n'); + + if (! interspecies_construction) return; + + /* Transfer any cargo on the ship to the planet. */ + cargo_on_board = FALSE; + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + { + nampla->item_quantity[i] += ship->item_quantity[i]; + ship->item_quantity[i] = 0; + cargo_on_board = TRUE; + } + } + if (cargo_on_board) + log_string (" Forgotten cargo on the ship was first transferred to the planet.\n"); + + /* Transfer the ship to the recipient species. */ + unused_ship_available = FALSE; + recipient_ship = ship_data[g_spec_number - 1]; + for (i = 0; i < recipient_species->num_ships; i++) + { + if (recipient_ship->pn == 99) + { + unused_ship_available = TRUE; + break; + } + + ++recipient_ship; + } + + if (! unused_ship_available) + { + /* Make sure we have enough memory for new ship. */ + if (num_new_ships[g_spec_number - 1] == NUM_EXTRA_SHIPS) + { + fprintf (stderr, "\n\n\tInsufficient memory for new recipient ship!\n\n"); + exit (-1); + } + recipient_ship = ship_data[g_spec_number - 1] + + (int) recipient_species->num_ships; + ++recipient_species->num_ships; + ++num_new_ships[g_spec_number - 1]; + } + + /* Copy donor ship to recipient ship. */ + src = (char *) ship; + dest = (char *) recipient_ship; + for (i = 0; i < sizeof (struct ship_data); i++) + *dest++ = *src++; + + recipient_ship->status = IN_ORBIT; + + data_modified[g_spec_number - 1] = TRUE; + + /* Delete donor ship. */ + delete_ship (ship); + + if (first_pass) return; + + /* Define transaction so that recipient will be notified. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = INTERSPECIES_CONSTRUCTION; + transaction[n].donor = species_number; + transaction[n].recipient = g_spec_number; + transaction[n].value = 2; /* Ship, not items. */ + transaction[n].number3 = total_cost + premium; + strcpy (transaction[n].name1, species->name); + strcpy (transaction[n].name2, ship_name (recipient_ship)); +} diff --git a/src/do_deep.c b/src/do_deep.c new file mode 100644 index 0000000..cea80e9 --- /dev/null +++ b/src/do_deep.c @@ -0,0 +1,78 @@ + +#include "fh.h" + + +extern int first_pass; +extern char input_line[256], original_line[256], + *input_line_pointer; +extern FILE *log_file; +extern struct ship_data *ship; + + +do_DEEP_command () +{ + int i, found; + + char *original_line_pointer; + + + /* Get the ship. */ + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in ORBIT command.\n"); + return; + } + } + + if (ship->type == STARBASE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! DEEP order may not be given for a starbase.\n"); + return; + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Make sure ship is not salvage of a disbanded colony. */ + if (disbanded_ship (ship)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! This ship is salvage of a disbanded colony!\n"); + return; + } + + /* Move the ship. */ + ship->pn = 0; + ship->status = IN_DEEP_SPACE; + + /* Log result. */ + log_string (" "); + log_string (ship_name (ship)); + log_string (" moved into deep space.\n"); +} diff --git a/src/do_des.c b/src/do_des.c new file mode 100644 index 0000000..0aec220 --- /dev/null +++ b/src/do_des.c @@ -0,0 +1,42 @@ + +#include "fh.h" + + +extern int first_pass, correct_spelling_required; +extern char input_line[256]; +extern FILE *log_file; +extern struct species_data *species; +extern struct ship_data *ship; + + +do_DESTROY_command () +{ + int found; + + + /* Get the ship. */ + correct_spelling_required = TRUE; + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid ship or starbase name in DESTROY command.\n"); + return; + } + + /* Log result. */ + log_string (" "); + log_string (ship_name (ship)); + + if (first_pass) + { + log_string (" will be destroyed.\n"); + return; + } + + log_string (" was destroyed.\n"); + + delete_ship (ship); +} + diff --git a/src/do_dev.c b/src/do_dev.c new file mode 100644 index 0000000..3743367 --- /dev/null +++ b/src/do_dev.c @@ -0,0 +1,526 @@ + +#include "fh.h" + + +extern int doing_production; +extern long value, balance, EU_spending_limit; +extern char input_line[256], original_line[256], *input_line_pointer; +extern FILE *log_file; + +extern struct planet_data *planet_base; +extern struct species_data *species; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship; + + +do_DEVELOP_command () +{ + int i, num_CUs, num_AUs, num_IUs, more_args, load_transport, + capacity, resort_colony, mining_colony, production_penalty, + CUs_only; + + char c, *original_line_pointer, *tp; + + long n, ni, na, amount_to_spend, original_cost, max_funds_available, + ls_needed, raw_material_units, production_capacity, + colony_production, ib, ab, md, denom, reb, specified_max; + + struct planet_data *colony_planet, *home_planet; + struct nampla_data *temp_nampla, *colony_nampla; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get default spending limit. */ + max_funds_available = species->econ_units; + if (max_funds_available > EU_spending_limit) + max_funds_available = EU_spending_limit; + max_funds_available += balance; + + /* Get specified spending limit, if any. */ + specified_max = -1; + if (get_value ()) + { + if (value == 0) + max_funds_available = balance; + else if (value > 0) + { + specified_max = value; + if (value <= max_funds_available) + max_funds_available = value; + else + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, + "! Insufficient funds. Substituting %ld for %ld.\n", + max_funds_available, value); + if (max_funds_available == 0) return; + } + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid spending limit.\n"); + return; + } + } + + /* See if there are any more arguments. */ + tp = input_line_pointer; + more_args = FALSE; + while (c = *tp++) + { + if (c == ';' || c == '\n') break; + if (c == ' ' || c == '\t') continue; + more_args = TRUE; + break; + } + + if (! more_args) + { + /* Make sure planet is not a healthy home planet. */ + if (nampla->status & HOME_PLANET) + { + reb = species->hp_original_base - (nampla->mi_base + nampla->ma_base); + if (reb > 0) + { + /* Home planet is recovering from bombing. */ + if (reb < max_funds_available) max_funds_available = reb; + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can only DEVELOP a home planet if it is recovering from bombing.\n"); + return; + } + } + + /* No arguments. Order is for this planet. */ + num_CUs = nampla->pop_units; + if (2 * num_CUs > max_funds_available) + num_CUs = max_funds_available / 2; + if (num_CUs <= 0) return; + + colony_planet = planet_base + (long) nampla->planet_index; + ib = nampla->mi_base + nampla->IUs_to_install; + ab = nampla->ma_base + nampla->AUs_to_install; + md = colony_planet->mining_difficulty; + + denom = 100 + md; + num_AUs = + (100 * (num_CUs + ib) - (md * ab) + denom/2) / denom; + num_IUs = num_CUs - num_AUs; + + if (num_IUs < 0) + { + num_AUs = num_CUs; + num_IUs = 0; + } + if (num_AUs < 0) + { + num_IUs = num_CUs; + num_AUs = 0; + } + + amount_to_spend = num_CUs + num_AUs + num_IUs; + + if (check_bounced (amount_to_spend)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Internal error. Please notify GM!\n"); + return; + } + + nampla->pop_units -= num_CUs; + nampla->item_quantity[CU] += num_CUs; + nampla->item_quantity[IU] += num_IUs; + nampla->item_quantity[AU] += num_AUs; + + nampla->auto_IUs += num_IUs; + nampla->auto_AUs += num_AUs; + + start_dev_log (num_CUs, num_IUs, num_AUs); + log_string (".\n"); + + check_population (nampla); + + return; + } + + /* Get the planet to be developed. */ + temp_nampla = nampla; + original_line_pointer = input_line_pointer; + i = get_location (); + if (! i || nampla == NULL) + { + /* Check for missing comma or tab after source name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + i = get_location (); + } + colony_nampla = nampla; + nampla = temp_nampla; + if (! i || colony_nampla == NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in DEVELOP command.\n"); + return; + } + + /* Make sure planet is not a healthy home planet. */ + if (colony_nampla->status & HOME_PLANET) + { + reb = species->hp_original_base - (colony_nampla->mi_base + colony_nampla->ma_base); + if (reb > 0) + { + /* Home planet is recovering from bombing. */ + if (reb < max_funds_available) max_funds_available = reb; + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can only DEVELOP a home planet if it is recovering from bombing.\n"); + return; + } + } + + /* Determine if its a mining or resort colony, and if it can afford to + build its own IUs and AUs. Note that we cannot use nampla->status + because it is not correctly set until the Finish program is run. */ + + home_planet = planet_base + (long) nampla_base->planet_index; + colony_planet = planet_base + (long) colony_nampla->planet_index; + ls_needed = life_support_needed (species, home_planet, colony_planet); + + ni = colony_nampla->mi_base + colony_nampla->IUs_to_install; + na = colony_nampla->ma_base + colony_nampla->AUs_to_install; + + if (ni > 0 && na == 0) + { + colony_production = 0; + mining_colony = TRUE; + resort_colony = FALSE; + } + else if (na > 0 && ni == 0 && ls_needed <= 6 + && colony_planet->gravity <= home_planet->gravity) + { + colony_production = 0; + resort_colony = TRUE; + mining_colony = FALSE; + } + else + { + mining_colony = FALSE; + resort_colony = FALSE; + + raw_material_units = (10L * (long) species->tech_level[MI] * ni) + / (long) colony_planet->mining_difficulty; + production_capacity = ((long) species->tech_level[MA] * na) / 10L; + + if (ls_needed == 0) + production_penalty = 0; + else + production_penalty = (100 * ls_needed) / species->tech_level[LS]; + + raw_material_units -= (production_penalty * raw_material_units) / 100; + production_capacity -= (production_penalty * production_capacity) / 100; + + colony_production = (production_capacity > raw_material_units) + ? raw_material_units : production_capacity; + + colony_production -= colony_nampla->IUs_needed + + colony_nampla->AUs_needed; + /* In case there is more than one DEVELOP order for + this colony. */ + } + + /* See if there are more arguments. */ + tp = input_line_pointer; + more_args = FALSE; + while (c = *tp++) + { + if (c == ';' || c == '\n') break; + if (c == ' ' || c == '\t') continue; + more_args = TRUE; + break; + } + + if (more_args) + { + load_transport = TRUE; + + /* Get the ship to receive the cargo. */ + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship to be loaded does not exist!\n"); + return; + } + + if (ship->class == TR) + capacity = (10 + ((int) ship->tonnage / 2)) * (int) ship->tonnage; + else if (ship->class == BA) + capacity = 10 * ship->tonnage; + else + capacity = ship->tonnage; + + for (i = 0; i < MAX_ITEMS; i++) + capacity -= ship->item_quantity[i] * item_carry_capacity[i]; + + if (capacity <= 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s was already full and could take no more cargo!\n", + ship_name (ship)); + return; + } + + if (capacity > max_funds_available) + { + capacity = max_funds_available; + if (max_funds_available != specified_max) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, "! Insufficient funds to completely fill %s!\n", + ship_name (ship)); + fprintf (log_file, "! Will use all remaining funds (= %d).\n", + capacity); + } + } + } + else + { + load_transport = FALSE; + + /* No more arguments. Order is for a colony in the same sector as the + producing planet. */ + if (nampla->x != colony_nampla->x || nampla->y != colony_nampla->y + || nampla->z != colony_nampla->z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Colony and producing planet are not in the same sector.\n"); + return; + } + + num_CUs = nampla->pop_units; + if (2 * num_CUs > max_funds_available) + num_CUs = max_funds_available / 2; + } + + CUs_only = FALSE; + if (mining_colony) + { + if (load_transport) + { + num_CUs = capacity / 2; + if (num_CUs > nampla->pop_units) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, + "! Insufficient available population! %d CUs are needed", + num_CUs); + num_CUs = nampla->pop_units; + fprintf (log_file, " to fill ship but only %d can be built.\n", + num_CUs); + } + } + + num_AUs = 0; + num_IUs = num_CUs; + } + else if (resort_colony) + { + if (load_transport) + { + num_CUs = capacity / 2; + if (num_CUs > nampla->pop_units) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, + "! Insufficient available population! %d CUs are needed", + num_CUs); + num_CUs = nampla->pop_units; + fprintf (log_file, " to fill ship but only %d can be built.\n", + num_CUs); + } + } + + num_IUs = 0; + num_AUs = num_CUs; + } + else + { + if (load_transport) + { + if (colony_production >= capacity) + { + /* Colony can build its own IUs and AUs. */ + num_CUs = capacity; + CUs_only = TRUE; + } + else + { + /* Build IUs and AUs for the colony. */ + num_CUs = capacity / 2; + } + + if (num_CUs > nampla->pop_units) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, + "! Insufficient available population! %d CUs are needed", + num_CUs); + num_CUs = nampla->pop_units; + fprintf (log_file, " to fill ship, but\n! only %d can be built.\n", + num_CUs); + } + } + + colony_planet = planet_base + (long) colony_nampla->planet_index; + + i = 100 + (int) colony_planet->mining_difficulty; + num_AUs = ((100 * num_CUs) + (i + 1)/2) / i; + num_IUs = num_CUs - num_AUs; + } + + if (num_CUs <= 0) return; + + /* Make sure there's enough money to pay for it all. */ + if (load_transport && CUs_only) + amount_to_spend = num_CUs; + else + amount_to_spend = num_CUs + num_IUs + num_AUs; + + if (check_bounced (amount_to_spend)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Internal error. Notify GM!\n"); + return; + } + + /* Start logging what happened. */ + if (load_transport && CUs_only) + { + start_dev_log (num_CUs, 0, 0); + } + else + start_dev_log (num_CUs, num_IUs, num_AUs); + + log_string (" for PL "); log_string (colony_nampla->name); + + nampla->pop_units -= num_CUs; + + if (load_transport) + { + if (CUs_only) + { + colony_nampla->IUs_needed += num_IUs; + colony_nampla->AUs_needed += num_AUs; + } + + if (nampla->x != ship->x || nampla->y != ship->y + || nampla->z != ship->z) + { + nampla->item_quantity[CU] += num_CUs; + if (! CUs_only) + { + nampla->item_quantity[IU] += num_IUs; + nampla->item_quantity[AU] += num_AUs; + } + + log_string (" but will remain on the planet's surface because "); + log_string (ship_name (ship)); + log_string (" is not in the same sector."); + } + else + { + ship->item_quantity[CU] += num_CUs; + if (! CUs_only) + { + ship->item_quantity[IU] += num_IUs; + ship->item_quantity[AU] += num_AUs; + } + + n = colony_nampla - nampla_base; + if (n == 0) n = 9999; /* Home planet. */ + ship->unloading_point = n; + + n = nampla - nampla_base; + if (n == 0) n = 9999; /* Home planet. */ + ship->loading_point = n; + + log_string (" and transferred to "); + log_string (ship_name (ship)); + } + } + else + { + colony_nampla->item_quantity[CU] += num_CUs; + colony_nampla->item_quantity[IU] += num_IUs; + colony_nampla->item_quantity[AU] += num_AUs; + + colony_nampla->auto_IUs += num_IUs; + colony_nampla->auto_AUs += num_AUs; + + log_string (" and transferred to PL "); + log_string (colony_nampla->name); + + check_population (colony_nampla); + } + + log_string (".\n"); +} + + +start_dev_log (num_CUs, num_IUs, num_AUs) + +int num_CUs, num_IUs, num_AUs; + +{ + log_string (" "); + log_int (num_CUs); log_string (" Colonist Unit"); + if (num_CUs != 1) log_char ('s'); + + if (num_IUs + num_AUs == 0) goto done; + + if (num_IUs > 0) + { + if (num_AUs == 0) + log_string (" and "); + else + log_string (", "); + + log_int (num_IUs); log_string (" Colonial Mining Unit"); + if (num_IUs != 1) log_char ('s'); + } + + if (num_AUs > 0) + { + if (num_IUs > 0) log_char (','); + + log_string (" and "); + + log_int (num_AUs); log_string (" Colonial Manufacturing Unit"); + if (num_AUs != 1) log_char ('s'); + } + +done: + + log_string (" were built"); +} diff --git a/src/do_disband.c b/src/do_disband.c new file mode 100644 index 0000000..a568900 --- /dev/null +++ b/src/do_disband.c @@ -0,0 +1,57 @@ + +#include "fh.h" + + +extern char input_line[256]; +extern FILE *log_file; +extern struct nampla_data *nampla; + + +do_DISBAND_command () +{ + int found; + + + /* Get the planet. */ + found = get_location (); + if (! found || nampla == NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in DISBAND command.\n"); + return; + } + + /* Make sure planet is not the home planet. */ + if (nampla->status & HOME_PLANET) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You cannot disband your home planet!\n"); + return; + } + + /* Make sure planet is not under siege. */ + if (nampla->siege_eff) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You cannot disband a planet that is under siege!\n"); + return; + } + + /* Mark the colony as "disbanded" and convert mining and manufacturing + base to CUs, IUs, and AUs. */ + nampla->status |= DISBANDED_COLONY; + nampla->item_quantity[CU] += nampla->mi_base + nampla->ma_base; + nampla->item_quantity[IU] += nampla->mi_base / 2; + nampla->item_quantity[AU] += nampla->ma_base / 2; + nampla->mi_base = 0; + nampla->ma_base = 0; + + /* Log the event. */ + log_string (" The colony on PL "); + log_string (nampla->name); + log_string (" was ordered to disband.\n"); +} + diff --git a/src/do_enemy.c b/src/do_enemy.c new file mode 100644 index 0000000..f2ce57b --- /dev/null +++ b/src/do_enemy.c @@ -0,0 +1,60 @@ + +#include "fh.h" + + +extern int abbr_type, g_spec_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; + + +do_ENEMY_command () + +{ + int i, array_index, bit_number; + + long bit_mask; + + + /* See if declaration is for all species. */ + if (get_value ()) + { + bit_mask = 0; + for (i = 0; i < NUM_CONTACT_WORDS; i++) + { + species->enemy[i] = ~bit_mask; /* Set all enemy bits. */ + species->ally[i] = bit_mask; /* Clear all ally bits. */ + } + } + else + { + /* Get name of species that is being declared an enemy. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing argument in ENEMY command.\n"); + return; + } + + /* Get array index and bit mask. */ + array_index = (g_spec_number - 1) / 32; + bit_number = (g_spec_number - 1) % 32; + bit_mask = 1 << bit_number; + + /* Set/clear the appropriate bit. */ + species->enemy[array_index] |= bit_mask; /* Set enemy bit. */ + species->ally[array_index] &= ~bit_mask; /* Clear ally bit. */ + } + + /* Log the result. */ + log_string (" Enmity was declared towards "); + if (bit_mask == 0) + log_string ("ALL species"); + else + { + log_string ("SP "); + log_string (g_spec_name); + } + log_string (".\n"); +} diff --git a/src/do_est.c b/src/do_est.c new file mode 100644 index 0000000..da6ecc0 --- /dev/null +++ b/src/do_est.c @@ -0,0 +1,100 @@ + +#include "fh.h" + + +extern int first_pass, doing_production, g_spec_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla_base; +extern struct ship_data *ship_base; + + +do_ESTIMATE_command () + +{ + int i, max_error, estimate[6], contact_word_number, + contact_bit_number; + + long cost, contact_mask; + + struct species_data *alien; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get name of alien species. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in ESTIMATE command.\n"); + return; + } + + /* Check if we've met this species. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't do an estimate of a species you haven't met.\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = 25; + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Log the result. */ + if (first_pass) + { + log_string (" An estimate of the technology of SP "); + log_string (g_spec_name); + log_string (" was made at a cost of "); + log_long (cost); + log_string (".\n"); + return; + } + + /* Make the estimates. */ + alien = &spec_data[g_spec_number - 1]; + for (i = 0; i < 6; i++) + { + max_error = (int) alien->tech_level[i] - (int) species->tech_level[i]; + if (max_error < 1) max_error = 1; + estimate[i] = (int) alien->tech_level[i] + rnd((2 * max_error) + 1) + - (max_error + 1); + if (alien->tech_level[i] == 0) estimate[i] = 0; + if (estimate[i] < 0) estimate[i] = 0; + } + + log_string (" Estimate of the technology of SP "); + log_string (alien->name); + log_string (" (government name '"); + log_string (alien->govt_name); + log_string ("', government type '"); + log_string (alien->govt_type); + log_string ("'):\n MI = "); log_int (estimate[MI]); + log_string (", MA = "); log_int (estimate[MA]); + log_string (", ML = "); log_int (estimate[ML]); + log_string (", GV = "); log_int (estimate[GV]); + log_string (", LS = "); log_int (estimate[LS]); + log_string (", BI = "); log_int (estimate[BI]); + log_string (".\n"); +} diff --git a/src/do_friend.c b/src/do_friend.c new file mode 100644 index 0000000..531b468 --- /dev/null +++ b/src/do_friend.c @@ -0,0 +1,60 @@ + +#include "fh.h" + + +extern int abbr_type, g_spec_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; + + +do_FRIEND_command () + +{ + int i, array_index, bit_number; + + long bit_mask; + + + /* See if declaration is for all species. */ + if (get_value ()) + { + bit_mask = 0; + for (i = 0; i < NUM_CONTACT_WORDS; i++) + { + species->friend[i] = ~bit_mask; /* Set all friend bits. */ + species->enemy[i] = bit_mask; /* Clear all enemy bits. */ + } + } + else + { + /* Get name of species that is being declared a friend. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing argument in FRIEND command.\n"); + return; + } + + /* Get array index and bit mask. */ + array_index = (g_spec_number - 1) / 32; + bit_number = (g_spec_number - 1) % 32; + bit_mask = 1 << bit_number; + + /* Set/clear the appropriate bit. */ + species->friend[array_index] |= bit_mask; /* Set friend bit. */ + species->enemy[array_index] &= ~bit_mask; /* Clear enemy bit. */ + } + + /* Log the result. */ + log_string (" Friendship was declared towards "); + if (bit_mask == 0) + log_string ("ALL species"); + else + { + log_string ("SP "); + log_string (g_spec_name); + } + log_string (".\n"); +} diff --git a/src/do_germ.c b/src/do_germ.c new file mode 100644 index 0000000..10b1173 --- /dev/null +++ b/src/do_germ.c @@ -0,0 +1,149 @@ + +#include "fh.h" +#include "combat.h" + + +extern int num_transactions; +extern char field_distorted[MAX_SPECIES]; +extern short germ_bombs_used[MAX_SPECIES][MAX_SPECIES]; +extern struct planet_data *planet_base; +extern struct species_data *c_species[MAX_SPECIES]; +extern struct nampla_data *c_nampla[MAX_SPECIES]; +extern struct ship_data *c_ship[MAX_SPECIES]; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_germ_warfare (attacking_species, defending_species, defender_index, bat, act) + +int attacking_species, defending_species, defender_index; +struct battle_data *bat; +struct action_data *act; + +{ + int i, attacker_BI, defender_BI, success_chance, num_bombs, + success; + + long econ_units_from_looting; + + struct planet_data *planet; + struct nampla_data *attacked_nampla; + struct ship_data *sh; + + + attacker_BI = c_species[attacking_species]->tech_level[BI]; + defender_BI = c_species[defending_species]->tech_level[BI]; + attacked_nampla = (struct nampla_data *) act->fighting_unit[defender_index]; + planet = planet_base + (long) attacked_nampla->planet_index; + + success_chance = 50 + (2 * (attacker_BI - defender_BI)); + success = FALSE; + num_bombs = germ_bombs_used[attacking_species][defending_species]; + + for (i = 0; i < num_bombs; i++) + { + if (rnd(100) <= success_chance) + { + success = TRUE; + break; + } + } + + if (success) + log_string (" Unfortunately"); + else + log_string (" Fortunately"); + + log_string (" for the "); + log_string (c_species[defending_species]->name); + log_string (" defenders of PL "); + log_string (attacked_nampla->name); + log_string (", the "); + i = bat->spec_num[attacking_species]; + if (field_distorted[attacking_species]) + log_int (distorted (i)); + else + log_string (c_species[attacking_species]->name); + log_string (" attackers "); + + if (! success) + { + log_string ("failed"); + + if (num_bombs <= 0) + log_string (" because they didn't have any germ warfare bombs"); + + log_string ("!\n"); + + return; + } + + log_string ("succeeded, using "); + log_int (num_bombs); + log_string (" germ warfare bombs. The defenders were wiped out!\n"); + + /* Take care of looting. */ + econ_units_from_looting = + (long) attacked_nampla->mi_base + (long) attacked_nampla->ma_base; + + if (attacked_nampla->status & HOME_PLANET) + { + if (c_species[defending_species]->hp_original_base < econ_units_from_looting) + c_species[defending_species]->hp_original_base = econ_units_from_looting; + + econ_units_from_looting *= 5; + } + + if (econ_units_from_looting > 0) + { + /* Check if there's enough memory for a new interspecies transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\nRan out of memory! MAX_TRANSACTIONS is too small!\n\n"); + exit (-1); + } + i = num_transactions++; + + /* Define this transaction. */ + transaction[i].type = LOOTING_EU_TRANSFER; + transaction[i].donor = bat->spec_num[defending_species]; + transaction[i].recipient = bat->spec_num[attacking_species]; + transaction[i].value = econ_units_from_looting; + strcpy (transaction[i].name1, c_species[defending_species]->name); + strcpy (transaction[i].name2, c_species[attacking_species]->name); + strcpy (transaction[i].name3, attacked_nampla->name); + } + + /* Finish off defenders. */ + attacked_nampla->mi_base = 0; + attacked_nampla->ma_base = 0; + attacked_nampla->IUs_to_install = 0; + attacked_nampla->AUs_to_install = 0; + attacked_nampla->pop_units = 0; + attacked_nampla->siege_eff = 0; + attacked_nampla->shipyards = 0; + attacked_nampla->hiding = 0; + attacked_nampla->hidden = 0; + attacked_nampla->use_on_ambush = 0; + + for (i = 0; i < MAX_ITEMS; i++) attacked_nampla->item_quantity[i] = 0; + + /* Reset status word. */ + if (attacked_nampla->status & HOME_PLANET) + attacked_nampla->status = HOME_PLANET; + else + attacked_nampla->status = COLONY; + + /* Delete any ships that were under construction on the planet. */ + sh = c_ship[defending_species] - 1; + for (i = 0; i < c_species[defending_species]->num_ships; i++) + { + ++sh; + + if (sh->x != attacked_nampla->x) continue; + if (sh->y != attacked_nampla->y) continue; + if (sh->z != attacked_nampla->z) continue; + if (sh->pn != attacked_nampla->pn) continue; + + delete_ship (sh); + } +} diff --git a/src/do_hide.c b/src/do_hide.c new file mode 100644 index 0000000..ff43815 --- /dev/null +++ b/src/do_hide.c @@ -0,0 +1,83 @@ + +#include "fh.h" + + +extern int doing_production, first_pass, abbr_index; +extern long value, balance; +extern char input_line[256]; +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla; + + +do_HIDE_command () +{ + int n, status; + + long cost; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Make sure this is not a mining colony or home planet. */ + if (nampla->status & HOME_PLANET) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not HIDE a home planet.\n"); + return; + } + if (nampla->status & RESORT_COLONY) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not HIDE a resort colony.\n"); + return; + } + + /* Check if planet is under siege. */ + if (nampla->siege_eff != 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Besieged planet cannot HIDE!\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = (nampla->mi_base + nampla->ma_base) / 10L; + if (nampla->status & MINING_COLONY) + { + if (cost > species->econ_units) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Mining colony does not have sufficient EUs to hide.\n"); + return; + } + else + species->econ_units -= cost; + } + else if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Set 'hiding' flag. */ + nampla->hiding = TRUE; + + /* Log transaction. */ + log_string (" Spent "); log_long (cost); + log_string (" hiding this colony.\n"); +} + diff --git a/src/do_inst.c b/src/do_inst.c new file mode 100644 index 0000000..91ccab0 --- /dev/null +++ b/src/do_inst.c @@ -0,0 +1,201 @@ + +#include "fh.h" + + +extern int abbr_index, species_number; +extern char input_line[256]; +extern long value; +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct nampla_data *nampla; + + +do_INSTALL_command () +{ + int i, item_class, item_count, num_available, do_all_units, + recovering_home_planet, alien_index; + + long n, current_pop, reb; + + struct nampla_data *alien_home_nampla; + + + /* Get number of items to install. */ + if (get_value ()) + do_all_units = FALSE; + else + { + do_all_units = TRUE; + item_count = 0; + item_class = IU; + goto get_planet; + } + + /* Make sure value is meaningful. */ + if (value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid item count in INSTALL command.\n"); + return; + } + item_count = value; + + /* Get class of item. */ + item_class = get_class_abbr (); + if (item_class != ITEM_CLASS || (abbr_index != IU && abbr_index != AU)) + { + /* Players sometimes accidentally use "MI" for "IU" + or "MA" for "AU". */ + if (item_class == TECH_ID && abbr_index == MI) + abbr_index = IU; + else if (item_class == TECH_ID && abbr_index == MA) + abbr_index = AU; + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid item class!\n"); + return; + } + } + item_class = abbr_index; + +get_planet: + + /* Get planet where items are to be installed. */ + if (! get_location () || nampla == NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in INSTALL command.\n"); + return; + } + + /* Make sure this is not someone else's populated homeworld. */ + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (species_number == alien_index + 1) continue; + if (! data_in_memory[alien_index]) continue; + + alien_home_nampla = namp_data[alien_index]; + + if (alien_home_nampla->x != nampla->x) continue; + if (alien_home_nampla->y != nampla->y) continue; + if (alien_home_nampla->z != nampla->z) continue; + if (alien_home_nampla->pn != nampla->pn) continue; + if ((alien_home_nampla->status & POPULATED) == 0) continue; + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not colonize someone else's populated home planet!\n"); + + return; + } + + /* Make sure it's not a healthy home planet. */ + recovering_home_planet = FALSE; + if (nampla->status & HOME_PLANET) + { + n = nampla->mi_base + nampla->ma_base + nampla->IUs_to_install + + nampla->AUs_to_install; + reb = species->hp_original_base - n; + + if (reb > 0) + recovering_home_planet = TRUE; /* HP was bombed. */ + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Installation not allowed on a healthy home planet!\n"); + return; + } + } + +check_items: + + /* Make sure planet has the specified items. */ + if (item_count == 0) + { + item_count = nampla->item_quantity[item_class]; + + if (nampla->item_quantity[CU] < item_count) + item_count = nampla->item_quantity[CU]; + + if (item_count == 0) + { + if (do_all_units) + { + item_count = 0; + item_class = AU; + do_all_units = FALSE; + goto check_items; + } + else + return; + } + } + else if (nampla->item_quantity[item_class] < item_count) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, + "! Planet does not have %d %ss. Substituting 0 for %d!\n", + item_count, item_abbr[item_class], item_count); + item_count = 0; + goto check_items; + } + + if (recovering_home_planet) + { + if (item_count > reb) item_count = reb; + reb -= item_count; + } + + /* Make sure planet has enough colonist units. */ + num_available = nampla->item_quantity[CU]; + if (num_available < item_count) + { + if (num_available > 0) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, "! Planet does not have %d CUs. Substituting %d for %d!\n", + item_count, num_available, item_count); + item_count = num_available; + } + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! No colonist units on planet for installation.\n"); + return; + } + } + + /* Start the installation. */ + nampla->item_quantity[CU] -= item_count; + nampla->item_quantity[item_class] -= item_count; + + if (item_class == IU) + nampla->IUs_to_install += item_count; + else + nampla->AUs_to_install += item_count; + + /* Log result. */ + log_string (" Installation of "); log_int (item_count); + log_char (' '); log_string (item_name[item_class]); + if (item_count != 1) log_char ('s'); + log_string (" began on PL "); + log_string (nampla->name); + log_string (".\n"); + + if (do_all_units) + { + item_count = 0; + item_class = AU; + do_all_units = FALSE; + goto check_items; + } + + check_population (nampla); +} diff --git a/src/do_int.c b/src/do_int.c new file mode 100644 index 0000000..7679fb9 --- /dev/null +++ b/src/do_int.c @@ -0,0 +1,264 @@ + +#include "fh.h" + +#define MAX_INTERCEPTS 1000 + +int num_intercepts; + +struct +{ + char x, y, z; + long amount_spent; +} intercept[MAX_INTERCEPTS]; + +extern int doing_production, first_pass, abbr_index, + species_number, num_transactions; +extern long value, balance; +extern char input_line[256], *ship_name(); +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct nampla_data *nampla; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + + +do_INTERCEPT_command () +{ + int i, n, status; + + long cost; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get amount to spend. */ + status = get_value (); + if (status == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing amount.\n"); + return; + } + if (value == 0) value = balance; + if (value == 0) return; + cost = value; + + /* Check if planet is under siege. */ + if (nampla->siege_eff != 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Besieged planet cannot INTERCEPT!\n"); + return; + } + + /* Check if sufficient funds are available. */ + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + log_string (" Preparations were made for an interception at a cost of "); + log_long (cost); + log_string (".\n"); + + if (first_pass) return; + + /* Allocate funds. */ + for (i = 0; i < num_intercepts; i++) + { + if (nampla->x != intercept[i].x) continue; + if (nampla->y != intercept[i].y) continue; + if (nampla->z != intercept[i].z) continue; + + /* This interception was started by another planet in the same + star system. */ + intercept[i].amount_spent += cost; + return; + } + + if (num_intercepts == MAX_INTERCEPTS) + { + fprintf (stderr, "\n\tMAX_INTERCEPTS exceeded in do_int.c!\n\n"); + exit (-1); + } + + intercept[num_intercepts].x = nampla->x; + intercept[num_intercepts].y = nampla->y; + intercept[num_intercepts].z = nampla->z; + intercept[num_intercepts].amount_spent = cost; + + ++num_intercepts; +} + + + +#define MAX_ENEMY_SHIPS 400 + + +handle_intercept (intercept_index) + +int intercept_index; + +{ + int i, j, n, num_enemy_ships, alien_index, enemy_index, enemy_num, + num_ships_left, array_index, bit_number, is_an_enemy, + is_distorted; + + char enemy_number[MAX_ENEMY_SHIPS]; + + long bit_mask, cost_to_destroy; + + struct species_data *alien; + struct ship_data *alien_sh, *enemy_sh, + *enemy_ship[MAX_ENEMY_SHIPS]; + + + /* Make a list of all enemy ships that jumped into this system. */ + num_enemy_ships = 0; + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (! data_in_memory[alien_index]) continue; + + if (species_number == alien_index + 1) continue; + + /* Is it an enemy species? */ + array_index = (alien_index) / 32; + bit_number = (alien_index) % 32; + bit_mask = 1 << bit_number; + if (species->enemy[array_index] & bit_mask) + is_an_enemy = TRUE; + else + is_an_enemy = FALSE; + + /* Find enemy ships, if any, that jumped to this location. */ + alien = &spec_data[alien_index]; + alien_sh = ship_data[alien_index] - 1; + for (i = 0; i < alien->num_ships; i++) + { + ++alien_sh; + + if (alien_sh->pn == 99) continue; + + /* Did it jump this turn? */ + if (! alien_sh->just_jumped) continue; + if (alien_sh->just_jumped == 50) continue; /* Ship MOVEd. */ + + /* Did it enter this star system? */ + if (alien_sh->x != intercept[intercept_index].x) continue; + if (alien_sh->y != intercept[intercept_index].y) continue; + if (alien_sh->z != intercept[intercept_index].z) continue; + + /* Is it field-distorted? */ + if (alien_sh->item_quantity[FD] == alien_sh->tonnage) + is_distorted = TRUE; + else + is_distorted = FALSE; + + if (!is_an_enemy && !is_distorted) continue; + + /* This is an enemy ship that just jumped into the system. */ + if (num_enemy_ships == MAX_ENEMY_SHIPS) + { + fprintf (stderr, "\n\tERROR! Array overflow in do_int.c!\n\n"); + exit (-1); + } + enemy_number[num_enemy_ships] = alien_index + 1; + enemy_ship[num_enemy_ships] = alien_sh; + ++num_enemy_ships; + } + } + + if (num_enemy_ships == 0) return; /* Nothing to intercept. */ + + num_ships_left = num_enemy_ships; + while (num_ships_left > 0) + { + /* Select ship for interception. */ + enemy_index = rnd(num_enemy_ships) - 1; + if (enemy_ship[enemy_index] == NULL) continue; /* We already did this + one. */ + enemy_num = enemy_number[enemy_index]; + enemy_sh = enemy_ship[enemy_index]; + + /* Are there enough funds to destroy this ship? */ + cost_to_destroy = 100L * (long) enemy_sh->tonnage; + if (enemy_sh->class == TR) cost_to_destroy /= 10; + if (cost_to_destroy > intercept[intercept_index].amount_spent) break; + + /* Is the ship too large? Check only if ship did NOT arrive via a + natural wormhole. */ + if (enemy_sh->just_jumped != 99) + { + if (enemy_sh->tonnage > 20) break; + if (enemy_sh->class != TR && enemy_sh->tonnage > 5) break; + } + + /* Update funds available. */ + intercept[intercept_index].amount_spent -= cost_to_destroy; + + /* Log the result for current species. */ + log_string ("\n! "); + n = enemy_sh->item_quantity[FD]; /* Show real name. */ + enemy_sh->item_quantity[FD] = 0; + log_string (ship_name (enemy_sh)); + enemy_sh->item_quantity[FD] = n; + + /* List cargo destroyed. */ + n = 0; + for (j = 0; j < MAX_ITEMS; j++) + { + if (enemy_sh->item_quantity[j] > 0) + { + if (n++ == 0) + log_string (" (cargo: "); + else + log_char (','); + log_int ((int) enemy_sh->item_quantity[j]); + log_char (' '); + log_string (item_abbr[j]); + } + } + if (n > 0) log_char (')'); + + log_string (", owned by SP "); + log_string (spec_data[enemy_num - 1].name); + log_string (", was successfully intercepted and destroyed in sector "); + log_int (enemy_sh->x); log_char (' '); + log_int (enemy_sh->y); log_char (' '); + log_int (enemy_sh->z); + log_string (".\n"); + + /* Create interspecies transaction so that other player will be + notified. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS in do_int.c!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = SHIP_MISHAP; + transaction[n].value = 1; /* Interception. */ + transaction[n].number1 = enemy_number[enemy_index]; + strcpy (transaction[n].name1, ship_name(enemy_sh)); + + delete_ship (enemy_sh); + + enemy_ship[enemy_index] = NULL; /* Don't select this ship again. */ + + --num_ships_left; + } +} diff --git a/src/do_jump.c b/src/do_jump.c new file mode 100644 index 0000000..c1a9282 --- /dev/null +++ b/src/do_jump.c @@ -0,0 +1,545 @@ + +#include "fh.h" + + +int using_alien_portal, other_species_number, + jump_portal_gv; + +char jump_portal_name[128]; + +short jump_portal_units, jump_portal_age; + +struct species_data *other_species; +struct ship_data *alien_portal; + + +extern int x, y, z, pn, first_pass, ship_index, abbr_type, + abbr_index, species_number, num_transactions; + +extern char input_line[256], original_line[256], + upper_name[32], *input_line_pointer, + *ship_name(); + +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct star_data *star; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship, *ship_base; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + + +do_JUMP_command (jumped_in_combat, using_jump_portal) + +int jumped_in_combat, using_jump_portal; + +{ + int i, n, found, max_xyz, temp_x, temp_y, temp_z, difference, + status, mishap_gv; + + long mishap_chance, success_chance; + + char temp_string[32], *original_line_pointer; + + short mishap_age; + + struct ship_data *jump_portal; + + + /* Set default status at end of jump. */ + status = IN_DEEP_SPACE; + + /* Check if this ship jumped in combat. */ + if (jumped_in_combat) + { + x = ship->dest_x; y = ship->dest_y; z = ship->dest_z; pn = 0; + using_jump_portal = FALSE; + nampla = NULL; + goto do_jump; + } + + /* Get ship making the jump. */ + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + input_line_pointer = original_line_pointer; + fix_separator (); /* Check for missing comma or tab. */ + found = get_ship (); /* Try again. */ + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in JUMP or PJUMP command.\n"); + return; + } + } + + /* Make sure ship is not salvage of a disbanded colony. */ + if (disbanded_ship (ship)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! This ship is salvage of a disbanded colony!\n"); + return; + } + + /* Check if this ship withdrew or was was forced to jump from combat. + If so, ignore specified coordinates and use those provided by the + combat program. */ + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + x = ship->dest_x; y = ship->dest_y; z = ship->dest_z; pn = 0; + jumped_in_combat = TRUE; + using_jump_portal = FALSE; + nampla = NULL; + goto do_jump; + } + + /* Make sure ship can jump. */ + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s is still under construction!\n", + ship_name (ship)); + return; + } + + if (ship->type == STARBASE + || (! using_jump_portal && ship->type == SUB_LIGHT)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s cannot make an interstellar jump!\n", + ship_name (ship)); + return; + } + + /* Check if JUMP, MOVE, or WORMHOLE was already done for this ship. */ + if (ship->just_jumped) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s already jumped or moved this turn!\n", + ship_name (ship)); + return; + } + + /* Get the destination. */ + original_line_pointer = input_line_pointer; + found = get_location(); + if (! found) + { + if (using_jump_portal) + { + input_line_pointer = original_line_pointer; + fix_separator (); /* Check for missing comma or tab. */ + found = get_location(); /* Try again. */ + } + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid destination in JUMP or PJUMP command.\n"); + return; + } + } + + /* Set status to IN_ORBIT if destination is a planet. */ + if (pn > 0) status = IN_ORBIT; + + /* Check if a jump portal is being used. */ + if (using_jump_portal) + { + found = get_jump_portal (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid starbase name in PJUMP command.\n"); + return; + } + } + + /* If using a jump portal, make sure that starbase has sufficient number + of jump portal units. */ + if (using_jump_portal) + { + if (jump_portal_units < ship->tonnage) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Starbase does not have enough Jump Portal Units!\n"); + return; + } + } + +do_jump: + + if (x == ship->x && y == ship->y && z == ship->z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s was already at specified x,y,z.\n", + ship_name (ship)); + return; + } + + /* Set flags to show that ship jumped this turn. */ + ship->just_jumped = TRUE; + + /* Calculate basic mishap probability. */ + if (using_jump_portal) + { + mishap_age = jump_portal_age; + mishap_gv = jump_portal_gv; + } + else + { + mishap_age = ship->age; + mishap_gv = species->tech_level[GV]; + } + mishap_chance = ( 100L * (long) ( ((x - ship->x) * (x - ship->x)) + + ((y - ship->y) * (y - ship->y)) + + ((z - ship->z) * (z - ship->z)) ) ) + / (long) mishap_gv; + + if (mishap_chance > 10000L) + { + mishap_chance = 10000L; + goto start_jump; + } + + /* Add aging effect. */ + if (mishap_age > 0) + { + success_chance = 10000L - mishap_chance; + success_chance -= (2L * (long) mishap_age * success_chance)/100L; + if (success_chance < 0) success_chance = 0; + mishap_chance = 10000L - success_chance; + } + + +start_jump: + + log_string (" "); + log_string (ship_name (ship)); + log_string (" will try to jump to "); + + if (nampla == NULL) + { + log_int (x); log_char (' '); + log_int (y); log_char (' '); + log_int (z); + } + else + { + log_string ("PL "); + log_string (nampla->name); + } + + if (using_jump_portal) + { + log_string (" via jump portal "); + log_string (jump_portal_name); + + if (using_alien_portal && ! first_pass) + { + /* Define this transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = ALIEN_JUMP_PORTAL_USAGE; + transaction[n].number1 = other_species_number; + strcpy (transaction[n].name1, species->name); + strcpy (transaction[n].name2, ship_name(ship)); + strcpy (transaction[n].name3, ship_name(alien_portal)); + } + } + + sprintf (temp_string, " (%ld.%02ld%%).\n", mishap_chance/100L, + mishap_chance%100L); + log_string (temp_string); + +jump_again: + + if (first_pass || (rnd(10000) > mishap_chance)) + { + ship->x = x; ship->y = y; ship->z = z; ship->pn = pn; + ship->status = status; + + if (! first_pass) star_visited (x, y, z); + + return; + } + + /* Ship had a mishap. Check if it has any fail-safe jump units. */ + if (ship->item_quantity[FS] > 0) + { + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS in do_int.c!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = SHIP_MISHAP; + transaction[n].value = 4; /* Use of one FS. */ + transaction[n].number1 = species_number; + strcpy (transaction[n].name1, ship_name(ship)); + + ship->item_quantity[FS] -= 1; + goto jump_again; + } + + /* If ship was forced to jump, and it reached this point, then it + self-destructed. */ + if (ship->status == FORCED_JUMP) goto self_destruct; + + /* Check if ship self-destructed or just mis-jumped. */ + if (rnd(10000) > mishap_chance) + { + /* Calculate mis-jump location. */ + max_xyz = 2 * galaxy.radius - 1; + + try_again: + temp_x = -1; + difference = (ship->x > x) ? (ship->x - x) : (x - ship->x); + difference = (2L * mishap_chance * difference)/10000L; + if (difference < 3) difference = 3; + while (temp_x < 0 || temp_x > max_xyz) + temp_x = x - rnd(difference) + rnd(difference); + + temp_y = -1; + difference = (ship->y > y) ? (ship->y - y) : (y - ship->y); + difference = (2L * mishap_chance * difference)/10000L; + if (difference < 3) difference = 3; + while (temp_y < 0 || temp_y > max_xyz) + temp_y = y - rnd(difference) + rnd(difference); + + temp_z = -1; + difference = (ship->z > z) ? (ship->z - z) : (z - ship->z); + difference = (2L * mishap_chance * difference)/10000L; + if (difference < 3) difference = 3; + while (temp_z < 0 || temp_z > max_xyz) + temp_z = z - rnd(difference) + rnd(difference); + + if (x == temp_x && y == temp_y && z == temp_z) + goto try_again; + + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS in do_int.c!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = SHIP_MISHAP; + transaction[n].value = 3; /* Mis-jump. */ + transaction[n].number1 = species_number; + strcpy (transaction[n].name1, ship_name(ship)); + transaction[n].x = temp_x; + transaction[n].y = temp_y; + transaction[n].z = temp_z; + + ship->x = temp_x; ship->y = temp_y; ship->z = temp_z; + ship->pn = 0; + + ship->status = IN_DEEP_SPACE; + + star_visited (temp_x, temp_y, temp_z); + + return; + } + +self_destruct: + + /* Ship self-destructed. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS in do_int.c!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = SHIP_MISHAP; + transaction[n].value = 2; /* Self-destruction. */ + transaction[n].number1 = species_number; + strcpy (transaction[n].name1, ship_name(ship)); + + delete_ship (ship); +} + + + +int get_jump_portal () + +{ + int i, j, k, found, array_index, bit_number; + + long bit_mask; + + char start_x, start_y, start_z, upper_ship_name[32], + *original_line_pointer; + + struct species_data *original_species; + + struct ship_data *temp_ship, *portal, *original_ship, + *original_ship_base; + + + /* See if specified starbase is owned by the current species. */ + original_line_pointer = input_line_pointer; + temp_ship = ship; + found = get_ship(); + portal = ship; + ship = temp_ship; + using_alien_portal = FALSE; + + if (found) + { + if (portal->type != STARBASE) return FALSE; + jump_portal_age = portal->age; + jump_portal_gv = species->tech_level[GV]; + jump_portal_units = portal->item_quantity[JP]; + strcpy (jump_portal_name, ship_name (portal)); + return TRUE; + } + + start_x = ship->x; + start_y = ship->y; + start_z = ship->z; + + if (abbr_type != SHIP_CLASS) goto check_for_bad_spelling; + if (abbr_index != BA) goto check_for_bad_spelling; + + /* It IS the name of a starbase. See if another species has given + permission to use their starbase. */ + + for (other_species_number = 1; other_species_number <= galaxy.num_species; + other_species_number++) + { + if (! data_in_memory[other_species_number - 1]) continue; + + if (other_species_number == species_number) continue; + + other_species = &spec_data[other_species_number - 1]; + + found = FALSE; + + /* Check if other species has declared this species as an ally. */ + array_index = (species_number - 1) / 32; + bit_number = (species_number - 1) % 32; + bit_mask = 1 << bit_number; + if ((other_species->ally[array_index] & bit_mask) == 0) continue; + + /* See if other species has a starbase with the specified name at + the start location. */ + alien_portal = ship_data[other_species_number - 1] - 1; + for (j = 0; j < other_species->num_ships; j++) + { + ++alien_portal; + + if (alien_portal->type != STARBASE) continue; + if (alien_portal->x != start_x) continue; + if (alien_portal->y != start_y) continue; + if (alien_portal->z != start_z) continue; + if (alien_portal->pn == 99) continue; + + /* Make upper case copy of ship name. */ + for (k = 0; k < 32; k++) + upper_ship_name[k] = toupper(alien_portal->name[k]); + + /* Compare names. */ + if (strcmp (upper_ship_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (found) + { + jump_portal_units = alien_portal->item_quantity[JP]; + jump_portal_age = alien_portal->age; + jump_portal_gv = other_species->tech_level[GV]; + strcpy (jump_portal_name, ship_name (alien_portal)); + strcat (jump_portal_name, " owned by SP "); + strcat (jump_portal_name, other_species->name); + + using_alien_portal = TRUE; + + break; + } + } + + if (found) return TRUE; + +check_for_bad_spelling: + + /* Try again, but allow spelling errors. */ + original_ship = ship; + original_ship_base = ship_base; + original_species = species; + + for (other_species_number = 1; other_species_number <= galaxy.num_species; + other_species_number++) + { + if (! data_in_memory[other_species_number - 1]) continue; + + if (other_species_number == species_number) continue; + + species = &spec_data[other_species_number - 1]; + + /* Check if other species has declared this species as an ally. */ + array_index = (species_number - 1) / 32; + bit_number = (species_number - 1) % 32; + bit_mask = 1 << bit_number; + if ((species->ally[array_index] & bit_mask) == 0) continue; + + input_line_pointer = original_line_pointer; + + ship_base = ship_data[other_species_number - 1]; + + found = get_ship (); + + if (found) + { + found = FALSE; + + if (ship->type != STARBASE) continue; + if (ship->x != start_x) continue; + if (ship->y != start_y) continue; + if (ship->z != start_z) continue; + if (ship->pn == 99) continue; + + found = TRUE; + break; + } + } + + if (found) + { + jump_portal_units = ship->item_quantity[JP]; + jump_portal_age = ship->age; + jump_portal_gv = species->tech_level[GV]; + strcpy (jump_portal_name, ship_name (ship)); + strcat (jump_portal_name, " owned by SP "); + strcat (jump_portal_name, species->name); + + using_alien_portal = TRUE; + } + + species = original_species; + ship = original_ship; + ship_base = original_ship_base; + + return found; +} diff --git a/src/do_land.c b/src/do_land.c new file mode 100644 index 0000000..5b2f777 --- /dev/null +++ b/src/do_land.c @@ -0,0 +1,342 @@ + +#include "fh.h" + + +extern int first_pass, num_transactions, species_number; +extern long value; +extern char input_line[256], original_line[256], + *input_line_pointer, *ship_name(); +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct nampla_data *nampla; +extern struct ship_data *ship; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_LAND_command () +{ + int i, n, found, siege_effectiveness, landing_detected, landed, + alien_number, alien_index, alien_pn, array_index, bit_number, + requested_alien_landing, alien_here, already_logged; + + long bit_mask; + + char *original_line_pointer; + + struct species_data *alien; + struct nampla_data *alien_nampla; + + + /* Get the ship. */ + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in LAND command.\n"); + return; + } + } + + /* Make sure the ship is not a starbase. */ + if (ship->type == STARBASE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! A starbase cannot land on a planet!\n"); + return; + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Get the planet number, if specified. */ + found = get_value (); + +get_planet: + + alien_pn = 0; + alien_here = FALSE; + requested_alien_landing = FALSE; + landed = FALSE; + if (! found) + { + found = get_location (); + if (! found || nampla == NULL) found = FALSE; + } + else + { + /* Check if we or another species that has declared us ALLY has + a colony on this planet. */ + found = FALSE; + alien_pn = value; + requested_alien_landing = TRUE; + array_index = (species_number - 1) / 32; + bit_number = (species_number - 1) % 32; + bit_mask = 1 << bit_number; + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (! data_in_memory[alien_index]) continue; + + alien = &spec_data[alien_index]; + alien_nampla = namp_data[alien_index] - 1; + for (i = 0; i < alien->num_namplas; i++) + { + ++alien_nampla; + if (ship->x != alien_nampla->x) continue; + if (ship->y != alien_nampla->y) continue; + if (ship->z != alien_nampla->z) continue; + if (alien_pn != alien_nampla->pn) continue; + if ((alien_nampla->status & POPULATED) == 0) continue; + + if (alien_index == species_number - 1) + { + /* We have a colony here. No permission needed. */ + nampla = alien_nampla; + found = TRUE; + alien_here = FALSE; + requested_alien_landing = FALSE; + goto finish_up; + } + + alien_here = TRUE; + + if ((alien->ally[array_index] & bit_mask) == 0) continue; + + found = TRUE; + break; + } + + if (found) break; + } + } + +finish_up: + + already_logged = FALSE; + + if (requested_alien_landing && alien_here) + { + /* Notify the other alien(s). */ + landed = found; + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (! data_in_memory[alien_index]) continue; + + if (alien_index == species_number - 1) continue; + + alien = &spec_data[alien_index]; + alien_nampla = namp_data[alien_index] - 1; + for (i = 0; i < alien->num_namplas; i++) + { + ++alien_nampla; + if (ship->x != alien_nampla->x) continue; + if (ship->y != alien_nampla->y) continue; + if (ship->z != alien_nampla->z) continue; + if (alien_pn != alien_nampla->pn) continue; + if ((alien_nampla->status & POPULATED) == 0) continue; + + if ((alien->ally[array_index] & bit_mask) != 0) + found = TRUE; + else + found = FALSE; + + if (landed && ! found) continue; + + if (landed) + log_string (" "); + else + log_string ("!!! "); + + log_string (ship_name (ship)); + + if (landed) + log_string (" was granted"); + else + log_string (" was denied"); + log_string (" permission to land on PL "); + log_string (alien_nampla->name); + log_string (" by SP "); + log_string (alien->name); + log_string (".\n"); + + already_logged = TRUE; + + nampla = alien_nampla; + + if (first_pass) break; + + /* Define a 'landing request' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = LANDING_REQUEST; + transaction[n].value = landed; + transaction[n].number1 = alien_index + 1; + strcpy (transaction[n].name1, alien_nampla->name); + strcpy (transaction[n].name2, ship_name(ship)); + strcpy (transaction[n].name3, species->name); + + break; + } + } + + found = TRUE; + } + + if (alien_here && ! landed) return; + + if (! found) + { + if ((ship->status == IN_ORBIT || ship->status == ON_SURFACE) + && ! requested_alien_landing) + { + /* Player forgot to specify planet. Use the one it's already at. */ + value = ship->pn; + found = TRUE; + goto get_planet; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid or missing planet in LAND command.\n"); + return; + } + + /* Make sure the ship and the planet are in the same star system. */ + if (ship->x != nampla->x || ship->y != nampla->y + || ship->z != nampla->z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship and planet are not in the same sector.\n"); + return; + } + + /* Make sure planet is populated. */ + if ((nampla->status & POPULATED) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Planet in LAND command is not populated.\n"); + return; + } + + /* Move the ship. */ + ship->pn = nampla->pn; + ship->status = ON_SURFACE; + + if (already_logged) return; + + /* If the planet is under siege, the landing may be detected by the + besiegers. */ + log_string (" "); + log_string (ship_name (ship)); + + if (nampla->siege_eff != 0) + { + if (first_pass) + { + log_string (" will attempt to land on PL "); + log_string (nampla->name); + log_string (" in spite of the siege"); + } + else + { + if (nampla->siege_eff < 0) + siege_effectiveness = -nampla->siege_eff; + else + siege_effectiveness = nampla->siege_eff; + + landing_detected = FALSE; + if (rnd(100) <= siege_effectiveness) + { + landing_detected = TRUE; + for (i = 0; i < num_transactions; i++) + { + /* Find out who is besieging this planet. */ + if (transaction[i].type != BESIEGE_PLANET) continue; + if (transaction[i].x != nampla->x) continue; + if (transaction[i].y != nampla->y) continue; + if (transaction[i].z != nampla->z) continue; + if (transaction[i].pn != nampla->pn) continue; + if (transaction[i].number2 != species_number) continue; + + alien_number = transaction[i].number1; + + /* Define a 'detection' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = DETECTION_DURING_SIEGE; + transaction[n].value = 1; /* Landing. */ + strcpy (transaction[n].name1, nampla->name); + strcpy (transaction[n].name2, ship_name(ship)); + strcpy (transaction[n].name3, species->name); + transaction[n].number3 = alien_number; + } + } + + if (rnd(100) <= siege_effectiveness) + { + /* Ship doesn't know if it was detected. */ + log_string (" may have been detected by the besiegers when it landed on PL "); + log_string (nampla->name); + } + else + { + /* Ship knows whether or not it was detected. */ + if (landing_detected) + { + log_string (" was detected by the besiegers when it landed on PL "); + log_string (nampla->name); + } + else + { + log_string (" landed on PL "); + log_string (nampla->name); + log_string (" without being detected by the besiegers"); + } + } + } + } + else + { + if (first_pass) + log_string (" will land on PL "); + else + log_string (" landed on PL "); + log_string (nampla->name); + } + + log_string (".\n"); +} diff --git a/src/do_locs.c b/src/do_locs.c new file mode 100644 index 0000000..d9fbf86 --- /dev/null +++ b/src/do_locs.c @@ -0,0 +1,89 @@ + +/* This routine will create the "loc" array based on current species' data. */ + + +#include "fh.h" + + +extern int species_number, species_index, num_locs; + +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct nampla_data *nampla_base, *nampla; +extern struct ship_data *ship_base, *ship; +extern struct sp_loc_data loc[MAX_LOCATIONS]; + + +do_locations () +{ + int i; + + + num_locs = 0; + + for (species_number = 1; species_number <= galaxy.num_species; species_number++) + { + if (! data_in_memory[species_number - 1]) continue; + + species = &spec_data[species_number - 1]; + nampla_base = namp_data[species_number - 1]; + ship_base = ship_data[species_number - 1]; + + nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + + if (nampla->pn == 99) continue; + + if (nampla->status & POPULATED) + add_location (nampla->x, nampla->y, nampla->z); + } + + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) continue; + + add_location (ship->x, ship->y, ship->z); + } + } +} + + + + +add_location (x, y, z) + +char x, y, z; + +{ + int i; + + + for (i = 0; i < num_locs; i++) + { + if (loc[i].x != x) continue; + if (loc[i].y != y) continue; + if (loc[i].z != z) continue; + if (loc[i].s != species_number) continue; + + return; /* This location is already in list for this species. */ + } + + /* Add new location to the list. */ + loc[num_locs].x = x; + loc[num_locs].y = y; + loc[num_locs].z = z; + loc[num_locs].s = species_number; + + ++num_locs; + if (num_locs < MAX_LOCATIONS) + return; + + fprintf (stderr, "\n\n\tInternal error. Overflow of 'loc' arrays!\n\n"); + exit (-1); +} diff --git a/src/do_man.c b/src/do_man.c new file mode 100644 index 0000000..e94971c --- /dev/null +++ b/src/do_man.c @@ -0,0 +1,101 @@ + +#include "fh.h" + + +extern int nampla_index, doing_production; +extern long value, balance; +extern char input_line[256], manufacturing_done[1000]; +extern FILE *log_file; +extern struct nampla_data *nampla; + + +do_MANUFACTURING_command () +{ + int status; + + long cost, increment, old_base, original_value; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (stderr, "\n\n\tMissing PRODUCTION order!\n\n"); + exit (-1); + } + + /* Check if MANUFACTURING order was already executed for this planet. */ + if (manufacturing_done[nampla_index]) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Only one MANUFACTURING command allowed per planet.\n"); + return; + } + + /* Get amount of increment. */ + status = get_value (); + if (status == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing amount.\n"); + return; + } + original_value = value; + + old_base = nampla->ma_base; + if (value == 0) + { + increment = (3 * old_base)/100; + if (increment > balance) increment = balance; + if (increment > nampla->pop_units) increment = nampla->pop_units; + if (increment == 0) return; + } + else + increment = value; + + /* Check if amount requested exceeds 3% growth limit. */ + if (increment > (3 * old_base)/100) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Specified increase exceeds 3%% growth limit.\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = increment; + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* If the planet is not self-sufficient, make sure there is enough + available population. */ + if ((nampla->status & SELF_SUFFICIENT) == 0) + { + if (nampla->pop_units < increment) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient available population units.\n"); + return; + } + nampla->pop_units -= increment; + } + + /* Increase base and log transaction. */ + nampla->ma_base += increment; + log_string (" Manufacturing base was increased by "); + log_long (increment/10); log_char ('.'); log_long (increment%10); + log_string (" (from "); + log_long (old_base/10); log_char ('.'); log_long (old_base%10); + log_string (" to "); + log_long (nampla->ma_base/10); log_char ('.'); log_long (nampla->ma_base%10); + log_string (").\n"); + + manufacturing_done[nampla_index] = TRUE; +} diff --git a/src/do_mes.c b/src/do_mes.c new file mode 100644 index 0000000..94053b5 --- /dev/null +++ b/src/do_mes.c @@ -0,0 +1,124 @@ + +#include "fh.h" + + +extern int abbr_type, first_pass, species_number, + g_spec_number, num_transactions, end_of_file; +extern char input_line[256], g_spec_name[32], + *input_line_pointer; +extern FILE *log_file, *input_file; +extern struct species_data *species; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_MESSAGE_command () + +{ + int i, message_number, message_fd, bad_species, + unterminated_message; + + char c1, c2, c3, filename[32]; + + FILE *message_file; + + + /* Get destination of message. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in MESSAGE command.\n"); + bad_species = TRUE; + } + else + bad_species = FALSE; + + /* Generate a random number, create a filename with it, and use it to + store message. */ + if (! first_pass && ! bad_species) + { + while (1) + { + /* Generate a random filename. */ + message_number = rnd (32000); + sprintf (filename, "m%d.msg\0", message_number); + + /* Make sure that this filename is not already in use. */ + message_fd = open (filename, 0); + if (message_fd < 0) break; + + /* File already exists. Try again. */ + close (message_fd); + } + + message_file = fopen (filename, "w"); + if (message_file == NULL) + { + fprintf (stderr, + "\n\n!!! Cannot open message file '%s' for writing !!!\n\n", + filename); + exit (-1); + } + } + + /* Copy message to file. */ + unterminated_message = FALSE; + while (1) + { + /* Read next line. */ + input_line_pointer = fgets (input_line, 256, input_file); + if (input_line_pointer == NULL) + { + unterminated_message = TRUE; + end_of_file = TRUE; + break; + } + + skip_whitespace (); + + c1 = *input_line_pointer++; + c2 = *input_line_pointer++; + c3 = *input_line_pointer; + + c1 = toupper (c1); + c2 = toupper (c2); + c3 = toupper (c3); + + if (c1 == 'Z' && c2 == 'Z' && c3 == 'Z') break; + + if (! first_pass && ! bad_species) fputs (input_line, message_file); + } + + if (bad_species) return; + + /* Log the result. */ + log_string (" A message was sent to SP "); + log_string (g_spec_name); + log_string (".\n"); + + if (unterminated_message) + { + log_string (" ! WARNING: Message was not properly terminated with ZZZ!"); + log_string (" Any orders that follow the message will be assumed"); + log_string (" to be part of the message and will be ignored!\n"); + } + + if (first_pass) return; + + fclose (message_file); + + /* Define this message transaction and add to list of transactions. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + i = num_transactions++; + transaction[i].type = MESSAGE_TO_SPECIES; + transaction[i].value = message_number; + transaction[i].number1 = species_number; + strcpy (transaction[i].name1, species->name); + transaction[i].number2 = g_spec_number; + strcpy (transaction[i].name2, g_spec_name); +} diff --git a/src/do_min.c b/src/do_min.c new file mode 100644 index 0000000..1e5c217 --- /dev/null +++ b/src/do_min.c @@ -0,0 +1,101 @@ + +#include "fh.h" + + +extern int nampla_index, doing_production; +extern long value, balance; +extern char input_line[256], mining_done[1000]; +extern FILE *log_file; +extern struct nampla_data *nampla; + + +do_MINING_command () +{ + int status; + + long cost, increment, old_base, original_value; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (stderr, "\n\n\tMissing PRODUCTION order!\n\n"); + exit (-1); + } + + /* Check if MINING order was already executed for this planet. */ + if (mining_done[nampla_index]) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Only one MINING command allowed per planet.\n"); + return; + } + + /* Get amount of increment. */ + status = get_value (); + if (status == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing amount.\n"); + return; + } + original_value = value; + + old_base = nampla->mi_base; + if (value == 0) + { + increment = (3 * old_base)/100; + if (increment > balance) increment = balance; + if (increment > nampla->pop_units) increment = nampla->pop_units; + if (increment == 0) return; + } + else + increment = value; + + /* Check if amount requested exceeds 3% growth limit. */ + if (increment > (3 * old_base)/100) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Specified increase exceeds 3%% growth limit.\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = increment; + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* If the planet is not self-sufficient, make sure there is enough + available population. */ + if ((nampla->status & SELF_SUFFICIENT) == 0) + { + if (nampla->pop_units < increment) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient available population units.\n"); + return; + } + nampla->pop_units -= increment; + } + + /* Increase base and log transaction. */ + nampla->mi_base += increment; + log_string (" Mining base was increased by "); + log_long (increment/10); log_char ('.'); log_long (increment%10); + log_string (" (from "); + log_long (old_base/10); log_char ('.'); log_long (old_base%10); + log_string (" to "); + log_long (nampla->mi_base/10); log_char ('.'); log_long (nampla->mi_base%10); + log_string (").\n"); + + mining_done[nampla_index] = TRUE; +} diff --git a/src/do_move.c b/src/do_move.c new file mode 100644 index 0000000..51de9a9 --- /dev/null +++ b/src/do_move.c @@ -0,0 +1,114 @@ + +#include "fh.h" + + +extern int x, y, z, first_pass; +extern char input_line[256], original_line[256], + *input_line_pointer; +extern FILE *log_file; +extern struct nampla_data *nampla; +extern struct ship_data *ship; + + + +do_MOVE_command () +{ + int i, n, found; + + char *original_line_pointer; + + + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in MOVE command.\n"); + return; + } + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Check if JUMP or MOVE was already done for this ship. */ + if (ship->just_jumped) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s already jumped or moved this turn!\n", + ship_name (ship)); + return; + } + + /* Make sure ship is not salvage of a disbanded colony. */ + if (disbanded_ship (ship)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! This ship is salvage of a disbanded colony!\n"); + return; + } + + /* Get the planet. */ + found = get_location (); + if (! found || nampla != NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! You may not use a planet name in MOVE command.\n"); + return; + } + + /* Check if deltas are acceptable. */ + i = x - ship->x; if (i < 0) n = -i; else n = i; + i = y - ship->y; if (i < 0) n += -i; else n += i; + i = z - ship->z; if (i < 0) n += -i; else n += i; + if (n > 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Destination is too far in MOVE command.\n"); + return; + } + + /* Move the ship. */ + ship->x = x; + ship->y = y; + ship->z = z; + ship->pn = 0; + ship->status = IN_DEEP_SPACE; + ship->just_jumped = 50; + + if (! first_pass) star_visited (x, y, z); + + /* Log result. */ + log_string (" "); + log_string (ship_name (ship)); + if (first_pass) + log_string (" will move to sector "); + else + log_string (" moved to sector "); + log_int (x); log_char (' '); log_int (y); log_char (' '); log_int (z); + log_string (".\n"); +} diff --git a/src/do_name.c b/src/do_name.c new file mode 100644 index 0000000..b02f815 --- /dev/null +++ b/src/do_name.c @@ -0,0 +1,144 @@ + +#include "fh.h" + + + +extern int x, y, z, pn, num_stars, nampla_index, + species_index; +extern char input_line[256], upper_name[32], + original_name[32], *input_line_pointer; +extern FILE *log_file; +extern struct species_data *species; +extern struct star_data *star; +extern struct planet_data *planet_base; +extern struct nampla_data *nampla_base, *nampla; + + +do_NAME_command () +{ + int i, found, name_length, unused_nampla_available; + + char upper_nampla_name[32], *original_line_pointer; + + struct planet_data *planet; + struct nampla_data *unused_nampla; + + + /* Get x y z coordinates. */ + found = get_location (); + if (! found || nampla != NULL || pn == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid coordinates in NAME command.\n"); + return; + } + + /* Get planet abbreviation. */ + skip_whitespace (); + original_line_pointer = input_line_pointer; + if (get_class_abbr () != PLANET_ID) + { + /* Check if PL was mispelled (i.e, "PT" or "PN"). Otherwise + assume that it was accidentally omitted. */ + if (tolower(*original_line_pointer) != 'p' + || isalnum (*(original_line_pointer+2))) + input_line_pointer = original_line_pointer; + } + + /* Get planet name. */ + name_length = get_name (); + if (name_length < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in NAME command.\n"); + return; + } + + /* Search existing namplas for name and location. */ + found = FALSE; + unused_nampla_available = FALSE; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->pn == 99) + { + /* We can re-use this nampla rather than append a new one. */ + unused_nampla = nampla; + unused_nampla_available = TRUE; + continue; + } + + /* Check if a named planet already exists at this location. */ + if (nampla->x == x && nampla->y == y && nampla->z == z + && nampla->pn == pn) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! The planet at these coordinates already has a name.\n"); + return; + } + + /* Make upper case copy of nampla name. */ + for (i = 0; i < 32; i++) + upper_nampla_name[i] = toupper(nampla->name[i]); + + /* Compare names. */ + if (strcmp (upper_nampla_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Planet in NAME command already exists.\n"); + return; + } + + /* Add new nampla to database for this species. */ + if (unused_nampla_available) + nampla = unused_nampla; + else + { + ++num_new_namplas[species_index]; + if (num_new_namplas[species_index] > NUM_EXTRA_NAMPLAS) + { + fprintf (stderr, "\n\n\tInsufficient memory for new planet name:\n"); + fprintf (stderr, "\n\t%s\n", input_line); + exit (-1); + } + nampla = nampla_base + species->num_namplas; + species->num_namplas += 1; + delete_nampla (nampla); /* Set everything to zero. */ + } + + /* Initialize new nampla. */ + strcpy (nampla->name, original_name); + nampla->x = x; + nampla->y = y; + nampla->z = z; + nampla->pn = pn; + nampla->status = COLONY; + nampla->planet_index = star->planet_index + pn - 1; + planet = planet_base + (long) nampla->planet_index; + nampla->message = planet->message; + + /* Everything else was set to zero in above call to 'delete_nampla'. */ + + /* Mark sector as having been visited. */ + star_visited (x, y, z); + + /* Log result. */ + log_string (" Named PL "); log_string (nampla->name); + log_string (" at "); log_int (nampla->x); log_char (' '); + log_int (nampla->y); log_char (' '); log_int (nampla->z); + log_string (", planet #"); log_int (nampla->pn); + log_string (".\n"); +} diff --git a/src/do_neutral.c b/src/do_neutral.c new file mode 100644 index 0000000..9faad9b --- /dev/null +++ b/src/do_neutral.c @@ -0,0 +1,60 @@ + +#include "fh.h" + + +extern int abbr_type, g_spec_number; +extern char input_line[256], g_spec_name[32]; +extern FILE *log_file; +extern struct species_data *species; + + +do_NEUTRAL_command () + +{ + int i, array_index, bit_number; + + long bit_mask; + + + /* See if declaration is for all species. */ + if (get_value ()) + { + bit_mask = 0; + for (i = 0; i < NUM_CONTACT_WORDS; i++) + { + species->enemy[i] = bit_mask; /* Clear all enemy bits. */ + species->ally[i] = bit_mask; /* Clear all ally bits. */ + } + } + else + { + /* Get name of species. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing argument in NEUTRAL command.\n"); + return; + } + + /* Get array index and bit mask. */ + array_index = (g_spec_number - 1) / 32; + bit_number = (g_spec_number - 1) % 32; + bit_mask = 1 << bit_number; + + /* Clear the appropriate bit. */ + species->enemy[array_index] &= ~bit_mask; /* Clear enemy bit. */ + species->ally[array_index] &= ~bit_mask; /* Clear ally bit. */ + } + + /* Log the result. */ + log_string (" Neutrality was declared towards "); + if (bit_mask == 0) + log_string ("ALL species"); + else + { + log_string ("SP "); + log_string (g_spec_name); + } + log_string (".\n"); +} diff --git a/src/do_orbit.c b/src/do_orbit.c new file mode 100644 index 0000000..26a67b9 --- /dev/null +++ b/src/do_orbit.c @@ -0,0 +1,184 @@ + +#include "fh.h" + + +extern int first_pass, num_stars; +extern long value; +extern char input_line[256], original_line[256], + *input_line_pointer; +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct star_data *star_base, *star; +extern struct species_data *species; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship; + + +do_ORBIT_command () +{ + int i, found, specified_planet_number; + + char *original_line_pointer; + + + /* Get the ship. */ + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in ORBIT command.\n"); + return; + } + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Make sure this ship didn't just arrive via a MOVE command. */ + if (ship->just_jumped == 50) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! ORBIT not allowed immediately after a MOVE!\n"); + return; + } + + /* Make sure ship is not salvage of a disbanded colony. */ + if (disbanded_ship (ship)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! This ship is salvage of a disbanded colony!\n"); + return; + } + + /* Get the planet. */ + specified_planet_number = get_value (); + +get_planet: + + if (specified_planet_number) + { + found = FALSE; + specified_planet_number = value; + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + if (star->x != ship->x) continue; + if (star->y != ship->y) continue; + if (star->z != ship->z) continue; + + if (specified_planet_number >= 1 + && specified_planet_number <= star->num_planets) + found = TRUE; + + break; + } + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid planet in ORBIT command.\n"); + return; + } + + ship->pn = specified_planet_number; + + goto finish_up; + } + + found = get_location (); + if (! found || nampla == NULL) + { + if (ship->status == IN_ORBIT || ship->status == ON_SURFACE) + { + /* Player forgot to specify planet. Use the one it's already at. */ + specified_planet_number = ship->pn; + value = specified_planet_number; + goto get_planet; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid or missing planet in ORBIT command.\n"); + return; + } + + /* Make sure the ship and the planet are in the same star system. */ + if (ship->x != nampla->x || ship->y != nampla->y || ship->z != nampla->z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship and planet are not in the same sector.\n"); + return; + } + + /* Move the ship. */ + ship->pn = nampla->pn; + +finish_up: + + ship->status = IN_ORBIT; + + /* If a planet number is being used, see if it has a name. If so, + use the name. */ + if (specified_planet_number) + { + for (i = 0; i < species->num_namplas; i++) + { + nampla = nampla_base + i; + + if (nampla->x != ship->x) continue; + if (nampla->y != ship->y) continue; + if (nampla->z != ship->z) continue; + if (nampla->pn != specified_planet_number) continue; + + specified_planet_number = 0; + break; + } + } + + /* Log result. */ + log_string (" "); + log_string (ship_name (ship)); + if (first_pass) + log_string (" will enter orbit around "); + else + log_string (" entered orbit around "); + + if (specified_planet_number) + { + log_string ("planet number "); + log_int (specified_planet_number); + } + else + { + log_string ("PL "); + log_string (nampla->name); + } + + log_string (".\n"); +} diff --git a/src/do_prod.c b/src/do_prod.c new file mode 100644 index 0000000..af4c9e7 --- /dev/null +++ b/src/do_prod.c @@ -0,0 +1,654 @@ + +#include "fh.h" + + +int last_planet_produced = FALSE; + +int shipyard_built, shipyard_capacity; + +extern int nampla_index, doing_production, first_pass, next_nampla_index, + planet_data_modified, species_number, num_transactions; +extern long balance, raw_material_units, production_capacity, + EU_spending_limit; +extern char production_done[1000], input_line[256], upper_name[32]; +extern FILE *log_file; + +extern struct planet_data *planet_base, *planet, *home_planet; +extern struct species_data *species; +extern struct nampla_data *nampla_base, *nampla, *next_nampla; +extern struct ship_data *ship_base; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_PRODUCTION_command (missing_production_order) + +int missing_production_order; + +{ + int i, j, abbr_type, name_length, found, alien_number, under_siege, + siege_percent_effectiveness, new_alien, num_siege_ships, + mining_colony, resort_colony, special_colony, ship_index, + enemy_on_same_planet, trans_index, production_penalty, + ls_needed, shipyards_for_this_species; + + char upper_nampla_name[32]; + + long n, RMs_produced, num_bytes, total_siege_effectiveness, + siege_effectiveness[MAX_SPECIES+1], EUs_available_for_siege, + EUs_for_distribution, EUs_for_this_species, total_EUs_stolen, + special_production, pop_units_here[MAX_SPECIES+1], + alien_pop_units, total_alien_pop_here, total_besieged_pop, + ib_for_this_species, ab_for_this_species, total_ib, total_ab, + total_effective_tonnage; + + struct species_data *alien; + struct nampla_data *alien_nampla_base, *alien_nampla; + struct ship_data *alien_ship_base, *alien_ship, *ship; + + + if (doing_production) + { + /* Terminate production for previous planet. */ + if (last_planet_produced) + { + transfer_balance (); + last_planet_produced = FALSE; + } + + /* Give gamemaster option to abort. */ + if (first_pass) gamemaster_abort_option (); + log_char ('\n'); + } + + doing_production = TRUE; + + if (missing_production_order) + { + nampla = next_nampla; + nampla_index = next_nampla_index; + + goto got_nampla; + } + + /* Get PL abbreviation. */ + abbr_type = get_class_abbr (); + + if (abbr_type != PLANET_ID) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in PRODUCTION command.\n"); + return; + } + + /* Get planet name. */ + name_length = get_name (); + + /* Search all namplas for name. */ + found = FALSE; + nampla = nampla_base - 1; + for (nampla_index = 0; nampla_index < species->num_namplas; nampla_index++) + { + ++nampla; + + if (nampla->pn == 99) continue; + + /* Make upper case copy of nampla name. */ + for (i = 0; i < 32; i++) + upper_nampla_name[i] = toupper(nampla->name[i]); + + /* Compare names. */ + if (strcmp (upper_nampla_name, upper_name) == 0) + { + found = TRUE; + break; + } + } + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in PRODUCTION command.\n"); + return; + } + + /* Check if production was already done for this planet. */ + if (production_done[nampla_index]) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! More than one PRODUCTION command for planet.\n"); + return; + } + production_done[nampla_index] = TRUE; + + /* Check if this colony was disbanded. */ + if (nampla->status & DISBANDED_COLONY) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Production orders cannot be given for a disbanded colony!\n"); + return; + } + +got_nampla: + + last_planet_produced = TRUE; + shipyard_built = FALSE; + shipyard_capacity = nampla->shipyards; + + /* See if this is a mining or resort colony. */ + mining_colony = FALSE; + resort_colony = FALSE; + special_colony = FALSE; + if (nampla->status & MINING_COLONY) + { + mining_colony = TRUE; + special_colony = TRUE; + } + else if (nampla->status & RESORT_COLONY) + { + resort_colony = TRUE; + special_colony = TRUE; + } + + /* Get planet data for this nampla. */ + planet = planet_base + (long) nampla->planet_index; + + /* Check if fleet maintenance cost is so high that riots ensued. */ + i = 0; + j = (species->fleet_percent_cost - 10000) / 100; + if (rnd(100) <= j) + { + log_string ("!!! WARNING! Riots on PL "); + log_string (nampla->name); + log_string (" due to excessive and unpopular military build-up reduced "); + + if (mining_colony || ! special_colony) + { + log_string ("mining base by "); + i = rnd (j); + log_int (i); log_string (" percent "); + nampla->mi_base -= (i * nampla->mi_base) / 100; + } + + if (resort_colony || ! special_colony) + { + if (i) log_string ("and "); + log_string ("manufacturing base by "); + i = rnd (j); + log_int (i); log_string (" percent"); + nampla->ma_base -= (i * nampla->ma_base) / 100; + } + log_string ("!\n\n"); + } + + /* Calculate "balance" available for spending and create pseudo + "checking account". */ + ls_needed = life_support_needed (species, home_planet, planet); + + if (ls_needed == 0) + production_penalty = 0; + else + production_penalty = (100 * ls_needed) / species->tech_level[LS]; + + RMs_produced = + (10L * (long) species->tech_level[MI] * (long) nampla->mi_base) + / (long) planet->mining_difficulty; + RMs_produced + -= (production_penalty * RMs_produced) / 100; + RMs_produced + = (((long) planet->econ_efficiency * RMs_produced) + 50) / 100; + + if (special_colony) + /* RMs just 'sitting' on the planet cannot be converted to EUs on a + mining colony, and cannot create a 'balance' on a resort + colony. */ + raw_material_units = 0; + else + raw_material_units = RMs_produced + nampla->item_quantity[RM]; + + production_capacity = + ((long) species->tech_level[MA] * (long) nampla->ma_base) / 10L; + production_capacity + -= (production_penalty * production_capacity) / 100; + production_capacity + = (((long) planet->econ_efficiency * production_capacity) + 50) / 100; + + balance = (raw_material_units > production_capacity) + ? production_capacity : raw_material_units; + + if (species->fleet_percent_cost > 10000) + n = 10000; + else + n = species->fleet_percent_cost; + + if (special_colony) + EU_spending_limit = 0; + else + { + /* Only excess RMs may be recycled. */ + nampla->item_quantity[RM] = raw_material_units - balance; + + balance -= ((n * balance) + 5000) / 10000; + raw_material_units = balance; + production_capacity = balance; + EUs_available_for_siege = balance; + if (nampla->status & HOME_PLANET) + { + if (species->hp_original_base != 0) /* HP was bombed. */ + EU_spending_limit = 4 * balance; /* Factor = 4 + 1 = 5. */ + else + EU_spending_limit = species->econ_units; + } + else + EU_spending_limit = balance; + } + + /* Log what was done. Balances for mining and resort colonies will always + be zero and should not be printed. */ + log_string (" Start of production on PL "); log_string (nampla->name); + log_char ('.'); + if (! special_colony) + { + log_string (" (Initial balance is "); log_long (balance); + log_string (".)"); + } + log_char ('\n'); + + /* If this IS a mining or resort colony, convert RMs or production capacity + to EUs. */ + if (mining_colony) + { + special_production = (2 * RMs_produced) / 3; + special_production -= ((n * special_production) + 5000) / 10000; + log_string (" Mining colony "); + } + else if (resort_colony) + { + special_production = (2 * production_capacity) / 3; + special_production -= ((n * special_production) + 5000) / 10000; + log_string (" Resort colony "); + } + + if (special_colony) + { + log_string (nampla->name); log_string (" generated "); + log_long (special_production); log_string (" economic units.\n"); + + EUs_available_for_siege = special_production; + species->econ_units += special_production; + + if (mining_colony && ! first_pass) + { + planet->mining_difficulty += RMs_produced/150; + planet_data_modified = TRUE; + } + } + + /* Check if this planet is under siege. */ + nampla->siege_eff = 0; + under_siege = FALSE; + alien_number = 0; + num_siege_ships = 0; + total_siege_effectiveness = 0; + enemy_on_same_planet = FALSE; + total_alien_pop_here = 0; + for (i = 1; i <= MAX_SPECIES; i++) + { + siege_effectiveness[i] = 0; + pop_units_here[i] = 0; + } + + for (trans_index = 0; trans_index < num_transactions; trans_index++) + { + /* Check if this is a siege of this nampla. */ + if (transaction[trans_index].type != BESIEGE_PLANET) continue; + if (transaction[trans_index].x != nampla->x) continue; + if (transaction[trans_index].y != nampla->y) continue; + if (transaction[trans_index].z != nampla->z) continue; + if (transaction[trans_index].pn != nampla->pn) continue; + if (transaction[trans_index].number2 != species_number) continue; + + /* Check if alien ship is still in the same star system as the + planet. */ + if (alien_number != transaction[trans_index].number1) + { + /* First transaction for this alien. */ + alien_number = transaction[trans_index].number1; + if (! data_in_memory[alien_number - 1]) + { + fprintf (stderr, "\n\tData for species #%d should be in memory but is not!\n\n", + alien_number); + exit (-1); + } + alien = &spec_data[alien_number - 1]; + alien_nampla_base = namp_data[alien_number - 1]; + alien_ship_base = ship_data[alien_number - 1]; + + new_alien = TRUE; + } + + /* Find the alien ship. */ + found = FALSE; + alien_ship = alien_ship_base - 1; + for (i = 0; i < alien->num_ships; i++) + { + ++alien_ship; + + if (alien_ship->pn == 99) continue; + + if (strcmp(alien_ship->name, transaction[trans_index].name3) == 0) + { + found = TRUE; + break; + } + } + + /* Check if alien ship is still at the siege location. */ + if (! found) continue; /* It must have jumped away and self- + destructed, or was recycled. */ + if (alien_ship->x != nampla->x) continue; + if (alien_ship->y != nampla->y) continue; + if (alien_ship->z != nampla->z) continue; + if (alien_ship->class == TR) continue; + + /* This nampla is under siege. */ + if (! under_siege) + { + log_string ("\n WARNING! PL "); log_string (nampla->name); + log_string (" is under siege by the following:\n "); + under_siege = TRUE; + } + + if (num_siege_ships++ > 0) log_string (", "); + if (new_alien) + { + log_string (alien->name); log_char (' '); + new_alien = FALSE; + + /* Check if this alien has a colony on the same planet. */ + alien_nampla = alien_nampla_base - 1; + for (i = 0; i < alien->num_namplas; i++) + { + ++alien_nampla; + + if (alien_nampla->x != nampla->x) continue; + if (alien_nampla->y != nampla->y) continue; + if (alien_nampla->z != nampla->z) continue; + if (alien_nampla->pn != nampla->pn) continue; + + /* Enemy population that will count for both detection AND + assimilation. */ + alien_pop_units = alien_nampla->mi_base + + alien_nampla->ma_base + + alien_nampla->IUs_to_install + + alien_nampla->AUs_to_install; + + /* Any base over 200.0 has only 5% effectiveness. */ + if (alien_pop_units > 2000) + alien_pop_units = (alien_pop_units - 2000) / 20 + 2000; + + /* Enemy population that counts ONLY for detection. */ + n = alien_nampla->pop_units + + alien_nampla->item_quantity[CU] + + alien_nampla->item_quantity[PD]; + + if (alien_pop_units > 0) + { + enemy_on_same_planet = TRUE; + pop_units_here[alien_number] = alien_pop_units; + total_alien_pop_here += alien_pop_units; + } + else if (n > 0) + enemy_on_same_planet = TRUE; + + if (alien_nampla->item_quantity[PD] == 0) continue; + + log_string ("planetary defenses of PL "); + log_string (alien_nampla->name); + log_string (", "); + + n = (4 * alien_nampla->item_quantity[PD]) / 5; + n = (n * (long) alien->tech_level[ML]) + / ((long) species->tech_level[ML] + 1); + total_siege_effectiveness += n; + siege_effectiveness[alien_number] += n; + } + } + log_string (ship_name(alien_ship)); + + /* Determine the number of planets that this ship is besieging. */ + n = 0; + for (j = 0; j < num_transactions; j++) + { + if (transaction[j].type != BESIEGE_PLANET) continue; + if (transaction[j].number1 != alien_number) continue; + if (strcmp (transaction[j].name3, alien_ship->name) != 0) continue; + + ++n; + } + + /* Determine the effectiveness of this ship on the siege. */ + if (alien_ship->type == STARBASE) + i = alien_ship->tonnage; /* One quarter of normal ships. */ + else + i = 4 * (int) alien_ship->tonnage; + + i = (i * (int) alien->tech_level[ML]) + / ((int) species->tech_level[ML] + 1); + + i /= n; + + total_siege_effectiveness += i; + siege_effectiveness[alien_number] += i; + } + + if (under_siege) + log_string (".\n"); + else + return; + + /* Determine percent effectiveness of the siege. */ + total_effective_tonnage = 2500 * total_siege_effectiveness; + + if (nampla->mi_base + nampla->ma_base == 0) + siege_percent_effectiveness = -9999; /* New colony with nothing + installed yet. */ + else + siege_percent_effectiveness = total_effective_tonnage + / ((((long) species->tech_level[MI] * (long) nampla->mi_base) + + ((long) species->tech_level[MA] * (long) nampla->ma_base)) + / 10L); + + if (siege_percent_effectiveness > 95) + siege_percent_effectiveness = 95; + else if (siege_percent_effectiveness == -9999) + { + log_string (" However, although planet is populated, it has no economic base.\n\n"); + return; + } + else if (siege_percent_effectiveness < 1) + { + log_string (" However, because of the weakness of the siege, it was completely ineffective!\n\n"); + return; + } + + if (enemy_on_same_planet) + nampla->siege_eff = -siege_percent_effectiveness; + else + nampla->siege_eff = siege_percent_effectiveness; + + log_string (" The siege is approximately "); + log_int (siege_percent_effectiveness); + log_string ("% effective.\n"); + + /* Add siege EU transfer(s). */ + EUs_for_distribution + = (siege_percent_effectiveness * EUs_available_for_siege) / 100; + + total_EUs_stolen = 0; + + for (alien_number = 1; alien_number <= MAX_SPECIES; alien_number++) + { + n = siege_effectiveness[alien_number]; + if (n < 1) continue; + alien = &spec_data[alien_number - 1]; + EUs_for_this_species + = (n * EUs_for_distribution) / total_siege_effectiveness; + if (EUs_for_this_species < 1) continue; + total_EUs_stolen += EUs_for_this_species; + log_string (" "); log_long (EUs_for_this_species); + log_string (" economic unit"); + if (EUs_for_this_species > 1) + log_string ("s were"); + else + log_string (" was"); + log_string (" lost and 25% of the amount was transferred to SP "); + log_string (alien->name); + log_string (".\n"); + + if (first_pass) continue; + + /* Define this transaction and add to list of transactions. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + trans_index = num_transactions++; + transaction[trans_index].type = SIEGE_EU_TRANSFER; + transaction[trans_index].donor = species_number; + transaction[trans_index].recipient = alien_number; + transaction[trans_index].value = EUs_for_this_species/4; + transaction[trans_index].x = nampla->x; + transaction[trans_index].y = nampla->y; + transaction[trans_index].z = nampla->z; + transaction[trans_index].number1 = siege_percent_effectiveness; + strcpy (transaction[trans_index].name1, species->name); + strcpy (transaction[trans_index].name2, alien->name); + strcpy (transaction[trans_index].name3, nampla->name); + } + log_char ('\n'); + + /* Correct balances. */ + if (special_colony) + species->econ_units -= total_EUs_stolen; + else + { + if (check_bounced (total_EUs_stolen)) + { + fprintf (stderr, "\nWARNING! Internal error! Should never reach this point!\n\n"); + exit (-1); + } + } + + if (! enemy_on_same_planet) return; + + /* All ships currently under construction may be detected by the besiegers + and destroyed. */ + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship = ship_base + ship_index; + + if (ship->status == UNDER_CONSTRUCTION + && ship->x == nampla->x + && ship->y == nampla->y + && ship->z == nampla->z + && ship->pn == nampla->pn) + { + if (rnd(100) > siege_percent_effectiveness) continue; + + log_string (" "); + log_string (ship_name (ship)); + log_string (", under construction when the siege began, was detected by the besiegers and destroyed!\n"); + if (! first_pass) delete_ship (ship); + } + } + + /* Check for assimilation. */ + if (nampla->status & HOME_PLANET) return; + if (total_alien_pop_here < 1) return; + + total_besieged_pop = nampla->mi_base + nampla->ma_base + + nampla->IUs_to_install + nampla->AUs_to_install; + + /* Any base over 200.0 has only 5% effectiveness. */ + if (total_besieged_pop > 2000) + total_besieged_pop = (total_besieged_pop - 2000) / 20 + 2000; + + if (total_besieged_pop / total_alien_pop_here >= 5) return; + if (siege_percent_effectiveness < 95) return; + + log_string (" PL "); log_string (nampla->name); + log_string (" has become assimilated by the besieging species"); + log_string (" and is no longer under your control.\n\n"); + + total_ib = nampla->mi_base; /* My stupid compiler can't add an int and + an unsigned short. */ + total_ib += nampla->IUs_to_install; + total_ab = nampla->ma_base; + total_ab += nampla->AUs_to_install; + + for (alien_number = 1; alien_number <= MAX_SPECIES; alien_number++) + { + n = pop_units_here[alien_number]; + if (n < 1) continue; + + shipyards_for_this_species + = (n * nampla->shipyards) / total_alien_pop_here; + + ib_for_this_species + = (n * total_ib) / total_alien_pop_here; + total_ib -= ib_for_this_species; + + ab_for_this_species + = (n * total_ab) / total_alien_pop_here; + total_ab -= ab_for_this_species; + + if (ib_for_this_species == 0 && ab_for_this_species == 0) continue; + + if (first_pass) continue; + + /* Define this transaction and add to list of transactions. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + trans_index = num_transactions++; + transaction[trans_index].type = ASSIMILATION; + transaction[trans_index].value = alien_number; + transaction[trans_index].x = nampla->x; + transaction[trans_index].y = nampla->y; + transaction[trans_index].z = nampla->z; + transaction[trans_index].pn = nampla->pn; + transaction[trans_index].number1 = ib_for_this_species/2; + transaction[trans_index].number2 = ab_for_this_species/2; + transaction[trans_index].number3 = shipyards_for_this_species; + strcpy (transaction[trans_index].name1, species->name); + strcpy (transaction[trans_index].name2, nampla->name); + } + + /* Erase the original colony. */ + balance = 0; + EU_spending_limit = 0; + raw_material_units = 0; + production_capacity = 0; + nampla->mi_base = 0; + nampla->ma_base = 0; + nampla->IUs_to_install = 0; + nampla->AUs_to_install = 0; + nampla->pop_units = 0; + nampla->siege_eff = 0; + nampla->status = COLONY; + nampla->shipyards = 0; + nampla->hiding = 0; + nampla->hidden = 0; + nampla->use_on_ambush = 0; + + for (i = 0; i < MAX_ITEMS; i++) nampla->item_quantity[i] = 0; +} diff --git a/src/do_recy.c b/src/do_recy.c new file mode 100644 index 0000000..38a3bf8 --- /dev/null +++ b/src/do_recy.c @@ -0,0 +1,176 @@ + +#include "fh.h" + + +extern int ship_index, doing_production, correct_spelling_required, + abbr_index; +extern long value, raw_material_units, balance, EU_spending_limit; +extern char input_line[256]; +extern FILE *log_file; + +extern struct species_data *species; +extern struct nampla_data *nampla; +extern struct ship_data *ship, *ship_base; + + +do_RECYCLE_command () +{ + int i, class, cargo; + + long recycle_value, original_cost, units_available; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get number of items to recycle. */ + i = get_value (); + + if (i == 0) + goto recycle_ship; /* Not an item. */ + + /* Get class of item. */ + class = get_class_abbr (); + + if (class != ITEM_CLASS) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid item class in RECYCLE command.\n"); + return; + } + class = abbr_index; + + /* Make sure value is meaningful. */ + if (value == 0) value = nampla->item_quantity[class]; + if (value == 0) return; + if (value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid item count in RECYCLE command.\n"); + return; + } + + /* Make sure that items exist. */ + units_available = nampla->item_quantity[class]; + if (value > units_available) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Attempt to recycle more items than are available.\n"); + return; + } + + /* Determine recycle value. */ + if (class == TP) + recycle_value = (value * item_cost[class]) + / (2L * (long) species->tech_level[BI]); + else if (class == RM) + recycle_value = value / 5L; + else + recycle_value = (value * item_cost[class]) / 2L; + + /* Update inventories. */ + nampla->item_quantity[class] -= value; + if (class == PD || class == CU) nampla->pop_units += value; + species->econ_units += recycle_value; + if (nampla->status & HOME_PLANET) EU_spending_limit += recycle_value; + + /* Log what was recycled. */ + log_string (" "); log_long (value); log_char (' '); + log_string (item_name[class]); + + if (value > 1) + log_string ("s were"); + else + log_string (" was"); + + log_string (" recycled, generating "); log_long (recycle_value); + log_string (" economic units.\n"); + + return; + + +recycle_ship: + + correct_spelling_required = TRUE; + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship to be recycled does not exist.\n"); + return; + } + + /* Make sure it didn't just jump. */ + if (ship->just_jumped) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship just jumped and is still in transit.\n"); + return; + } + + /* Make sure item is at producing planet. */ + if (ship->x != nampla->x || ship->y != nampla->y + || ship->z != nampla->z || ship->pn != nampla->pn) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship is not at the production planet.\n"); + return; + } + + /* Calculate recycled value. */ + if (ship->class == TR || ship->type == STARBASE) + original_cost = ship_cost[ship->class] * ship->tonnage; + else + original_cost = ship_cost[ship->class]; + + if (ship->type == SUB_LIGHT) + original_cost = (3 * original_cost) / 4; + + if (ship->status == UNDER_CONSTRUCTION) + recycle_value = (original_cost - (long) ship->remaining_cost) / 2; + else + recycle_value = (3 * original_cost * (60 - (long) ship->age)) / 200; + + species->econ_units += recycle_value; + if (nampla->status & HOME_PLANET) EU_spending_limit += recycle_value; + + /* Log what was recycled. */ + log_string (" "); log_string (ship_name (ship)); + log_string (" was recycled, generating "); log_long (recycle_value); + log_string (" economic units"); + + /* Transfer cargo, if any, from ship to planet. */ + cargo = FALSE; + for (i = 0; i < MAX_ITEMS; i++) + { + if (ship->item_quantity[i] > 0) + { + nampla->item_quantity[i] += ship->item_quantity[i]; + cargo = TRUE; + } + } + + if (cargo) + { + log_string (". Cargo onboard "); + log_string (ship_name (ship)); + log_string (" was first transferred to PL "); + log_string (nampla->name); + } + + log_string (".\n"); + + /* Remove ship from inventory. */ + delete_ship (ship); +} diff --git a/src/do_rep.c b/src/do_rep.c new file mode 100644 index 0000000..cb7dae4 --- /dev/null +++ b/src/do_rep.c @@ -0,0 +1,238 @@ + +#include "fh.h" + + +extern long value; +extern char input_line[256], original_line[256], *input_line_pointer; +extern FILE *log_file; + + +extern struct species_data *species; +extern struct ship_data *ship_base, *ship; + + +do_REPAIR_command () +{ + int i, j, n, x, y, z, age_reduction, num_dr_units, + total_dr_units, dr_units_used, max_age, desired_age; + + char *original_line_pointer; + + struct ship_data *damaged_ship; + + + /* See if this is a "pool" repair. */ + if (get_value ()) + { + x = value; + get_value (); y = value; + get_value (); z = value; + + if (get_value ()) + desired_age = value; + else + desired_age = 0; + + goto pool_repair; + } + + /* Get the ship to be repaired. */ + original_line_pointer = input_line_pointer; + if (! get_ship ()) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship to be repaired does not exist.\n"); + return; + } + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Item to be repaired is still under construction.\n"); + return; + } + + if (ship->age < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship or starbase is too new to repair.\n"); + return; + } + + /* Get number of damage repair units to use. */ + if (get_value ()) + { + if (value == 0) + num_dr_units = ship->item_quantity[DR]; + else + num_dr_units = value; + + age_reduction = (16 * num_dr_units) / ship->tonnage; + if (age_reduction > ship->age) + { + age_reduction = ship->age; + n = age_reduction * ship->tonnage; + num_dr_units = (n + 15) / 16; + } + } + else + { + age_reduction = ship->age; + n = age_reduction * ship->tonnage; + num_dr_units = (n + 15) / 16; + } + + /* Check if sufficient units are available. */ + if (num_dr_units > ship->item_quantity[DR]) + { + if (ship->item_quantity[DR] == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship does not have any DRs!\n"); + return; + } + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, "! Ship does not have %d DRs. Substituting %d for %d.\n", + num_dr_units, ship->item_quantity[DR], num_dr_units); + num_dr_units = ship->item_quantity[DR]; + } + + /* Check if repair will have any effect. */ + age_reduction = (16 * num_dr_units) / ship->tonnage; + if (age_reduction < 1) + { + if (value == 0) return; + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %d DRs is not enough to do a repair.\n", + num_dr_units); + return; + } + + /* Log what was repaired. */ + log_string (" "); log_string (ship_name (ship)); + log_string (" was repaired using "); + log_int (num_dr_units); log_char (' '); + log_string (item_name[DR]); + if (num_dr_units != 1) log_char ('s'); + log_string (". Age went from "); + log_int ((int) ship->age); log_string (" to "); + ship->age -= age_reduction; + if (ship->age < 0) ship->age = 0; + ship->item_quantity[DR] -= num_dr_units; + log_int ((int) ship->age); + log_string (".\n"); + + return; + + +pool_repair: + + /* Get total number of DR units available. */ + total_dr_units = 0; + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + if (ship->x != x) continue; + if (ship->y != y) continue; + if (ship->z != z) continue; + + total_dr_units += ship->item_quantity[DR]; + + ship->special = 0; + } + + /* Repair ships, starting with the most heavily damaged. */ + dr_units_used = 0; + while (total_dr_units > 0) + { + /* Find most heavily damaged ship. */ + max_age = 0; + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + if (ship->x != x) continue; + if (ship->y != y) continue; + if (ship->z != z) continue; + if (ship->special != 0) continue; + if (ship->status == UNDER_CONSTRUCTION) continue; + + n = ship->age; + if (n > max_age) + { + max_age = n; + damaged_ship = ship; + } + } + + if (max_age == 0) break; + + damaged_ship->special = 99; + + age_reduction = max_age - desired_age; + n = age_reduction * damaged_ship->tonnage; + num_dr_units = (n + 15) / 16; + + if (num_dr_units > total_dr_units) + { + num_dr_units = total_dr_units; + age_reduction = (16 * num_dr_units) / damaged_ship->tonnage; + } + + if (age_reduction < 1) continue; /* This ship is too big. */ + + log_string (" "); log_string (ship_name (damaged_ship)); + log_string (" was repaired using "); + log_int (num_dr_units); log_char (' '); + log_string (item_name[DR]); + if (num_dr_units != 1) log_char ('s'); + log_string (". Age went from "); + log_int ((int) damaged_ship->age); log_string (" to "); + damaged_ship->age -= age_reduction; + if (damaged_ship->age < 0) damaged_ship->age = 0; + log_int ((int) damaged_ship->age); + log_string (".\n"); + + total_dr_units -= num_dr_units; + dr_units_used += num_dr_units; + } + + if (dr_units_used == 0) return; + + /* Subtract units used from ships at the location. */ + ship = ship_base - 1; + for (i = 0; i < species->num_ships; i++) + { + ++ship; + + if (ship->pn == 99) continue; + if (ship->x != x) continue; + if (ship->y != y) continue; + if (ship->z != z) continue; + + n = ship->item_quantity[DR]; + if (n < 1) continue; + if (n > dr_units_used) n = dr_units_used; + + ship->item_quantity[DR] -= n; + dr_units_used -= n; + + if (dr_units_used == 0) break; + } +} diff --git a/src/do_res.c b/src/do_res.c new file mode 100644 index 0000000..1cb4d75 --- /dev/null +++ b/src/do_res.c @@ -0,0 +1,129 @@ + +#include "fh.h" + + +extern int doing_production, first_pass, abbr_index; +extern short sp_tech_level[6]; +extern long value, balance, EU_spending_limit; +extern char input_line[256]; +extern FILE *log_file; +extern struct species_data *species; + + +do_RESEARCH_command () +{ + int n, status, tech, initial_level, current_level, + need_amount_to_spend; + + long cost, amount_spent, cost_for_one_level, funds_remaining, + max_funds_available; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get amount to spend. */ + status = get_value (); + need_amount_to_spend = (status == 0); /* Sometimes players reverse + the arguments. */ + /* Get technology. */ + if (get_class_abbr () != TECH_ID) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing technology.\n"); + return; + } + tech = abbr_index; + + if (species->tech_knowledge[tech] == 0 && sp_tech_level[tech] == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Zero level can only be raised via TECH or TEACH.\n"); + return; + } + + /* Get amount to spend if it was not obtained above. */ + if (need_amount_to_spend) status = get_value (); + + if (status == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing amount to spend!\n"); + return; + } + +do_cost: + + if (value == 0) value = balance; + if (value == 0) return; + cost = value; + + /* Check if sufficient funds are available. */ + if (check_bounced (cost)) + { + max_funds_available = species->econ_units; + if (max_funds_available > EU_spending_limit) + max_funds_available = EU_spending_limit; + max_funds_available += balance; + + if (max_funds_available > 0) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, "! Insufficient funds. Substituting %ld for %ld.\n", + max_funds_available, cost); + value = max_funds_available; + goto do_cost; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Check if we already have knowledge of this technology. */ + funds_remaining = cost; + amount_spent = 0; + initial_level = sp_tech_level[tech]; + current_level = initial_level; + while (current_level < species->tech_knowledge[tech]) + { + cost_for_one_level = current_level * current_level; + cost_for_one_level -= cost_for_one_level/4; /* 25% discount. */ + if (funds_remaining < cost_for_one_level) break; + funds_remaining -= cost_for_one_level; + amount_spent += cost_for_one_level; + ++current_level; + } + + if (current_level > initial_level) + { + log_string (" Spent "); log_long (amount_spent); + log_string (" raising "); log_string (tech_name[tech]); + log_string (" tech level from "); log_int (initial_level); + log_string (" to "); log_int (current_level); + log_string (" using transferred knowledge.\n"); + + sp_tech_level[tech] = current_level; + } + + if (funds_remaining == 0) return; + + /* Increase in experience points is equal to whatever was not spent + above. */ + species->tech_eps[tech] += funds_remaining; + + /* Log transaction. */ + log_string (" Spent "); log_long (funds_remaining); + log_string (" on "); log_string (tech_name[tech]); + log_string (" research.\n"); +} diff --git a/src/do_round.c b/src/do_round.c new file mode 100644 index 0000000..144d8a6 --- /dev/null +++ b/src/do_round.c @@ -0,0 +1,613 @@ + +#include "fh.h" +#include "combat.h" + + +long power (); + +char x_attacked_y[MAX_SPECIES][MAX_SPECIES]; + +short germ_bombs_used[MAX_SPECIES][MAX_SPECIES]; + + +extern int log_summary, ignore_field_distorters, + log_to_file; +extern char field_distorted[MAX_SPECIES]; +extern struct species_data *c_species[MAX_SPECIES]; + + +/* The following routine will return TRUE if a round of combat actually + occurred. Otherwise, it will return false. */ + +int do_round (option, round_number, bat, act) + +char option; +int round_number; +struct battle_data *bat; +struct action_data *act; + +{ + int i, j, n, unit_index, combat_occurred, total_shots, + attacker_index, defender_index, found, chance_to_hit, + attacker_ml, attacker_gv, defender_ml, target_index[MAX_SHIPS], + num_targets, header_printed, num_sp, fj_chance, shields_up, + FDs_were_destroyed, di[3], start_unit, current_species, + this_is_a_hijacking; + + long aux_shield_power, units_destroyed, tons, percent_decrease, + damage_done, damage_to_ship, damage_to_shields, op1, op2, + original_cost, recycle_value, economic_units; + + char attacker_name[64], defender_name[64]; + + struct species_data *attacking_species, *defending_species; + struct ship_data *sh, *attacking_ship, *defending_ship; + struct nampla_data *attacking_nampla, *defending_nampla; + + + /* Clear out x_attacked_y and germ_bombs_used arrays. They will be used + to log who bombed who, or how many GWs were used. */ + num_sp = bat->num_species_here; + for (i = 0; i < num_sp; i++) + { + for (j = 0; j < num_sp; j++) + { + x_attacked_y[i][j] = FALSE; + germ_bombs_used[i][j] = 0; + } + } + + /* If a species has ONLY non-combatants left, then let them fight. */ + start_unit = 0; + total_shots = 0; + current_species = act->fighting_species_index[0]; + for (unit_index = 0; unit_index < act->num_units_fighting; unit_index++) + { + if (act->fighting_species_index[unit_index] != current_species) + { + if (total_shots == 0) + { + /* Convert all non-combatants, if any, to combatants. */ + for (i = start_unit; i < unit_index; i++) + { + if (act->unit_type[i] == SHIP) + { + sh = (struct ship_data *) act->fighting_unit[i]; + sh->special = 0; + } + } + } + start_unit = unit_index; + total_shots = 0; + } + + n = act->num_shots[unit_index]; + if (act->surprised[unit_index]) n = 0; + if (act->unit_type[unit_index] == SHIP) + { + sh = (struct ship_data *) act->fighting_unit[unit_index]; + if (sh->special == NON_COMBATANT) n = 0; + } + total_shots += n; + } + + /* Determine total number of shots for all species present. */ + total_shots = 0; + for (unit_index = 0; unit_index < act->num_units_fighting; unit_index++) + { + n = act->num_shots[unit_index]; + if (act->surprised[unit_index]) n = 0; + if (act->unit_type[unit_index] == SHIP) + { + sh = (struct ship_data *) act->fighting_unit[unit_index]; + if (sh->special == NON_COMBATANT) n = 0; + } + act->shots_left[unit_index] = n; + total_shots += n; + } + + /* Handle all shots. */ + header_printed = FALSE; + combat_occurred = FALSE; + while (total_shots > 0) + { + /* Determine who fires next. */ + attacker_index = rnd(act->num_units_fighting) - 1; + if (act->unit_type[attacker_index] == SHIP) + { + attacking_ship = (struct ship_data *) act->fighting_unit[attacker_index]; + i = act->fighting_species_index[attacker_index]; + ignore_field_distorters = ! field_distorted[i]; + sprintf (attacker_name, "%s\0", ship_name (attacking_ship)); + ignore_field_distorters = FALSE; + + /* Check if ship can fight. */ + if (attacking_ship->age > 49) continue; + if (attacking_ship->status == FORCED_JUMP) continue; + if (attacking_ship->status == JUMPED_IN_COMBAT) continue; + if (attacking_ship->special == NON_COMBATANT && + option != GERM_WARFARE) continue; + } + else + { + attacking_nampla = (struct nampla_data *) act->fighting_unit[attacker_index]; + sprintf (attacker_name, "PL %s\0", attacking_nampla->name); + + /* Check if planet still has defenses. */ + if (attacking_nampla->item_quantity[PD] == 0) continue; + } + + /* Make sure attacker is not someone who is being taken by surprise + this round. */ + if (act->surprised[attacker_index]) continue; + + /* Find an enemy. */ + num_targets = 0; + i = act->fighting_species_index[attacker_index]; + attacker_ml = c_species[i]->tech_level[ML]; + attacker_gv = c_species[i]->tech_level[GV]; + for (defender_index = 0; defender_index < act->num_units_fighting; defender_index++) + { + j = act->fighting_species_index[defender_index]; + if (! bat->enemy_mine[i][j]) continue; + + if (act->unit_type[defender_index] == SHIP) + { + defending_ship = + (struct ship_data *) act->fighting_unit[defender_index]; + + if (defending_ship->age > 49) continue; /* Already destroyed. */ + if (defending_ship->status == FORCED_JUMP) continue; + if (defending_ship->status == JUMPED_IN_COMBAT) continue; + if (defending_ship->special == NON_COMBATANT) continue; + } + else + { + defending_nampla = + (struct nampla_data *) act->fighting_unit[defender_index]; + + if (defending_nampla->item_quantity[PD] == 0 + && option == PLANET_ATTACK) continue; + } + + target_index[num_targets] = defender_index; + ++num_targets; + } + + if (num_targets == 0) /* Attacker has no enemies left. */ + { + total_shots -= act->shots_left[attacker_index]; + act->shots_left[attacker_index] = 0; + continue; + } + + /* Randomly choose a target. Choose the toughest of four. */ + defender_index = target_index[rnd(num_targets) - 1]; + op1 = (long) act->num_shots[defender_index] + * act->weapon_damage[defender_index]; + di[0] = target_index[rnd(num_targets) - 1]; + di[1] = target_index[rnd(num_targets) - 1]; + di[2] = target_index[rnd(num_targets) - 1]; + for (i = 0; i < 3; i++) + { + op2 = (long) act->num_shots[di[i]] * act->weapon_damage[di[i]]; + if (op2 > op1) + { + defender_index = di[i]; + op1 = op2; + } + } + + j = act->fighting_species_index[defender_index]; + defender_ml = c_species[j]->tech_level[ML]; + + if (act->unit_type[defender_index] == SHIP) + { + defending_ship = + (struct ship_data *) act->fighting_unit[defender_index]; + ignore_field_distorters = ! field_distorted[j]; + sprintf (defender_name, "%s\0", ship_name (defending_ship)); + ignore_field_distorters = FALSE; + } + else + { + defending_nampla = + (struct nampla_data *) act->fighting_unit[defender_index]; + sprintf (defender_name, "PL %s\0", defending_nampla->name); + } + + /* Print round number. */ + if (! header_printed) + { + log_string (" Now doing round "); + log_int (round_number); + log_string (":\n"); + header_printed = TRUE; + } + + /* Check if attacker has any forced jump units. The attacker will + place more emphasis on the use of these devices if he + emphasizes gravitics technology over military technology. */ + fj_chance = 50 * attacker_gv / (attacker_gv + attacker_ml); + if (rnd(100) < fj_chance + && act->unit_type[attacker_index] == SHIP + && act->unit_type[defender_index] == SHIP) + { + if (forced_jump_units_used (attacker_index, defender_index, + &total_shots, bat, act)) + { + combat_occurred = TRUE; + continue; + } + } + + if (act->shots_left[attacker_index] == 0) continue; + + /* Since transports generally avoid combat, there is only a 10% + chance that they will be targetted, unless they are being + explicitly targetted. */ + i = act->fighting_species_index[attacker_index]; + j = act->fighting_species_index[defender_index]; + if (act->unit_type[defender_index] == SHIP + && defending_ship->class == TR + && bat->special_target[i] != TARGET_TRANSPORTS + && rnd(10) != 5) continue; + + /* If a special target has been specified, then there is a 75% + chance that it will be attacked if it is available. */ + if (bat->special_target[i] && rnd(100) < 76) + { + if (bat->special_target[i] == TARGET_PDS) + { + if (act->unit_type[defender_index] != SHIP) + goto fire; + else + continue; + } + + if (act->unit_type[defender_index] != SHIP) continue; + + if (bat->special_target[i] == TARGET_STARBASES + && defending_ship->class != BA) continue; + if (bat->special_target[i] == TARGET_TRANSPORTS + && defending_ship->class != TR) continue; + if (bat->special_target[i] == TARGET_WARSHIPS) + { + if (defending_ship->class == TR) continue; + if (defending_ship->class == BA) continue; + } + } + +fire: + /* Update counts. */ + --act->shots_left[attacker_index]; + --total_shots; + + /* Since transports generally avoid combat, there is only a 10% + chance that they will attack. */ + if (act->unit_type[attacker_index] == SHIP + && attacking_ship->class == TR + && option != GERM_WARFARE + && rnd(10) != 5) continue; + + /* Fire! */ + combat_occurred = TRUE; + log_string (" "); log_string (attacker_name); + log_string (" fires on "); log_string (defender_name); + if (act->unit_type[defender_index] == NAMPLA) + log_string (" defenses"); + + /* Get hit probability. The basic chance to hit is 1.5 times + attackers ML over the sum of attacker's and defender's ML. + Double this value if defender is surprised. */ + chance_to_hit = (150 * attacker_ml) / (attacker_ml + defender_ml); + if (act->surprised[defender_index]) + { + chance_to_hit *= 2; + shields_up = FALSE; + } + else + shields_up = TRUE; + + /* If defending ship is field-distorted, chance-to-hit is + reduced by 25%. */ + j = act->fighting_species_index[defender_index]; + if (act->unit_type[defender_index] == SHIP + && field_distorted[j] + && defending_ship->item_quantity[FD] == defending_ship->tonnage) + chance_to_hit = (3 * chance_to_hit) / 4; + + if (chance_to_hit > 98) chance_to_hit = 98; + if (chance_to_hit < 2) chance_to_hit = 2; + + /* Adjust for age. */ + if (act->unit_type[attacker_index] == SHIP) + chance_to_hit -= + (2 * attacking_ship->age * chance_to_hit)/100; + + /* Calculate damage that shot will do if it hits. */ + damage_done = act->weapon_damage[attacker_index]; + damage_done += ((26-rnd(51)) * damage_done) / 100; + + /* Take care of attempted annihilation and sieges. */ + if (option == PLANET_BOMBARDMENT || option == GERM_WARFARE + || option == SIEGE) + { + /* Indicate the action that was attempted against this nampla. */ + if (option == SIEGE) + act->unit_type[defender_index] = BESIEGED_NAMPLA; + else + act->unit_type[defender_index] = GENOCIDE_NAMPLA; + + /* Indicate who attacked who. */ + i = act->fighting_species_index[attacker_index]; + j = act->fighting_species_index[defender_index]; + x_attacked_y[i][j] = TRUE; + + /* Update bombardment damage. */ + if (option == PLANET_BOMBARDMENT) + act->bomb_damage[defender_index] += damage_done; + else if (option == GERM_WARFARE) + { + if (act->unit_type[attacker_index] == SHIP) + { + germ_bombs_used[i][j] += attacking_ship->item_quantity[GW]; + attacking_ship->item_quantity[GW] = 0; + } + else + { + germ_bombs_used[i][j] += attacking_nampla->item_quantity[GW]; + attacking_nampla->item_quantity[GW] = 0; + } + } + + continue; + } + + /* Check if shot hit. */ + if (rnd(100) <= chance_to_hit) + log_string (" and hits!\n"); + else + { + log_string (" and misses!\n"); + continue; + } + + /* Subtract damage from defender's shields, if they're up. */ + damage_to_ship = 0; + if (shields_up) + { + if (act->unit_type[defender_index] == SHIP) + { + damage_to_shields = + ((long) defending_ship->dest_y * damage_done) / 100; + damage_to_ship = damage_done - damage_to_shields; + act->shield_strength_left[defender_index] -= damage_to_shields; + + /* Calculate percentage of shields left. */ + if (act->shield_strength_left[defender_index] > 0) + defending_ship->dest_y = + (100L * act->shield_strength_left[defender_index]) + / act->shield_strength[defender_index]; + else + defending_ship->dest_y = 0; + } + else /* Planetary defenses. */ + act->shield_strength_left[defender_index] -= damage_done; + } + + /* See if it got through shields. */ + units_destroyed = 0; + percent_decrease = 0; + if (! shields_up || act->shield_strength_left[defender_index] < 0 + || damage_to_ship > 0) + { + /* Get net damage to ship or PDs. */ + if (shields_up) + { + if (act->unit_type[defender_index] == SHIP) + { + /* Total damage to ship is direct damage plus damage + that shields could not absorb. */ + damage_done = damage_to_ship; + if (act->shield_strength_left[defender_index] < 0) + damage_done -= + act->shield_strength_left[defender_index]; + } + else + damage_done = -act->shield_strength_left[defender_index]; + } + + percent_decrease = + (50L * damage_done) / act->shield_strength[defender_index]; + percent_decrease += ((rnd(51) - 26) * percent_decrease) / 100; + if (percent_decrease > 100) percent_decrease = 100; + + if (act->unit_type[defender_index] == SHIP) + { + defending_ship->age += percent_decrease/2; + units_destroyed = (defending_ship->age > 49); + } + else + { + units_destroyed = (percent_decrease + * act->original_age_or_PDs[defender_index]) / 100L; + if (units_destroyed > defending_nampla->item_quantity[PD]) + units_destroyed = defending_nampla->item_quantity[PD]; + if (units_destroyed < 1) units_destroyed = 1; + defending_nampla->item_quantity[PD] -= units_destroyed; + } + + if (act->shield_strength_left[defender_index] < 0) + act->shield_strength_left[defender_index] = 0; + } + + /* See if this is a hijacking. */ + i = act->fighting_species_index[attacker_index]; + j = act->fighting_species_index[defender_index]; + if (bat->enemy_mine[i][j] == 2 && (option == DEEP_SPACE_FIGHT + || option == PLANET_ATTACK)) + this_is_a_hijacking = TRUE; + else + this_is_a_hijacking = FALSE; + + attacking_species = c_species[i]; + defending_species = c_species[j]; + + /* Report if anything was destroyed. */ + FDs_were_destroyed = FALSE; + if (units_destroyed) + { + if (act->unit_type[defender_index] == SHIP) + { + log_summary = TRUE; + log_string (" "); + log_string (defender_name); + if (this_is_a_hijacking) + { + log_string (" was successfully hijacked and will generate "); + + if (defending_ship->class == TR || defending_ship->type == STARBASE) + original_cost = ship_cost[defending_ship->class] * defending_ship->tonnage; + else + original_cost = ship_cost[defending_ship->class]; + + if (defending_ship->type == SUB_LIGHT) + original_cost = (3 * original_cost) / 4; + + if (defending_ship->status == UNDER_CONSTRUCTION) + recycle_value = + (original_cost - (long) defending_ship->remaining_cost) / 2; + else + recycle_value = + (3 * original_cost * (60 - act->original_age_or_PDs[defender_index])) / 200; + + economic_units = recycle_value; + + for (i = 0; i < MAX_ITEMS; i++) + { + j = defending_ship->item_quantity[i]; + if (j > 0) + { + if (i == TP) + recycle_value = (j * item_cost[i]) + / (2L * (long) defending_species->tech_level[BI]); + else if (i == RM) + recycle_value = j / 5; + else + recycle_value = (j * item_cost[i]) / 2; + + economic_units += recycle_value; + } + } + + attacking_species->econ_units += economic_units; + + log_long (economic_units); + log_string (" economic units for the hijackers.\n"); + } + else + log_string (" was destroyed.\n"); + + for (i = 0; i < MAX_ITEMS; i++) + { + if (defending_ship->item_quantity[i] > 0) + { + /* If this is a hijacking of a field-distorted ship, + we want the true name of the hijacked species to + be announced, but we don't want any cargo to be + destroyed. */ + if (i == FD) FDs_were_destroyed = TRUE; + if (! this_is_a_hijacking) + defending_ship->item_quantity[FD] = 0; + } + } + log_to_file = FALSE; + if (this_is_a_hijacking) + log_string (" The hijacker was "); + else + log_string (" The killing blow was delivered by "); + log_string (attacker_name); + log_string (".\n"); + log_to_file = TRUE; + log_summary = FALSE; + + total_shots -= act->shots_left[defender_index]; + act->shots_left[defender_index] = 0; + act->num_shots[defender_index] = 0; + } + else + { + log_summary = TRUE; + log_string (" "); log_int (units_destroyed); + if (units_destroyed > 1) + log_string (" PDs on PL "); + else + log_string (" PD on PL "); + log_string (defending_nampla->name); + if (units_destroyed > 1) + log_string (" were destroyed by "); + else + log_string (" was destroyed by "); + + log_string (attacker_name); + log_string (".\n"); + + if (defending_nampla->item_quantity[PD] == 0) + { + total_shots -= act->shots_left[defender_index]; + act->shots_left[defender_index] = 0; + act->num_shots[defender_index] = 0; + log_string (" All planetary defenses have been destroyed on "); + log_string (defender_name); + log_string ("!\n"); + } + log_summary = FALSE; + } + } + else if (percent_decrease > 0 && ! this_is_a_hijacking + && act->unit_type[defender_index] == SHIP) + { + /* See if anything carried by the ship was also destroyed. */ + for (i = 0; i < MAX_ITEMS; i++) + { + j = defending_ship->item_quantity[i]; + if (j > 0) + { + j = (percent_decrease * j) / 100; + if (j > 0) + { + defending_ship->item_quantity[i] -= j; + if (i == FD) FDs_were_destroyed = TRUE; + } + } + } + } + + j = act->fighting_species_index[defender_index]; + if (FDs_were_destroyed && field_distorted[j] + && defending_ship->dest_x == 0) + { + /* Reveal the true name of the ship and the owning species. */ + log_summary = TRUE; + if (this_is_a_hijacking) + log_string (" Hijacking of "); + else + log_string (" Damage to "); + log_string (defender_name); + log_string (" caused collapse of distortion field. Real name of ship is "); + log_string (ship_name (defending_ship)); + log_string (" owned by SP "); + log_string (defending_species->name); + log_string (".\n"); + log_summary = FALSE; + defending_ship->dest_x = 127; /* Ship is now exposed. */ + } + } + + /* No more surprises. */ + for (i = 0; i < act->num_units_fighting; i++) + act->surprised[i] = FALSE; + + return combat_occurred; +} diff --git a/src/do_scan.c b/src/do_scan.c new file mode 100644 index 0000000..9709702 --- /dev/null +++ b/src/do_scan.c @@ -0,0 +1,62 @@ + +#include "fh.h" + + +extern int first_pass, test_mode; +extern char input_line[256]; +extern FILE *log_file; +extern struct ship_data *ship; + + +do_SCAN_command () +{ + int i, found, x, y, z; + + + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid ship name in SCAN command.\n"); + return; + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Log the result. */ + if (first_pass) + { + log_string (" A scan will be done by "); + log_string (ship_name (ship)); + log_string (".\n"); + return; + } + + /* Write scan of ship's location to log file. */ + x = ship->x; y = ship->y; z = ship->z; + + if (test_mode) + fprintf (log_file, "\nA scan will be done by %s.\n\n", ship_name (ship)); + else + { + fprintf (log_file, "\nScan done by %s:\n\n", ship_name (ship)); + scan (x, y, z); + } + + fprintf (log_file, "\n"); +} diff --git a/src/do_send.c b/src/do_send.c new file mode 100644 index 0000000..a7c3fb0 --- /dev/null +++ b/src/do_send.c @@ -0,0 +1,119 @@ + +#include "fh.h" + + +extern int abbr_type, abbr_index, species_number, + g_spec_number, first_pass, num_transactions; +extern long value; +extern char input_line[256], g_spec_name[32], + *input_line_pointer; +extern FILE *log_file; +extern struct species_data *species; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_SEND_command () + +{ + int i, n, found, contact_word_number, contact_bit_number; + + char *temp_pointer; + + long num_available, contact_mask, item_count; + + struct nampla_data *nampla1, *nampla2; + + + /* Get number of EUs to transfer. */ + i = get_value (); + + /* Make sure value is meaningful. */ + if (i == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid item count in SEND command.\n"); + return; + } + item_count = value; + + num_available = species->econ_units; + if (item_count == 0) item_count = num_available; + if (item_count == 0) return; + if (num_available < item_count) + { + if (num_available == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You do not have any EUs!\n"); + return; + } + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, "! You do not have %ld EUs! Substituting %ld for %ld.\n", + item_count, num_available, item_count); + item_count = num_available; + } + + /* Get destination of transfer. */ + found = get_species_name (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in SEND command.\n"); + return; + } + + /* Check if we've met this species and make sure it is not an enemy. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't SEND to a species you haven't met.\n"); + return; + } + if (species->enemy[contact_word_number] & contact_mask) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not SEND economic units to an ENEMY.\n"); + return; + } + + /* Make the transfer and log the result. */ + log_string (" "); + log_long (item_count); log_string (" economic unit"); + if (item_count > 1) + log_string ("s were"); + else + log_string (" was"); + log_string (" sent to SP "); + log_string (g_spec_name); + log_string (".\n"); + species->econ_units -= item_count; + + if (first_pass) return; + + /* Define this transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = EU_TRANSFER; + transaction[n].donor = species_number; + transaction[n].recipient = g_spec_number; + transaction[n].value = item_count; + strcpy (transaction[n].name1, species->name); + strcpy (transaction[n].name2, g_spec_name); + + /* Make the transfer to the alien. */ + spec_data[g_spec_number - 1].econ_units += item_count; + data_modified[g_spec_number - 1] = TRUE; +} diff --git a/src/do_shipyard.c b/src/do_shipyard.c new file mode 100644 index 0000000..1c5f871 --- /dev/null +++ b/src/do_shipyard.c @@ -0,0 +1,63 @@ + +#include "fh.h" + + +extern int doing_production, first_pass, abbr_index, + shipyard_built; +extern long value, balance; +extern char input_line[256]; +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla; + + +do_SHIPYARD_command () +{ + long cost; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Make sure this is not a mining or resort colony. */ + if ((nampla->status & MINING_COLONY) || (nampla->status & RESORT_COLONY)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not build shipyards on a mining or resort colony!\n"); + return; + } + + /* Check if planet has already built a shipyard. */ + if (shipyard_built) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Only one shipyard can be built per planet per turn!\n"); + return; + } + + /* Check if sufficient funds are available. */ + cost = 10 * species->tech_level[MA]; + if (check_bounced (cost)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + ++nampla->shipyards; + + shipyard_built = TRUE; + + /* Log transaction. */ + log_string (" Spent "); log_long (cost); + log_string (" to increase shipyard capacity by 1.\n"); +} diff --git a/src/do_siege.c b/src/do_siege.c new file mode 100644 index 0000000..21ea3d9 --- /dev/null +++ b/src/do_siege.c @@ -0,0 +1,84 @@ + +#include "fh.h" +#include "combat.h" + + + +extern int num_transactions; +extern char x_attacked_y[MAX_SPECIES][MAX_SPECIES]; + +extern struct species_data *c_species[MAX_SPECIES]; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_siege (bat, act) + +struct battle_data *bat; +struct action_data *act; + +{ + int a, d, i, attacker_index, defender_index, + attacking_species_number, defending_species_number; + + struct nampla_data *defending_nampla; + struct ship_data *attacking_ship; + struct species_data *defending_species, *attacking_species; + + + for (defender_index = 0; defender_index < act->num_units_fighting; + defender_index++) + { + if (act->unit_type[defender_index] == BESIEGED_NAMPLA) + { + defending_nampla = + (struct nampla_data *) act->fighting_unit[defender_index]; + + defending_nampla->siege_eff = TRUE; + + d = act->fighting_species_index[defender_index]; + defending_species = c_species[d]; + defending_species_number = bat->spec_num[d]; + + for (attacker_index = 0; attacker_index < act->num_units_fighting; + attacker_index++) + { + if (act->unit_type[attacker_index] == SHIP) + { + attacking_ship = + (struct ship_data *) act->fighting_unit[attacker_index]; + + a = act->fighting_species_index[attacker_index]; + + if (x_attacked_y[a][d]) + { + attacking_species = c_species[a]; + attacking_species_number = bat->spec_num[a]; + + /* Check if there's enough memory for a new + interspecies transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\nRan out of memory! MAX_TRANSACTIONS is too small!\n\n"); + exit (-1); + } + i = num_transactions++; + + /* Define this transaction. */ + transaction[i].type = BESIEGE_PLANET; + transaction[i].x = defending_nampla->x; + transaction[i].y = defending_nampla->y; + transaction[i].z = defending_nampla->z; + transaction[i].pn = defending_nampla->pn; + transaction[i].number1 = attacking_species_number; + strcpy (transaction[i].name1, attacking_species->name); + transaction[i].number2 = defending_species_number; + strcpy (transaction[i].name2, defending_species->name); + strcpy (transaction[i].name3, attacking_ship->name); + } + } + } + } + } + + log_string (" Only those ships that actually remain in the system will take part in the siege.\n"); +} diff --git a/src/do_teach.c b/src/do_teach.c new file mode 100644 index 0000000..403420c --- /dev/null +++ b/src/do_teach.c @@ -0,0 +1,111 @@ + +#include "fh.h" + + +extern int abbr_index, species_number, g_spec_number, + first_pass, num_transactions; +extern char input_line[256], g_spec_name[32], + *input_line_pointer; +extern long value; +extern FILE *log_file; +extern struct species_data *species; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_TEACH_command () + +{ + int i, tech, contact_word_number, contact_bit_number, + max_level_specified, need_technology; + + char *temp_ptr; + + short max_tech_level; + + long contact_mask; + + + /* Get technology. */ + temp_ptr = input_line_pointer; + if (get_class_abbr() != TECH_ID) + { + need_technology = TRUE; /* Sometimes players accidentally + reverse the arguments. */ + input_line_pointer = temp_ptr; + } + else + { + need_technology = FALSE; + tech = abbr_index; + } + + /* See if a maximum tech level was specified. */ + max_level_specified = get_value (); + if (max_level_specified) + { + max_tech_level = value; + if (max_tech_level > species->tech_level[tech]) + max_tech_level = species->tech_level[tech]; + } + else + max_tech_level = species->tech_level[tech]; + + /* Get the technology now if it wasn't obtained above. */ + if (need_technology) + { + if (get_class_abbr() != TECH_ID) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing technology!\n"); + return; + } + tech = abbr_index; + } + + /* Get species to transfer knowledge to. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in TEACH command.\n"); + return; + } + + /* Check if we've met this species and make sure it is not an enemy. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't TEACH a species you haven't met.\n"); + return; + } + + if (species->enemy[contact_word_number] & contact_mask) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't TEACH an ENEMY.\n"); + return; + } + + if (first_pass) return; + + /* Define this transaction and add to list of transactions. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + i = num_transactions++; + transaction[i].type = KNOWLEDGE_TRANSFER; + transaction[i].donor = species_number; + transaction[i].recipient = g_spec_number; + transaction[i].value = tech; + strcpy (transaction[i].name1, species->name); + transaction[i].number3 = max_tech_level; +} diff --git a/src/do_tech.c b/src/do_tech.c new file mode 100644 index 0000000..158e1fb --- /dev/null +++ b/src/do_tech.c @@ -0,0 +1,130 @@ + +#include "fh.h" + + +extern int abbr_index, first_pass, species_number, + g_spec_number, num_transactions; +extern char input_line[256], g_spec_name[32]; +extern long value; +extern FILE *log_file; +extern struct species_data *species; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_TECH_command () + +{ + int i, tech, contact_word_number, contact_bit_number, + max_level_specified, max_tech_level, max_cost_specified, + need_technology; + + long contact_mask, max_cost; + + + + /* See if a maximum cost was specified. */ + max_cost_specified = get_value (); + if (max_cost_specified) + max_cost = value; + else + max_cost = 0; + + /* Get technology. */ + if (get_class_abbr() != TECH_ID) + need_technology = TRUE; /* Sometimes players accidentally + reverse the arguments. */ + else + { + need_technology = FALSE; + tech = abbr_index; + } + + /* See if a maximum tech level was specified. */ + max_level_specified = get_value (); + max_tech_level = value; + + /* Get species to transfer tech to. */ + if (! get_species_name()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid species name in TECH command.\n"); + return; + } + + /* Check if we've met this species and make sure it is not an enemy. */ + contact_word_number = (g_spec_number - 1) / 32; + contact_bit_number = (g_spec_number - 1) % 32; + contact_mask = 1 << contact_bit_number; + if ((species->contact[contact_word_number] & contact_mask) == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't transfer tech to a species you haven't met.\n"); + return; + } + if (species->enemy[contact_word_number] & contact_mask) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't transfer tech to an ENEMY.\n"); + return; + } + + /* Get the technology now if it wasn't obtained above. */ + if (need_technology) + { + if (get_class_abbr() != TECH_ID) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid or missing technology!\n"); + return; + } + tech = abbr_index; + } + + /* Make sure there isn't already a transfer of the same technology from + the same donor species to the same recipient species. */ + for (i = 0; i < num_transactions; i++) + { + if (transaction[i].type != TECH_TRANSFER) continue; + if (transaction[i].value != tech) continue; + if (transaction[i].number1 != species_number) continue; + if (transaction[i].number2 != g_spec_number) continue; + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You can't transfer the same tech to the same species more than once!\n"); + return; + } + + /* Log the result. */ + log_string (" Will attempt to transfer "); + log_string (tech_name[tech]); + log_string (" technology to SP "); + log_string (g_spec_name); + log_string (".\n"); + + if (first_pass) return; + + /* Define this transaction and add to list of transactions. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + i = num_transactions++; + transaction[i].type = TECH_TRANSFER; + transaction[i].donor = species_number; + transaction[i].recipient = g_spec_number; + transaction[i].value = tech; + strcpy (transaction[i].name1, species->name); + transaction[i].number1 = max_cost; + strcpy (transaction[i].name2, g_spec_name); + if (max_level_specified && (max_tech_level < species->tech_level[tech])) + transaction[i].number3 = max_tech_level; + else + transaction[i].number3 = species->tech_level[tech]; +} diff --git a/src/do_tel.c b/src/do_tel.c new file mode 100644 index 0000000..396037e --- /dev/null +++ b/src/do_tel.c @@ -0,0 +1,350 @@ + +#include "fh.h" + + +#define MAX_OBS_LOCS 5000 + + +extern int first_pass, species_number, truncate_name, + num_transactions; +extern char input_line[256], *ship_name(); +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct ship_data *ship; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_TELESCOPE_command () +{ + int i, n, found, range_in_parsecs, max_range, alien_index, + alien_number, alien_nampla_index, alien_ship_index, + location_printed, industry, detection_chance, num_obs_locs, + alien_name_printed, loc_index, success_chance, something_found; + + long x, y, z, max_distance, max_distance_squared, + delta_x, delta_y, delta_z, distance_squared; + + char planet_type[32], obs_x[MAX_OBS_LOCS], obs_y[MAX_OBS_LOCS], + obs_z[MAX_OBS_LOCS]; + + struct species_data *alien; + struct nampla_data *alien_nampla; + struct ship_data *starbase, *alien_ship; + + + found = get_ship (); + if (! found || ship->type != STARBASE) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid starbase name in TELESCOPE command.\n"); + return; + } + starbase = ship; + + /* Make sure starbase does not get more than one TELESCOPE order per + turn. */ + if (starbase->dest_z != 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! A starbase may only be given one TELESCOPE order per turn.\n"); + return; + } + starbase->dest_z = 99; + + /* Get range of telescope. */ + range_in_parsecs = starbase->item_quantity[GT] / 2; + if (range_in_parsecs < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Starbase is not carrying enough gravitic telescope units.\n"); + return; + } + + /* Log the result. */ + if (first_pass) + { + log_string (" A gravitic telescope at "); + log_int (starbase->x); log_char (' '); + log_int (starbase->y); log_char (' '); + log_int (starbase->z); + log_string (" will be operated by "); + log_string (ship_name (starbase)); + log_string (".\n"); + return; + } + + /* Define range parameters. */ + max_range = (int) species->tech_level[GV] / 10; + if (range_in_parsecs > max_range) range_in_parsecs = max_range; + + x = starbase->x; + y = starbase->y; + z = starbase->z; + + max_distance = range_in_parsecs; + max_distance_squared = max_distance * max_distance; + + /* First pass. Simply create a list of X Y Z locations that have observable + aliens. */ + num_obs_locs = 0; + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (! data_in_memory[alien_index]) continue; + + alien_number = alien_index + 1; + if (alien_number == species_number) continue; + + alien = &spec_data[alien_index]; + + alien_nampla = namp_data[alien_index] - 1; + for (alien_nampla_index = 0; alien_nampla_index < alien->num_namplas; + alien_nampla_index++) + { + ++alien_nampla; + + if ((alien_nampla->status & POPULATED) == 0) continue; + + delta_x = x - alien_nampla->x; + delta_y = y - alien_nampla->y; + delta_z = z - alien_nampla->z; + distance_squared = (delta_x * delta_x) + (delta_y * delta_y) + + (delta_z * delta_z); + + if (distance_squared == 0) continue; /* Same loc as telescope. */ + if (distance_squared > max_distance_squared) continue; + + found = FALSE; + for (i = 0; i < num_obs_locs; i++) + { + if (alien_nampla->x != obs_x[i]) continue; + if (alien_nampla->y != obs_y[i]) continue; + if (alien_nampla->z != obs_z[i]) continue; + + found = TRUE; + break; + } + if (! found) + { + if (num_obs_locs == MAX_OBS_LOCS) + { + fprintf (stderr, "\n\nInternal error! MAX_OBS_LOCS exceeded in do_tel.c!\n\n"); + exit (-1); + } + obs_x[num_obs_locs] = alien_nampla->x; + obs_y[num_obs_locs] = alien_nampla->y; + obs_z[num_obs_locs] = alien_nampla->z; + + ++num_obs_locs; + } + } + + alien_ship = ship_data[alien_index] - 1; + for (alien_ship_index = 0; alien_ship_index < alien->num_ships; + alien_ship_index++) + { + ++alien_ship; + + if (alien_ship->status == UNDER_CONSTRUCTION) continue; + if (alien_ship->status == ON_SURFACE) continue; + if (alien_ship->item_quantity[FD] == alien_ship->tonnage) continue; + + delta_x = x - alien_ship->x; + delta_y = y - alien_ship->y; + delta_z = z - alien_ship->z; + distance_squared = (delta_x * delta_x) + (delta_y * delta_y) + + (delta_z * delta_z); + + if (distance_squared == 0) continue; /* Same loc as telescope. */ + if (distance_squared > max_distance_squared) continue; + + found = FALSE; + for (i = 0; i < num_obs_locs; i++) + { + if (alien_ship->x != obs_x[i]) continue; + if (alien_ship->y != obs_y[i]) continue; + if (alien_ship->z != obs_z[i]) continue; + + found = TRUE; + break; + } + if (! found) + { + if (num_obs_locs == MAX_OBS_LOCS) + { + fprintf (stderr, "\n\nInternal error! MAX_OBS_LOCS exceeded in do_tel.c!\n\n"); + exit (-1); + } + obs_x[num_obs_locs] = alien_ship->x; + obs_y[num_obs_locs] = alien_ship->y; + obs_z[num_obs_locs] = alien_ship->z; + + ++num_obs_locs; + } + } + } + + /* Operate the gravitic telescope. */ + log_string ("\n Results of operation of gravitic telescope by "); + log_string (ship_name (starbase)); log_string (" (location = "); + log_int (starbase->x); log_char (' '); + log_int (starbase->y); log_char (' '); + log_int (starbase->z); + log_string (", max range = "); + log_int (range_in_parsecs); log_string (" parsecs):\n"); + + something_found = FALSE; + + for (loc_index = 0; loc_index < num_obs_locs; loc_index++) + { + x = obs_x[loc_index]; + y = obs_y[loc_index]; + z = obs_z[loc_index]; + + location_printed = FALSE; + + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (! data_in_memory[alien_index]) continue; + + alien_number = alien_index + 1; + if (alien_number == species_number) continue; + + alien = &spec_data[alien_index]; + + alien_name_printed = FALSE; + + alien_nampla = namp_data[alien_index] - 1; + for (alien_nampla_index = 0; alien_nampla_index < alien->num_namplas; + alien_nampla_index++) + { + ++alien_nampla; + + if ((alien_nampla->status & POPULATED) == 0) continue; + if (alien_nampla->x != x) continue; + if (alien_nampla->y != y) continue; + if (alien_nampla->z != z) continue; + + industry = alien_nampla->mi_base + alien_nampla->ma_base; + + success_chance = species->tech_level[GV]; + success_chance += starbase->item_quantity[GT]; + success_chance += (industry - 500) / 20; + if (alien_nampla->hiding || alien_nampla->hidden) + success_chance /= 10; + + if (rnd(100) > success_chance) continue; + + if (industry < 100) + industry = (industry + 5)/10; + else + industry = ((industry + 50)/100) * 10; + + if (alien_nampla->status & HOME_PLANET) + strcpy (planet_type, "Home planet"); + else if (alien_nampla->status & RESORT_COLONY) + strcpy (planet_type, "Resort colony"); + else if (alien_nampla->status & MINING_COLONY) + strcpy (planet_type, "Mining colony"); + else + strcpy (planet_type, "Colony"); + + if (! alien_name_printed) + { + if (! location_printed) + { + fprintf (log_file, "\n %ld%3ld%3ld:\n", x, y, z); + location_printed = TRUE; + something_found = TRUE; + } + fprintf (log_file, " SP %s:\n", alien->name); + alien_name_printed = TRUE; + } + + fprintf (log_file, "\t#%d: %s PL %s (%d)\n", + alien_nampla->pn, planet_type, alien_nampla->name, industry); + } + + alien_ship = ship_data[alien_index] - 1; + for (alien_ship_index = 0; alien_ship_index < alien->num_ships; + alien_ship_index++) + { + ++alien_ship; + + if (alien_ship->x != x) continue; + if (alien_ship->y != y) continue; + if (alien_ship->z != z) continue; + if (alien_ship->status == UNDER_CONSTRUCTION) continue; + if (alien_ship->status == ON_SURFACE) continue; + if (alien_ship->item_quantity[FD] == alien_ship->tonnage) continue; + + success_chance = species->tech_level[GV]; + success_chance += starbase->item_quantity[GT]; + success_chance += alien_ship->tonnage - 10; + if (alien_ship->type == STARBASE) success_chance *= 2; + if (alien_ship->class == TR) + success_chance = (3 * success_chance) / 2; + if (rnd(100) > success_chance) continue; + + if (! alien_name_printed) + { + if (! location_printed) + { + fprintf (log_file, "\n %ld%3ld%3ld:\n", x, y, z); + location_printed = TRUE; + something_found = TRUE; + } + fprintf (log_file, " SP %s:\n", alien->name); + alien_name_printed = TRUE; + } + + truncate_name = FALSE; + fprintf (log_file, "\t%s", ship_name (alien_ship)); + truncate_name = TRUE; + + /* See if alien detected that it is being observed. */ + if (alien_ship->type == STARBASE) + { + detection_chance = 2 * alien_ship->item_quantity[GT]; + if (detection_chance > 0) + { + fprintf (log_file, " <- %d GTs installed!", + alien_ship->item_quantity[GT]); + } + } + else + detection_chance = 0; + + fprintf (log_file, "\n"); + + detection_chance += 2 * + ((int) alien->tech_level[GV] - (int) species->tech_level[GV]); + + if (rnd(100) > detection_chance) continue; + + /* Define this transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = TELESCOPE_DETECTION; + transaction[n].x = starbase->x; + transaction[n].y = starbase->y; + transaction[n].z = starbase->z; + transaction[n].number1 = alien_number; + strcpy (transaction[n].name1, ship_name (alien_ship)); + } + } + } + + if (something_found) + log_char ('\n'); + else + log_string (" No alien ships or planets were detected.\n\n"); +} diff --git a/src/do_terr.c b/src/do_terr.c new file mode 100644 index 0000000..e45b9b0 --- /dev/null +++ b/src/do_terr.c @@ -0,0 +1,262 @@ + +#include "fh.h" + + +extern int planet_data_modified, first_pass; +extern long value; +extern char input_line[256]; +extern FILE *log_file; +extern struct planet_data *planet_base, *planet; +extern struct species_data *species; +extern struct nampla_data *nampla_base, *nampla; + + +do_TERRAFORM_command () +{ + int i, j, ls_needed, num_plants, got_required_gas, + correct_percentage; + + struct planet_data *home_planet, *colony_planet; + + + /* Get number of TPs to use. */ + if (get_value ()) + num_plants = value; + else + num_plants = 0; + + /* Get planet where terraforming is to be done. */ + if (! get_location () || nampla == NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid planet name in TERRAFORM command.\n"); + return; + } + + /* Make sure planet is not a home planet. */ + if (nampla->status & HOME_PLANET) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Terraforming may not be done on a home planet.\n"); + return; + } + + /* Find out how many terraforming plants are needed. */ + colony_planet = planet_base + (long) nampla->planet_index; + home_planet = planet_base + (long) nampla_base->planet_index; + + ls_needed = life_support_needed (species, home_planet, colony_planet); + + if (ls_needed == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Colony does not need to be terraformed.\n"); + return; + } + + if (num_plants == 0) num_plants = nampla->item_quantity[TP]; + if (num_plants > ls_needed) num_plants = ls_needed; + num_plants = num_plants / 3; + num_plants *= 3; + + if (num_plants < 3) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! At least three TPs are needed to terraform.\n"); + return; + } + + if (num_plants > nampla->item_quantity[TP]) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! PL %s doesn't have that many TPs!\n", + nampla->name); + return; + } + + /* Log results. */ + log_string (" PL "); log_string (nampla->name); + log_string (" was terraformed using "); log_int (num_plants); + log_string (" Terraforming Unit"); + if (num_plants != 1) log_char ('s'); + log_string (".\n"); + + nampla->item_quantity[TP] -= num_plants; + planet_data_modified = TRUE; + + /* Terraform the planet. */ + while (num_plants > 1) + { + got_required_gas = FALSE; + correct_percentage = FALSE; + for (j = 0; j < 4; j++) /* Check gases on planet. */ + { + for (i = 0; i < 6; i++) /* Compare with poisonous gases. */ + { + if (colony_planet->gas[j] == species->required_gas) + { + got_required_gas = j + 1; + + if (colony_planet->gas_percent[j] >= species->required_gas_min + && colony_planet->gas_percent[j] <= species->required_gas_max) + correct_percentage = TRUE; + } + + if (species->poison_gas[i] == colony_planet->gas[j]) + { + colony_planet->gas[j] = 0; + colony_planet->gas_percent[j] = 0; + + /* Make sure percentages add up to 100%. */ + fix_gases (colony_planet); + + goto next_change; + } + } + } + + if (got_required_gas && correct_percentage) goto do_temp; + + j = 0; /* If all 4 gases are neutral gases, replace the first one. */ + + if (got_required_gas) + j = got_required_gas - 1; + else + { + for (i = 0; i < 4; i++) + { + if (colony_planet->gas_percent[i] == 0) + { + j = i; + break; + } + } + } + + colony_planet->gas[j] = species->required_gas; + i = species->required_gas_max - species->required_gas_min; + colony_planet->gas_percent[j] = species->required_gas_min + rnd (i); + + /* Make sure percentages add up to 100%. */ + fix_gases (colony_planet); + + goto next_change; + +do_temp: + + if (colony_planet->temperature_class != home_planet->temperature_class) + { + if (colony_planet->temperature_class > home_planet->temperature_class) + --colony_planet->temperature_class; + else + ++colony_planet->temperature_class; + + goto next_change; + } + + if (colony_planet->pressure_class != home_planet->pressure_class) + { + if (colony_planet->pressure_class > home_planet->pressure_class) + --colony_planet->pressure_class; + else + ++colony_planet->pressure_class; + } + +next_change: + + num_plants -= 3; + } +} + + +fix_gases (pl) + +struct planet_data *pl; + +{ + int i, j, total, left, add_neutral; + + long n; + + + total = 0; + for (i = 0; i < 4; i++) total += pl->gas_percent[i]; + + if (total == 100) return; + + left = 100 - total; + + /* If we have at least one gas that is not the required gas, then we + simply need to adjust existing gases. Otherwise, we have to add a + neutral gas. */ + add_neutral = TRUE; + for (i = 0; i < 4; i++) + { + if (pl->gas_percent[i] == 0) continue; + + if (pl->gas[i] == species->required_gas) continue; + + add_neutral = FALSE; + + break; + } + + if (add_neutral) goto add_neutral_gas; + + /* Randomly modify existing non-required gases until total percentage + is exactly 100. */ + while (left != 0) + { + i = rnd(4) - 1; + + if (pl->gas_percent[i] == 0) continue; + + if (pl->gas[i] == species->required_gas) continue; + + if (left > 0) + { + if (left > 2) + j = rnd(left); + else + j = left; + + pl->gas_percent[i] += j; + left -= j; + } + else + { + if (-left > 2) + j = rnd (-left); + else + j = -left; + + if (j < pl->gas_percent[i]) + { + pl->gas_percent[i] -= j; + left += j; + } + } + } + + return; + +add_neutral_gas: + + /* If we reach this point, there is either no atmosphere or it contains + only the required gas. In either case, add a random neutral gas. */ + for (i = 0; i < 4; i++) + { + if (pl->gas_percent[i] > 0) continue; + + j = rnd(6) - 1; + pl->gas[i] = species->neutral_gas[j]; + pl->gas_percent[i] = left; + + break; + } +} diff --git a/src/do_tran.c b/src/do_tran.c new file mode 100644 index 0000000..85f864e --- /dev/null +++ b/src/do_tran.c @@ -0,0 +1,524 @@ + +#include "fh.h" + + +extern int abbr_type, abbr_index, species_number, + first_pass, num_transactions, + post_arrival_phase; +extern long value; +extern char input_line[256], original_line[256], + *input_line_pointer; +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship; +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +do_TRANSFER_command () + +{ + int i, n, item_class, item_count, capacity, transfer_type, + attempt_during_siege, siege_1_chance, siege_2_chance, + alien_number, first_try, both_args_present, need_destination; + + char c, x1, x2, y1, y2, z1, z2, *original_line_pointer, *temp_ptr, + already_notified[MAX_SPECIES]; + + long num_available, original_count; + + struct nampla_data *nampla1, *nampla2, *temp_nampla; + struct ship_data *ship1, *ship2; + + + /* Get number of items to transfer. */ + i = get_value (); + + /* Make sure value is meaningful. */ + if (i == 0 || value < 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid item count in TRANSFER command.\n"); + return; + } + original_count = value; + item_count = value; + + /* Get class of item. */ + item_class = get_class_abbr (); + + if (item_class != ITEM_CLASS) + { + /* Players sometimes accidentally use "MI" for "IU" + or "MA" for "AU". */ + if (item_class == TECH_ID && abbr_index == MI) + abbr_index = IU; + else if (item_class == TECH_ID && abbr_index == MA) + abbr_index = AU; + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid item class!\n"); + return; + } + } + item_class = abbr_index; + + /* Get source of transfer. */ + nampla1 = NULL; + nampla2 = NULL; + original_line_pointer = input_line_pointer; + if (! get_transfer_point ()) + { + /* Check for missing comma or tab after source name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + if (! get_transfer_point ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid source location in TRANSFER command.\n"); + return; + } + } + + /* Test if the order has both a source and a destination. Sometimes, + the player will accidentally omit the source if it's "obvious". */ + temp_ptr = input_line_pointer; + both_args_present = FALSE; + while (1) + { + c = *temp_ptr++; + + if (c == ';' || c == '\n') break; /* End of order. */ + + if (isalpha (c)) + { + both_args_present = TRUE; + break; + } + } + + need_destination = TRUE; + + /* Make sure everything makes sense. */ + if (abbr_type == SHIP_CLASS) + { + ship1 = ship; + + if (ship1->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s is still under construction!\n", + ship_name (ship1)); + return; + } + + if (ship1->status == FORCED_JUMP || ship1->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + x1 = ship1->x; y1 = ship1->y; z1 = ship1->z; + + num_available = ship1->item_quantity[item_class]; + +check_ship_items: + + if (item_count == 0) item_count = num_available; + if (item_count == 0) return; + + if (num_available < item_count) + { + if (both_args_present) /* Change item count to "0". */ + { + if (num_available == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s does not have specified item(s)!\n", + ship_name (ship1)); + return; + } + + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, "! Ship does not have %d units. Substituting %d for %d!\n", + item_count, num_available, item_count); + item_count = 0; + goto check_ship_items; + } + + /* Check if ship is at a planet that has the items. If so, + we'll assume that the planet is the source and the ship is + the destination. We'll look first for a planet that the + ship is actually landed on or orbiting. If that fails, + then we'll look for a planet in the same sector. */ + + first_try = TRUE; + + next_ship_try: + + nampla1 = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla1; + + if (nampla1->x != ship1->x) continue; + if (nampla1->y != ship1->y) continue; + if (nampla1->z != ship1->z) continue; + if (first_try) + { + if (nampla1->pn != ship1->pn) + continue; + } + + num_available = nampla1->item_quantity[item_class]; + if (num_available < item_count) continue; + + ship = ship1; /* Destination. */ + transfer_type = 1; /* Source = planet. */ + abbr_type = SHIP_CLASS; /* Destination type. */ + + need_destination = FALSE; + + goto get_destination; + } + + if (first_try) + { + first_try = FALSE; + goto next_ship_try; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s does not have specified item(s)!\n", + ship_name (ship1)); + return; + } + + transfer_type = 0; /* Source = ship. */ + } + else /* Source is a planet. */ + { + nampla1 = nampla; + + x1 = nampla1->x; y1 = nampla1->y; z1 = nampla1->z; + + num_available = nampla1->item_quantity[item_class]; + +check_planet_items: + + if (item_count == 0) item_count = num_available; + if (item_count == 0) return; + + if (num_available < item_count) + { + if (both_args_present) /* Change item count to "0". */ + { + if (num_available == 0) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! PL %s does not have specified item(s)!\n", + nampla1 -> name); + return; + } + + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, "! Planet does not have %d units. Substituting %d for %d!\n", + item_count, num_available, item_count); + item_count = 0; + goto check_planet_items; + } + + /* Check if another planet in the same sector has the items. + If so, we'll assume that it is the source and that the + named planet is the destination. */ + + temp_nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++temp_nampla; + + if (temp_nampla->x != nampla1->x) continue; + if (temp_nampla->y != nampla1->y) continue; + if (temp_nampla->z != nampla1->z) continue; + + num_available = temp_nampla->item_quantity[item_class]; + if (num_available < item_count) continue; + + nampla = nampla1; /* Destination. */ + nampla1 = temp_nampla; /* Source. */ + transfer_type = 1; /* Source = planet. */ + abbr_type = PLANET_ID; /* Destination type. */ + + need_destination = FALSE; + + goto get_destination; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! PL %s does not have specified item(s)!\n", + nampla1 -> name); + return; + } + + transfer_type = 1; /* Source = planet. */ + } + +get_destination: + + /* Get destination of transfer. */ + if (need_destination) + { + if (! get_transfer_point ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid destination location.\n"); + return; + } + } + + /* Make sure everything makes sense. */ + if (abbr_type == SHIP_CLASS) + { + ship2 = ship; + + if (ship2->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s is still under construction!\n", + ship_name (ship2)); + return; + } + + if (ship2->status == FORCED_JUMP || ship2->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Check if destination ship has sufficient carrying capacity. */ + if (ship2->class == TR) + capacity = (10 + ((int) ship2->tonnage / 2)) * (int) ship2->tonnage; + else if (ship2->class == BA) + capacity = 10 * ship2->tonnage; + else + capacity = ship2->tonnage; + + for (i = 0; i < MAX_ITEMS; i++) + capacity -= ship2->item_quantity[i] * item_carry_capacity[i]; + + do_capacity: + + if (original_count == 0) + { + i = capacity / item_carry_capacity[item_class]; + if (i < item_count) item_count = i; + if (item_count == 0) return; + } + + if (capacity < item_count * item_carry_capacity[item_class]) + { + fprintf (log_file, "! WARNING: %s", original_line); + fprintf (log_file, "! %s does not have sufficient carrying capacity!", + ship_name (ship2)); + fprintf (log_file, " Changed %d to 0.\n", original_count); + original_count = 0; + goto do_capacity; + } + + x2 = ship2->x; y2 = ship2->y; z2 = ship2->z; + } + else + { + nampla2 = nampla; + + x2 = nampla2->x; y2 = nampla2->y; z2 = nampla2->z; + + transfer_type |= 2; + + /* If this is the post-arrival phase, then make sure the planet + is populated. */ + if (post_arrival_phase && ((nampla2->status & POPULATED) == 0)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Destination planet must be populated for post-arrival TRANSFERs.\n"); + return; + } + } + + /* Check if source and destination are in same system. */ + if (x1 != x2 || y1 != y2 || z1 != z2) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Source and destination are not at same 'x y z' in TRANSFER command.\n"); + return; + } + + /* Check for siege. */ + siege_1_chance = 0; + siege_2_chance = 0; + if (transfer_type == 3 /* Planet to planet. */ + && (nampla1->siege_eff != 0 || nampla2->siege_eff != 0)) + { + if (nampla1->siege_eff >= 0) + siege_1_chance = nampla1->siege_eff; + else + siege_1_chance = -nampla1->siege_eff; + + if (nampla2->siege_eff >= 0) + siege_2_chance = nampla2->siege_eff; + else + siege_2_chance = -nampla2->siege_eff; + + attempt_during_siege = TRUE; + } + else + attempt_during_siege = FALSE; + + /* Make the transfer and log the result. */ + log_string (" "); + + if (attempt_during_siege && first_pass) + log_string ("An attempt will be made to transfer "); + + log_int (item_count); log_char (' '); log_string (item_name[item_class]); + + if (attempt_during_siege && first_pass) + { + if (item_count > 1) log_char ('s'); + log_char (' '); + } + else + { + if (item_count > 1) + log_string ("s were transferred from "); + else + log_string (" was transferred from "); + } + + switch (transfer_type) + { + case 0: /* Ship to ship. */ + ship1->item_quantity[item_class] -= item_count; + ship2->item_quantity[item_class] += item_count; + log_string (ship_name (ship1)); log_string (" to "); + log_string (ship_name (ship2)); log_char ('.'); + break; + + case 1: /* Planet to ship. */ + nampla1->item_quantity[item_class] -= item_count; + ship2->item_quantity[item_class] += item_count; + if (item_class == CU) + { + if (nampla1 == nampla_base) + ship2->loading_point = 9999; /* Home planet. */ + else + ship2->loading_point = (nampla1 - nampla_base); + } + log_string ("PL "); log_string (nampla1->name); + log_string (" to "); log_string (ship_name (ship2)); + log_char ('.'); + break; + + case 2: /* Ship to planet. */ + ship1->item_quantity[item_class] -= item_count; + nampla2->item_quantity[item_class] += item_count; + log_string (ship_name (ship1)); log_string (" to PL "); + log_string (nampla2->name); log_char ('.'); + break; + + case 3: /* Planet to planet. */ + nampla1->item_quantity[item_class] -= item_count; + nampla2->item_quantity[item_class] += item_count; + + log_string ("PL "); log_string (nampla1->name); + log_string (" to PL "); log_string (nampla2->name); + if (attempt_during_siege) log_string (" despite the siege"); + log_char ('.'); + + if (first_pass) break; + + /* Check if either planet is under siege and if transfer + was detected by the besiegers. */ + if (rnd(100) > siege_1_chance && rnd(100) > siege_2_chance) + break; + + log_string (" However, the transfer was detected by the besiegers and the items were destroyed!!!"); + nampla2->item_quantity[item_class] -= item_count; + + for (i = 0; i < MAX_SPECIES; i++) already_notified[i] = FALSE; + + for (i = 0; i < num_transactions; i++) + { + /* Find out who is besieging this planet. */ + if (transaction[i].type != BESIEGE_PLANET) continue; + if (transaction[i].x != nampla->x) continue; + if (transaction[i].y != nampla->y) continue; + if (transaction[i].z != nampla->z) continue; + if (transaction[i].pn != nampla->pn) continue; + if (transaction[i].number2 != species_number) continue; + + alien_number = transaction[i].number1; + + if (already_notified[alien_number - 1]) continue; + + /* Define a 'detection' transaction. */ + if (num_transactions == MAX_TRANSACTIONS) + { + fprintf (stderr, "\n\n\tERROR! num_transactions > MAX_TRANSACTIONS!\n\n"); + exit (-1); + } + + n = num_transactions++; + transaction[n].type = DETECTION_DURING_SIEGE; + transaction[n].value = 4; /* Transfer of items. */ + transaction[n].number1 = item_count; + transaction[n].number2 = item_class; + if (siege_1_chance > siege_2_chance) + { + /* Besieged planet is the source of the transfer. */ + transaction[n].value = 4; + strcpy (transaction[n].name1, nampla1->name); + strcpy (transaction[n].name2, nampla2->name); + } + else + { + /* Besieged planet is the destination of the transfer. */ + transaction[n].value = 5; + strcpy (transaction[n].name1, nampla2->name); + strcpy (transaction[n].name2, nampla1->name); + } + strcpy (transaction[n].name3, species->name); + transaction[n].number3 = alien_number; + + already_notified[alien_number - 1] = TRUE; + } + + break; + + default: /* Internal error. */ + fprintf (stderr, "\n\n\tInternal error: transfer type!\n\n"); + exit (-1); + } + + log_char ('\n'); + + if (nampla1 != NULL) check_population (nampla1); + if (nampla2 != NULL) check_population (nampla2); +} diff --git a/src/do_unl.c b/src/do_unl.c new file mode 100644 index 0000000..11df652 --- /dev/null +++ b/src/do_unl.c @@ -0,0 +1,176 @@ + +#include "fh.h" + + +extern int species_number; +extern char input_line[256]; +extern FILE *log_file; +extern struct galaxy_data galaxy; +extern struct species_data *species; +extern struct nampla_data *nampla, *nampla_base; +extern struct ship_data *ship; + + +do_UNLOAD_command () +{ + int i, found, item_count, recovering_home_planet, alien_index; + + long n, reb, current_pop; + + struct nampla_data *alien_home_nampla; + + + /* Get the ship. */ + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid ship name in UNLOAD command.\n"); + return; + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship is still under construction.\n"); + return; + } + + if (ship->status == FORCED_JUMP || ship->status == JUMPED_IN_COMBAT) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship jumped during combat and is still in transit.\n"); + return; + } + + /* Find which planet the ship is at. */ + found = FALSE; + nampla = nampla_base - 1; + for (i = 0; i < species->num_namplas; i++) + { + ++nampla; + if (ship->x != nampla->x) continue; + if (ship->y != nampla->y) continue; + if (ship->z != nampla->z) continue; + if (ship->pn != nampla->pn) continue; + found = TRUE; + break; + } + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Ship is not at a named planet.\n"); + return; + } + + /* Make sure this is not someone else's populated homeworld. */ + for (alien_index = 0; alien_index < galaxy.num_species; alien_index++) + { + if (species_number == alien_index + 1) continue; + if (! data_in_memory[alien_index]) continue; + + alien_home_nampla = namp_data[alien_index]; + + if (alien_home_nampla->x != nampla->x) continue; + if (alien_home_nampla->y != nampla->y) continue; + if (alien_home_nampla->z != nampla->z) continue; + if (alien_home_nampla->pn != nampla->pn) continue; + if ((alien_home_nampla->status & POPULATED) == 0) continue; + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! You may not colonize someone else's populated home planet!\n"); + + return; + } + + /* Make sure it's not a healthy home planet. */ + recovering_home_planet = FALSE; + if (nampla->status & HOME_PLANET) + { + n = nampla->mi_base + nampla->ma_base + nampla->IUs_to_install + + nampla->AUs_to_install; + reb = species->hp_original_base - n; + + if (reb > 0) + recovering_home_planet = TRUE; /* HP was bombed. */ + else + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Installation not allowed on a healthy home planet!\n"); + return; + } + } + + /* Transfer the items from the ship to the planet. */ + log_string (" "); + + item_count = ship->item_quantity[CU]; + nampla->item_quantity[CU] += item_count; + log_int (item_count); log_char (' '); + log_string (item_abbr[CU]); if (item_count != 1) log_char ('s'); + ship->item_quantity[CU] = 0; + + item_count = ship->item_quantity[IU]; + nampla->item_quantity[IU] += item_count; + log_string (", "); + log_int (item_count); log_char (' '); + log_string (item_abbr[IU]); if (item_count != 1) log_char ('s'); + ship->item_quantity[IU] = 0; + + item_count = ship->item_quantity[AU]; + nampla->item_quantity[AU] += item_count; + log_string (", and "); + log_int (item_count); log_char (' '); + log_string (item_abbr[AU]); if (item_count != 1) log_char ('s'); + ship->item_quantity[AU] = 0; + + log_string (" were transferred from "); + log_string (ship_name (ship)); + log_string (" to PL "); + log_string (nampla->name); log_string (". "); + + /* Do the installation. */ + item_count = nampla->item_quantity[CU]; + if (item_count > nampla->item_quantity[IU]) + item_count = nampla->item_quantity[IU]; + if (recovering_home_planet) + { + if (item_count > reb) item_count = reb; + reb -= item_count; + } + + nampla->item_quantity[CU] -= item_count; + nampla->item_quantity[IU] -= item_count; + nampla->IUs_to_install += item_count; + current_pop += item_count; + + log_string ("Installation of "); + log_int (item_count); log_char (' '); + log_string (item_abbr[IU]); if (item_count != 1) log_char ('s'); + + item_count = nampla->item_quantity[CU]; + if (item_count > nampla->item_quantity[AU]) + item_count = nampla->item_quantity[AU]; + if (recovering_home_planet) + { + if (item_count > reb) item_count = reb; + reb -= item_count; + } + + nampla->item_quantity[CU] -= item_count; + nampla->item_quantity[AU] -= item_count; + nampla->AUs_to_install += item_count; + + log_string (" and "); + log_int (item_count); log_char (' '); + log_string (item_abbr[AU]); if (item_count != 1) log_char ('s'); + log_string (" began on the planet.\n"); + + check_population (nampla); +} diff --git a/src/do_upg.c b/src/do_upg.c new file mode 100644 index 0000000..7f344b6 --- /dev/null +++ b/src/do_upg.c @@ -0,0 +1,155 @@ + +#include "fh.h" + + +extern int doing_production; +extern long value, balance, EU_spending_limit; +extern char input_line[256], original_line[256], *input_line_pointer; +extern FILE *log_file; + +extern struct species_data *species; +extern struct nampla_data *nampla; +extern struct ship_data *ship; + + +do_UPGRADE_command () +{ + int age_reduction, value_specified; + + char *original_line_pointer; + + long amount_to_spend, original_cost, max_funds_available; + + + /* Check if this order was preceded by a PRODUCTION order. */ + if (!doing_production) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Missing PRODUCTION order!\n"); + return; + } + + /* Get the ship to be upgraded. */ + original_line_pointer = input_line_pointer; + if (! get_ship ()) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + if (! get_ship ()) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship to be upgraded does not exist.\n"); + return; + } + } + + /* Make sure it didn't just jump. */ + if (ship->just_jumped) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship just jumped and is still in transit.\n"); + return; + } + + /* Make sure it's in the same sector as the producing planet. */ + if (ship->x != nampla->x || ship->y != nampla->y + || ship->z != nampla->z) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Item to be upgraded is not in the same sector as the production planet.\n"); + return; + } + + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Item to be upgraded is still under construction.\n"); + return; + } + + if (ship->age < 1) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Ship or starbase is too new to upgrade.\n"); + return; + } + + /* Calculate the original cost of the ship. */ + if (ship->class == TR || ship->type == STARBASE) + original_cost = ship_cost[ship->class] * ship->tonnage; + else + original_cost = ship_cost[ship->class]; + + if (ship->type == SUB_LIGHT) + original_cost = (3 * original_cost) / 4; + + /* Get amount to be spent. */ + if (value_specified = get_value ()) + { + if (value == 0) + amount_to_spend = balance; + else + amount_to_spend = value; + + age_reduction = (40 * amount_to_spend) / original_cost; + } + else + age_reduction = ship->age; + +try_again: + + if (age_reduction < 1) + { + if (value == 0) return; + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Amount specified is not enough to do an upgrade.\n"); + return; + } + + if (age_reduction > ship->age) age_reduction = ship->age; + + /* Check if sufficient funds are available. */ + amount_to_spend = ((age_reduction * original_cost) + 39) / 40; + if (check_bounced (amount_to_spend)) + { + max_funds_available = species->econ_units; + if (max_funds_available > EU_spending_limit) + max_funds_available = EU_spending_limit; + max_funds_available += balance; + + if (max_funds_available > 0) + { + if (value_specified) + { + fprintf (log_file, "! WARNING: %s", input_line); + fprintf (log_file, "! Insufficient funds. Substituting %ld for %ld.\n", + max_funds_available, value); + } + amount_to_spend = max_funds_available; + age_reduction = (40 * amount_to_spend) / original_cost; + goto try_again; + } + + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Insufficient funds to execute order.\n"); + return; + } + + /* Log what was upgraded. */ + log_string (" "); log_string (ship_name (ship)); + log_string (" was upgraded from age "); + log_int ((int) ship->age); log_string (" to age "); + ship->age -= age_reduction; + log_int ((int) ship->age); + log_string (" at a cost of "); log_long (amount_to_spend); + log_string (".\n"); +} diff --git a/src/do_vis.c b/src/do_vis.c new file mode 100644 index 0000000..4402d30 --- /dev/null +++ b/src/do_vis.c @@ -0,0 +1,42 @@ + +#include "fh.h" + + +extern int x, y, z; +extern char input_line[256]; +extern FILE *log_file; +extern struct nampla_data *nampla; + + +do_VISITED_command () +{ + int found; + + + /* Get x y z coordinates. */ + found = get_location (); + if (! found || nampla != NULL) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! Invalid coordinates in VISITED command.\n"); + return; + } + + found = star_visited (x, y, z); + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", input_line); + fprintf (log_file, "!!! There is no star system at these coordinates.\n"); + return; + } + + /* Log result. */ + log_string (" The star system at "); + log_int (x); log_char (' '); + log_int (y); log_char (' '); + log_int (z); + log_string (" was marked as visited.\n"); +} diff --git a/src/do_worm.c b/src/do_worm.c new file mode 100644 index 0000000..42ac50d --- /dev/null +++ b/src/do_worm.c @@ -0,0 +1,128 @@ + +#include "fh.h" + + +extern int num_stars, first_pass; +extern char input_line[256], original_line[256], + *input_line_pointer; +extern FILE *log_file; +extern struct star_data *star_base; +extern struct nampla_data *nampla; +extern struct ship_data *ship; + + +do_WORMHOLE_command () + +{ + int i, found, status; + + char *original_line_pointer; + + struct star_data *star; + + + /* Get ship making the jump. */ + original_line_pointer = input_line_pointer; + found = get_ship (); + if (! found) + { + /* Check for missing comma or tab after ship name. */ + input_line_pointer = original_line_pointer; + fix_separator (); + found = get_ship (); + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! Invalid ship name in WORMHOLE command.\n"); + return; + } + } + + /* Make sure ship is not salvage of a disbanded colony. */ + if (disbanded_ship (ship)) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! This ship is salvage of a disbanded colony!\n"); + return; + } + + /* Make sure ship can jump. */ + if (ship->status == UNDER_CONSTRUCTION) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s is still under construction!\n", + ship_name (ship)); + return; + } + + /* Check if JUMP, MOVE, or WORMHOLE was already done for this ship. */ + if (ship->just_jumped) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! %s already jumped or moved this turn!\n", + ship_name (ship)); + return; + } + + /* Find star. */ + star = star_base; + found = FALSE; + for (i = 0; i < num_stars; i++) + { + if (star->x == ship->x && star->y == ship->y && star->z == ship->z) + { + found = star->worm_here; + break; + } + ++star; + } + + if (! found) + { + fprintf (log_file, "!!! Order ignored:\n"); + fprintf (log_file, "!!! %s", original_line); + fprintf (log_file, "!!! There is no wormhole at ship's location!\n"); + return; + } + + /* Get the destination planet, if any. */ + get_location(); + if (nampla != NULL) + { + if (nampla->x != star->worm_x || nampla->y != star->worm_y + || nampla->z != star->worm_z) + { + fprintf (log_file, "!!! WARNING - Destination planet is not at other end of wormhole!\n"); + nampla = NULL; + } + } + + /* Do the jump. */ + log_string (" "); + log_string (ship_name (ship)); + log_string (" will jump via natural wormhole at "); + log_int (ship->x); log_char (' '); + log_int (ship->y); log_char (' '); + log_int (ship->z); + ship->pn = 0; + ship->status = IN_DEEP_SPACE; + + if (nampla != NULL) + { + log_string (" to PL "); + log_string (nampla->name); + ship->pn = nampla->pn; + ship->status = IN_ORBIT; + } + log_string (".\n"); + ship->x = star->worm_x; + ship->y = star->worm_y; + ship->z = star->worm_z; + ship->just_jumped = 99; /* 99 indicates that a wormhole was used. */ + + if (! first_pass) star_visited (ship->x, ship->y, ship->z); +} diff --git a/src/fh.h b/src/fh.h new file mode 100644 index 0000000..80777f4 --- /dev/null +++ b/src/fh.h @@ -0,0 +1,672 @@ + +#include +#include +#include +#include + + +#define TRUE 1 +#define FALSE 0 + + +#define STANDARD_NUMBER_OF_SPECIES 15 + /* A standard game has 15 species. */ +#define STANDARD_NUMBER_OF_STAR_SYSTEMS 90 + /* A standard game has 90 star systems. */ +#define STANDARD_GALACTIC_RADIUS 20 + /* A standard game has a galaxy with a radius of 20 parsecs. */ + + +/* Minimum and maximum values for a galaxy. */ +#define MIN_SPECIES 1 +#define MAX_SPECIES 100 +#define MIN_STARS 12 +#define MAX_STARS 1000 +#define MIN_RADIUS 6 +#define MAX_RADIUS 50 +#define MAX_DIAMETER 2*MAX_RADIUS +#define MAX_PLANETS 9*MAX_STARS + +#define HP_AVAILABLE_POP 1500 + +#define NUM_EXTRA_NAMPLAS 50 +#define NUM_EXTRA_SHIPS 100 + + +#define MAX_LOCATIONS 10000 +struct sp_loc_data +{ + char s, x, y, z; /* Species number, x, y, and z. */ +}; + + +struct galaxy_data +{ + int d_num_species; /* Design number of species in galaxy. */ + int num_species; /* Actual number of species allocated. */ + int radius; /* Galactic radius in parsecs. */ + int turn_number; /* Current turn number. */ +}; + + +/* Assume at least 32 bits per long word. */ +#define NUM_CONTACT_WORDS ((MAX_SPECIES - 1) / 32) + 1 + + +/* Star types. */ +#define DWARF 1 +#define DEGENERATE 2 +#define MAIN_SEQUENCE 3 +#define GIANT 4 + +/* Star Colors. */ +#define BLUE 1 +#define BLUE_WHITE 2 +#define WHITE 3 +#define YELLOW_WHITE 4 +#define YELLOW 5 +#define ORANGE 6 +#define RED 7 + +struct star_data +{ + char x,y,z; /* Coordinates. */ + char type; /* Dwarf, degenerate, main sequence or giant. */ + char color; /* Star color. Blue, blue-white, etc. */ + char size; /* Star size, from 0 thru 9 inclusive. */ + char num_planets; /* Number of usable planets in star system. */ + char home_system; /* TRUE if this is a good potential home system. */ + char worm_here; /* TRUE if wormhole entry/exit. */ + char worm_x, worm_y, worm_z; + short reserved1; /* Reserved for future use. Zero for now. */ + short reserved2; /* Reserved for future use. Zero for now. */ + short planet_index; /* Index (starting at zero) into the file + "planets.dat" of the first planet in the + star system. */ + long message; /* Message associated with this star system, + if any. */ + long visited_by[NUM_CONTACT_WORDS]; + /* A bit is set if corresponding species has + been here. */ + long reserved3; /* Reserved for future use. Zero for now. */ + long reserved4; /* Reserved for future use. Zero for now. */ + long reserved5; /* Reserved for future use. Zero for now. */ +}; + + +/* Gases in planetary atmospheres. */ +#define H2 1 /* Hydrogen */ +#define CH4 2 /* Methane */ +#define HE 3 /* Helium */ +#define NH3 4 /* Ammonia */ +#define N2 5 /* Nitrogen */ +#define CO2 6 /* Carbon Dioxide */ +#define O2 7 /* Oxygen */ +#define HCL 8 /* Hydrogen Chloride */ +#define CL2 9 /* Chlorine */ +#define F2 10 /* Fluorine */ +#define H2O 11 /* Steam */ +#define SO2 12 /* Sulfur Dioxide */ +#define H2S 13 /* Hydrogen Sulfide */ + +struct planet_data +{ + char temperature_class; /* Temperature class, 1-30. */ + char pressure_class; /* Pressure class, 0-29. */ + char special; /* 0 = not special, 1 = ideal home planet, + 2 = ideal colony planet, 3 = radioactive + hellhole. */ + char reserved1; /* Reserved for future use. Zero for now. */ + char gas[4]; /* Gas in atmosphere. Zero if none. */ + char gas_percent[4]; /* Percentage of gas in atmosphere. */ + short reserved2; /* Reserved for future use. Zero for now. */ + short diameter; /* Diameter in thousands of kilometers. */ + short gravity; /* Surface gravity. Multiple of Earth + gravity times 100. */ + short mining_difficulty; /* Mining difficulty times 100. */ + short econ_efficiency; /* Economic efficiency. Always 100 for a + home planet. */ + short md_increase; /* Increase in mining difficulty. */ + long message; /* Message associated with this planet, + if any. */ + long reserved3; /* Reserved for future use. Zero for now. */ + long reserved4; /* Reserved for future use. Zero for now. */ + long reserved5; /* Reserved for future use. Zero for now. */ +}; + + +/* Tech level ids. */ +#define MI 0 /* Mining tech level. */ +#define MA 1 /* Manufacturing tech level. */ +#define ML 2 /* Military tech level. */ +#define GV 3 /* Gravitics tech level. */ +#define LS 4 /* Life Support tech level. */ +#define BI 5 /* Biology tech level. */ + +struct species_data +{ + char name[32]; /* Name of species. */ + char govt_name[32]; /* Name of government. */ + char govt_type[32]; /* Type of government. */ + char x, y, z, pn; /* Coordinates of home planet. */ + char required_gas; /* Gas required by species. */ + char required_gas_min; /* Minimum needed percentage. */ + char required_gas_max; /* Maximum allowed percentage. */ + char reserved5; /* Zero for now. */ + char neutral_gas[6]; /* Gases neutral to species. */ + char poison_gas[6]; /* Gases poisonous to species. */ + char auto_orders; /* AUTO command was issued. */ + char reserved3; /* Zero for now. */ + short reserved4; /* Zero for now. */ + short tech_level[6]; /* Actual tech levels. */ + short init_tech_level[6]; /* Tech levels at start of turn. */ + short tech_knowledge[6]; /* Unapplied tech level knowledge. */ + int num_namplas; /* Number of named planets, including + home planet and colonies. */ + int num_ships; /* Number of ships. */ + long tech_eps[6]; /* Experience points for tech levels. */ + long hp_original_base; /* If non-zero, home planet was bombed + either by bombardment or germ + warfare and has not yet fully + recovered. Value is total economic + base before bombing. */ + long econ_units; /* Number of economic units. */ + long fleet_cost; /* Total fleet maintenance cost. */ + long fleet_percent_cost; /* Fleet maintenance cost as a + percentage times one hundred. */ + long contact[NUM_CONTACT_WORDS]; + /* A bit is set if corresponding + species has been met. */ + long ally[NUM_CONTACT_WORDS]; + /* A bit is set if corresponding + species is considered an ally. */ + long enemy[NUM_CONTACT_WORDS]; + /* A bit is set if corresponding + species is considered an enemy. */ + char padding[12]; /* Use for expansion. Initialized to + all zeroes. */ +}; + + +/* Item IDs. */ +#define RM 0 /* Raw Material Units. */ +#define PD 1 /* Planetary Defense Units. */ +#define SU 2 /* Starbase Units. */ +#define DR 3 /* Damage Repair Units. */ +#define CU 4 /* Colonist Units. */ +#define IU 5 /* Colonial Mining Units. */ +#define AU 6 /* Colonial Manufacturing Units. */ +#define FS 7 /* Fail-Safe Jump Units. */ +#define JP 8 /* Jump Portal Units. */ +#define FM 9 /* Forced Misjump Units. */ +#define FJ 10 /* Forced Jump Units. */ +#define GT 11 /* Gravitic Telescope Units. */ +#define FD 12 /* Field Distortion Units. */ +#define TP 13 /* Terraforming Plants. */ +#define GW 14 /* Germ Warfare Bombs. */ +#define SG1 15 /* Mark-1 Auxiliary Shield Generators. */ +#define SG2 16 /* Mark-2. */ +#define SG3 17 /* Mark-3. */ +#define SG4 18 /* Mark-4. */ +#define SG5 19 /* Mark-5. */ +#define SG6 20 /* Mark-6. */ +#define SG7 21 /* Mark-7. */ +#define SG8 22 /* Mark-8. */ +#define SG9 23 /* Mark-9. */ +#define GU1 24 /* Mark-1 Auxiliary Gun Units. */ +#define GU2 25 /* Mark-2. */ +#define GU3 26 /* Mark-3. */ +#define GU4 27 /* Mark-4. */ +#define GU5 28 /* Mark-5. */ +#define GU6 29 /* Mark-6. */ +#define GU7 30 /* Mark-7. */ +#define GU8 31 /* Mark-8. */ +#define GU9 32 /* Mark-9. */ +#define X1 33 /* Unassigned. */ +#define X2 34 /* Unassigned. */ +#define X3 35 /* Unassigned. */ +#define X4 36 /* Unassigned. */ +#define X5 37 /* Unassigned. */ + +#define MAX_ITEMS 38 /* Always bump this up to a multiple of two. + Don't forget to make room for zeroth element! */ + + +/* Status codes for named planets. These are logically ORed together. */ +#define HOME_PLANET 1 +#define COLONY 2 +#define POPULATED 8 +#define MINING_COLONY 16 +#define RESORT_COLONY 32 +#define DISBANDED_COLONY 64 + +struct nampla_data +{ + char name[32]; /* Name of planet. */ + char x, y, z, pn; /* Coordinates. */ + char status; /* Status of planet. */ + char reserved1; /* Zero for now. */ + char hiding; /* HIDE order given. */ + char hidden; /* Colony is hidden. */ + short reserved2; /* Zero for now. */ + short planet_index; /* Index (starting at zero) into the file + "planets.dat" of this planet. */ + short siege_eff; /* Siege effectiveness - a percentage between + 0 and 99. */ + short shipyards; /* Number of shipyards on planet. */ + int reserved4; /* Zero for now. */ + int IUs_needed; /* Incoming ship with only CUs on board. */ + int AUs_needed; /* Incoming ship with only CUs on board. */ + int auto_IUs; /* Number of IUs to be automatically installed. */ + int auto_AUs; /* Number of AUs to be automatically installed. */ + int reserved5; /* Zero for now. */ + int IUs_to_install; /* Colonial mining units to be installed. */ + int AUs_to_install; /* Colonial manufacturing units to be installed. */ + long mi_base; /* Mining base times 10. */ + long ma_base; /* Manufacturing base times 10. */ + long pop_units; /* Number of available population units. */ + long item_quantity[MAX_ITEMS]; /* Quantity of each item available. */ + long reserved6; /* Zero for now. */ + long use_on_ambush; /* Amount to use on ambush. */ + long message; /* Message associated with this planet, + if any. */ + long special; /* Different for each application. */ + char padding[28]; /* Use for expansion. Initialized to + all zeroes. */ +}; + + +/* Ship classes. */ +#define PB 0 /* Picketboat. */ +#define CT 1 /* Corvette. */ +#define ES 2 /* Escort. */ +#define DD 3 /* Destroyer. */ +#define FG 4 /* Frigate. */ +#define CL 5 /* Light Cruiser. */ +#define CS 6 /* Strike Cruiser. */ +#define CA 7 /* Heavy Cruiser. */ +#define CC 8 /* Command Cruiser. */ +#define BC 9 /* Battlecruiser. */ +#define BS 10 /* Battleship. */ +#define DN 11 /* Dreadnought. */ +#define SD 12 /* Super Dreadnought. */ +#define BM 13 /* Battlemoon. */ +#define BW 14 /* Battleworld. */ +#define BR 15 /* Battlestar. */ +#define BA 16 /* Starbase. */ +#define TR 17 /* Transport. */ + +#define NUM_SHIP_CLASSES 18 + +/* Ship types. */ +#define FTL 0 +#define SUB_LIGHT 1 +#define STARBASE 2 + +/* Ship status codes. */ +#define UNDER_CONSTRUCTION 0 +#define ON_SURFACE 1 +#define IN_ORBIT 2 +#define IN_DEEP_SPACE 3 +#define JUMPED_IN_COMBAT 4 +#define FORCED_JUMP 5 + +struct ship_data +{ + char name[32]; /* Name of ship. */ + char x, y, z, pn; /* Current coordinates. */ + char status; /* Current status of ship. */ + char type; /* Ship type. */ + char dest_x, dest_y; /* Destination if ship was forced to + jump from combat. */ + char dest_z; /* Ditto. Also used by TELESCOPE command. */ + char just_jumped; /* Set if ship jumped this turn. */ + char arrived_via_wormhole; /* Ship arrived via wormhole in the + PREVIOUS turn. */ + char reserved1; /* Unused. Zero for now. */ + short reserved2; /* Unused. Zero for now. */ + short reserved3; /* Unused. Zero for now. */ + short class; /* Ship class. */ + short tonnage; /* Ship tonnage divided by 10,000. */ + short item_quantity[MAX_ITEMS]; /* Quantity of each item carried. */ + short age; /* Ship age. */ + short remaining_cost; /* The cost needed to complete the + ship if still under construction. */ + short reserved4; /* Unused. Zero for now. */ + short loading_point; /* Nampla index for planet where ship + was last loaded with CUs. Zero = + none. Use 9999 for home planet. */ + short unloading_point; /* Nampla index for planet that ship + should be given orders to jump to + where it will unload. Zero = none. + Use 9999 for home planet. */ + long special; /* Different for each application. */ + char padding[28]; /* Use for expansion. Initialized to + all zeroes. */ +}; + + +/* Interspecies transactions. */ + +#define MAX_TRANSACTIONS 1000 + +#define EU_TRANSFER 1 +#define MESSAGE_TO_SPECIES 2 +#define BESIEGE_PLANET 3 +#define SIEGE_EU_TRANSFER 4 +#define TECH_TRANSFER 5 +#define DETECTION_DURING_SIEGE 6 +#define SHIP_MISHAP 7 +#define ASSIMILATION 8 +#define INTERSPECIES_CONSTRUCTION 9 +#define TELESCOPE_DETECTION 10 +#define ALIEN_JUMP_PORTAL_USAGE 11 +#define KNOWLEDGE_TRANSFER 12 +#define LANDING_REQUEST 13 +#define LOOTING_EU_TRANSFER 14 + +struct trans_data +{ + int type; /* Transaction type. */ + short donor, recipient; + long value; /* Value of transaction. */ + char x, y, z, pn; /* Location associated with transaction. */ + long number1; /* Other items associated with transaction.*/ + char name1[40]; + long number2; + char name2[40]; + long number3; + char name3[40]; +}; + + +/* Command codes. */ +#define UNDEFINED 0 +#define ALLY 1 +#define AMBUSH 2 +#define ATTACK 3 +#define AUTO 4 +#define BASE 5 +#define BATTLE 6 +#define BUILD 7 +#define CONTINUE 8 +#define DEEP 9 +#define DESTROY 10 +#define DEVELOP 11 +#define DISBAND 12 +#define END 13 +#define ENEMY 14 +#define ENGAGE 15 +#define ESTIMATE 16 +#define HAVEN 17 +#define HIDE 18 +#define HIJACK 19 +#define IBUILD 20 +#define ICONTINUE 21 +#define INSTALL 22 +#define INTERCEPT 23 +#define JUMP 24 +#define LAND 25 +#define MESSAGE 26 +#define MOVE 27 +#define NAME 28 +#define NEUTRAL 29 +#define ORBIT 30 +#define PJUMP 31 +#define PRODUCTION 32 +#define RECYCLE 33 +#define REPAIR 34 +#define RESEARCH 35 +#define SCAN 36 +#define SEND 37 +#define SHIPYARD 38 +#define START 39 +#define SUMMARY 40 +#define SURRENDER 41 +#define TARGET 42 +#define TEACH 43 +#define TECH 44 +#define TELESCOPE 45 +#define TERRAFORM 46 +#define TRANSFER 47 +#define UNLOAD 48 +#define UPGRADE 49 +#define VISITED 50 +#define WITHDRAW 51 +#define WORMHOLE 52 +#define ZZZ 53 + +#define NUM_COMMANDS ZZZ+1 + +/* Constants needed for parsing. */ +#define UNKNOWN 0 +#define TECH_ID 1 +#define ITEM_CLASS 2 +#define SHIP_CLASS 3 +#define PLANET_ID 4 +#define SPECIES_ID 5 + + + +/* Global data used in most or all programs. */ + +#ifdef THIS_IS_MAIN + + char + type_char[] = " dD g"; + char + color_char[] = " OBAFGKM"; + char + size_char[] = "0123456789"; + char + gas_string[14][4] = + { + " ", "H2", "CH4", "He", "NH3", "N2", "CO2", + "O2", "HCl", "Cl2", "F2", "H2O", "SO2", "H2S" + }; + + char + tech_abbr[6][4] = + { + "MI", + "MA", + "ML", + "GV", + "LS", + "BI" + }; + + char + tech_name[6][16] = + { + "Mining", + "Manufacturing", + "Military", + "Gravitics", + "Life Support", + "Biology" + }; + + int data_in_memory[MAX_SPECIES]; + int data_modified[MAX_SPECIES]; + int num_new_namplas[MAX_SPECIES]; + int num_new_ships[MAX_SPECIES]; + + struct species_data spec_data[MAX_SPECIES]; + struct nampla_data *namp_data[MAX_SPECIES]; + struct ship_data *ship_data[MAX_SPECIES]; + + char + item_name[MAX_ITEMS][32] = + { + "Raw Material Unit", + "Planetary Defense Unit", + "Starbase Unit", + "Damage Repair Unit", + "Colonist Unit", + "Colonial Mining Unit", + "Colonial Manufacturing Unit", + "Fail-Safe Jump Unit", + "Jump Portal Unit", + "Forced Misjump Unit", + "Forced Jump Unit", + "Gravitic Telescope Unit", + "Field Distortion Unit", + "Terraforming Plant", + "Germ Warfare Bomb", + "Mark-1 Shield Generator", + "Mark-2 Shield Generator", + "Mark-3 Shield Generator", + "Mark-4 Shield Generator", + "Mark-5 Shield Generator", + "Mark-6 Shield Generator", + "Mark-7 Shield Generator", + "Mark-8 Shield Generator", + "Mark-9 Shield Generator", + "Mark-1 Gun Unit", + "Mark-2 Gun Unit", + "Mark-3 Gun Unit", + "Mark-4 Gun Unit", + "Mark-5 Gun Unit", + "Mark-6 Gun Unit", + "Mark-7 Gun Unit", + "Mark-8 Gun Unit", + "Mark-9 Gun Unit", + "X1 Unit", + "X2 Unit", + "X3 Unit", + "X4 Unit", + "X5 Unit", + }; + + char + item_abbr[MAX_ITEMS][4] = + { + "RM", "PD", "SU", "DR", "CU", "IU", "AU", "FS", + "JP", "FM", "FJ", "GT", "FD", "TP", "GW", "SG1", + "SG2", "SG3", "SG4", "SG5", "SG6", "SG7", "SG8", "SG9", + "GU1", "GU2", "GU3", "GU4", "GU5", "GU6", "GU7", "GU8", + "GU9", "X1", "X2", "X3", "X4", "X5" + }; + + long + item_cost[MAX_ITEMS] = + { + 1, 1, 110, 50, 1, 1, 1, 25, + 100, 100, 125, 500, 50, 50000, 1000, 250, + 500, 750, 1000, 1250, 1500, 1750, 2000, 2250, + 250, 500, 750, 1000, 1250, 1500, 1750, 2000, + 2250, 9999, 9999, 9999, 9999, 9999 + }; + + short + item_carry_capacity[MAX_ITEMS] = + { + 1, 3, 20, 1, 1, 1, 1, 1, + 10, 5, 5, 20, 1, 100, 100, 5, + 10, 15, 20, 25, 30, 35, 40, 45, + 5, 10, 15, 20, 25, 30, 35, 40, + 45, 9999, 9999, 9999, 9999, 9999 + }; + + char + item_critical_tech[MAX_ITEMS] = + { + MI, ML, MA, MA, LS, MI, MA, GV, + GV, GV, GV, GV, LS, BI, BI, LS, + LS, LS, LS, LS, LS, LS, LS, LS, + ML, ML, ML, ML, ML, ML, ML, ML, + ML, 99, 99, 99, 99, 99 + }; + + short + item_tech_requirment[MAX_ITEMS] = + { + 1, 1, 20, 30, 1, 1, 1, 20, + 25, 30, 40, 50, 20, 40, 50, 10, + 20, 30, 40, 50, 60, 70, 80, 90, + 10, 20, 30, 40, 50, 60, 70, 80, + 90, 999, 999, 999, 999, 999 + }; + + char + ship_abbr[NUM_SHIP_CLASSES][4] = + { + "PB", "CT", "ES", "FF", "DD", "CL", "CS", + "CA", "CC", "BC", "BS", "DN", "SD", "BM", + "BW", "BR", "BA", "TR" + }; + + char + ship_type[3][2] = {"", "S", "S"}; + + short + ship_tonnage[NUM_SHIP_CLASSES] = + { + 1, 2, 5, 10, 15, 20, 25, + 30, 35, 40, 45, 50, 55, 60, + 65, 70, 1, 1 + }; + + short + ship_cost[NUM_SHIP_CLASSES] = + { + 100, 200, 500, 1000, 1500, 2000, 2500, + 3000, 3500, 4000, 4500, 5000, 5500, 6000, + 6500, 7000, 100, 100 + }; + + char + command_abbr[NUM_COMMANDS][4] = + { + " ", "ALL", "AMB", "ATT", "AUT", "BAS", "BAT", "BUI", "CON", + "DEE", "DES", "DEV", "DIS", "END", "ENE", "ENG", "EST", "HAV", + "HID", "HIJ", "IBU", "ICO", "INS", "INT", "JUM", "LAN", "MES", + "MOV", "NAM", "NEU", "ORB", "PJU", "PRO", "REC", "REP", "RES", + "SCA", "SEN", "SHI", "STA", "SUM", "SUR", "TAR", "TEA", "TEC", + "TEL", "TER", "TRA", "UNL", "UPG", "VIS", "WIT", "WOR", "ZZZ" + }; + + char + command_name[NUM_COMMANDS][16] = + { + "Undefined", "Ally", "Ambush", "Attack", "Auto", "Base", + "Battle", "Build", "Continue", "Deep", "Destroy", "Develop", + "Disband", "End", "Enemy", "Engage", "Estimate", "Haven", + "Hide", "Hijack", "Ibuild", "Icontinue", "Install", "Intercept", + "Jump", "Land", "Message", "Move", "Name", "Neutral", "Orbit", + "Pjump", "Production", "Recycle", "Repair", "Research", "Scan", + "Send", "Shipyard", "Start", "Summary", "Surrender", "Target", + "Teach", "Tech", "Telescope", "Terraform", "Transfer", "Unload", + "Upgrade", "Visited", "Withdraw", "Wormhole", "ZZZ" + }; + +#else + + extern char type_char[]; + extern char color_char[]; + extern char size_char[]; + extern char gas_string[14][4]; + extern char tech_abbr[6][4]; + extern char tech_name[6][16]; + extern int data_in_memory[MAX_SPECIES]; + extern int data_modified[MAX_SPECIES]; + extern int num_new_namplas[MAX_SPECIES]; + extern int num_new_ships[MAX_SPECIES]; + extern struct species_data spec_data[MAX_SPECIES]; + extern struct nampla_data *namp_data[MAX_SPECIES]; + extern struct ship_data *ship_data[MAX_SPECIES]; + extern char item_name[MAX_ITEMS][32]; + extern char item_abbr[MAX_ITEMS][4]; + extern long item_cost[MAX_ITEMS]; + extern short item_carry_capacity[MAX_ITEMS]; + extern char item_critical_tech[MAX_ITEMS]; + extern short item_tech_requirment[MAX_ITEMS]; + extern char ship_abbr[NUM_SHIP_CLASSES][4]; + extern char ship_type[3][2]; + extern short ship_tonnage[NUM_SHIP_CLASSES]; + extern short ship_cost[NUM_SHIP_CLASSES]; + extern char command_abbr[NUM_COMMANDS][4]; + extern char command_name[NUM_COMMANDS][16]; + +#endif diff --git a/src/fight_par.c b/src/fight_par.c new file mode 100644 index 0000000..a9a619e --- /dev/null +++ b/src/fight_par.c @@ -0,0 +1,433 @@ + +/* The following routine will fill "act" with ship and nampla data necessary + for an action; i.e., number of shots per round, damage done per shot, + total shield power, etc. Note that this routine always restores shields + completely. It is assumed that a sufficient number of rounds passes + between actions of a battle to completely regenerate shields. + + The routine will return TRUE if the action can take place, otherwise + FALSE. +*/ + + +#include "fh.h" +#include "combat.h" + +extern int deep_space_defense, attacking_ML, defending_ML; + +extern struct species_data *c_species[MAX_SPECIES]; +extern struct nampla_data *c_nampla[MAX_SPECIES]; +extern struct ship_data *c_ship[MAX_SPECIES]; + +long power (); + + +int fighting_params (option, location, bat, act) + +char option, location; +struct battle_data *bat; +struct action_data *act; + +{ + char x, y, z, pn; + + int i, j, found, type, num_sp, unit_index, species_index, + ship_index, nampla_index, sp1, sp2, use_this_ship, n_shots, + engage_option, engage_location, attacking_ships_here, + defending_ships_here, attacking_pds_here, defending_pds_here, + num_fighting_units; + + short tons; + + long ml, ls, unit_power, offensive_power, defensive_power; + + struct ship_data *sh; + struct nampla_data *nam; + + + /* Add fighting units to "act" arrays. At the same time, check if + a fight of the current option type will occur at the current + location. */ + num_fighting_units = 0; + x = bat->x; + y = bat->y; + z = bat->z; + attacking_ML = 0; + defending_ML = 0; + attacking_ships_here = FALSE; + defending_ships_here = FALSE; + attacking_pds_here = FALSE; + defending_pds_here = FALSE; + deep_space_defense = FALSE; + num_sp = bat->num_species_here; + + for (species_index = 0; species_index < num_sp; ++species_index) + { + /* Check which ships can take part in fight. */ + sh = c_ship[species_index] - 1; + for (ship_index = 0; ship_index < c_species[species_index]->num_ships; ship_index++) + { + ++sh; + use_this_ship = FALSE; + + if (sh->x != x) continue; + if (sh->y != y) continue; + if (sh->z != z) continue; + if (sh->pn == 99) continue; + if (sh->age > 49) continue; + if (sh->status == UNDER_CONSTRUCTION) continue; + if (sh->status == FORCED_JUMP) continue; + if (sh->status == JUMPED_IN_COMBAT) continue; + if (sh->class == TR && sh->pn != location + && option != GERM_WARFARE) continue; + if (disbanded_ship (species_index, sh)) continue; + if (option == SIEGE || option == PLANET_BOMBARDMENT) + if (sh->special == NON_COMBATANT) continue; + + for (i = 0; i < bat->num_engage_options[species_index]; i++) + { + engage_option = bat->engage_option[species_index][i]; + engage_location = bat->engage_planet[species_index][i]; + + switch (engage_option) + { + case DEFENSE_IN_PLACE: + if (sh->pn != location) break; + defending_ships_here = TRUE; + use_this_ship = TRUE; + break; + + case DEEP_SPACE_DEFENSE: + if (option != DEEP_SPACE_FIGHT) break; + if (sh->class == BA && sh->pn != 0) break; + defending_ships_here = TRUE; + use_this_ship = TRUE; + deep_space_defense = TRUE; + if (c_species[species_index]->tech_level[ML] > defending_ML) + defending_ML = c_species[species_index]->tech_level[ML]; + break; + + case PLANET_DEFENSE: + if (location != engage_location) break; + if (sh->class == BA && sh->pn != location) break; + defending_ships_here = TRUE; + use_this_ship = TRUE; + break; + + case DEEP_SPACE_FIGHT: + if (option != DEEP_SPACE_FIGHT) break; + if (sh->class == BA && sh->pn != 0) break; + if (c_species[species_index]->tech_level[ML] > defending_ML) + defending_ML = c_species[species_index]->tech_level[ML]; + defending_ships_here = TRUE; + attacking_ships_here = TRUE; + use_this_ship = TRUE; + break; + + case PLANET_ATTACK: + case PLANET_BOMBARDMENT: + case GERM_WARFARE: + case SIEGE: + if (sh->class == BA && sh->pn != location) break; + if (sh->class == TR && option == SIEGE) break; + if (option == DEEP_SPACE_FIGHT) + { + /* There are two possibilities here: 1. outsiders + are attacking locals, or 2. locals are attacking + locals. If (1), we want outsiders to first fight + in deep space. If (2), locals will not first + fight in deep space (unless other explicit + orders were given). The case is (2) if current + species has a planet here. */ + + found = FALSE; + for (nampla_index = 0; nampla_index < c_species[species_index]->num_namplas; nampla_index++) + { + nam = c_nampla[species_index] + nampla_index; + + if (nam->x != x) continue; + if (nam->y != y) continue; + if (nam->z != z) continue; + if ((nam->status & POPULATED) == 0) continue; + + found = TRUE; + break; + } + + if (! found) + { + attacking_ships_here = TRUE; + use_this_ship = TRUE; + if (c_species[species_index]->tech_level[ML] > attacking_ML) + attacking_ML = c_species[species_index]->tech_level[ML]; + break; + } + } + if (option != engage_option + && option != PLANET_ATTACK) break; + if (location != engage_location) break; + attacking_ships_here = TRUE; + use_this_ship = TRUE; + break; + + default: + fprintf (stderr, "\n\n\tInternal error #1 in fight_par.c - invalid engage option!\n\n"); + exit (-1); + } + } + + add_ship: + if (use_this_ship) + { + /* Add data for this ship to action array. */ + act->fighting_species_index[num_fighting_units] = species_index; + act->unit_type[num_fighting_units] = SHIP; + act->fighting_unit[num_fighting_units] = (char *) sh; + act->original_age_or_PDs[num_fighting_units] = sh->age; + ++num_fighting_units; + } + } + + /* Check which namplas can take part in fight. */ + nam = c_nampla[species_index] - 1; + for (nampla_index = 0; nampla_index < c_species[species_index]->num_namplas; nampla_index++) + { + ++nam; + + if (nam->x != x) continue; + if (nam->y != y) continue; + if (nam->z != z) continue; + if (nam->pn != location) continue; + if ((nam->status & POPULATED) == 0) continue; + if (nam->status & DISBANDED_COLONY) continue; + + /* This planet has been targeted for some kind of attack. In + most cases, one species will attack a planet inhabited by + another species. However, it is also possible for two or + more species to have colonies on the SAME planet, and for + one to attack the other. */ + + for (i = 0; i < bat->num_engage_options[species_index]; i++) + { + engage_option = bat->engage_option[species_index][i]; + engage_location = bat->engage_planet[species_index][i]; + if (engage_location != location) continue; + + switch (engage_option) + { + case DEFENSE_IN_PLACE: + case DEEP_SPACE_DEFENSE: + case PLANET_DEFENSE: + case DEEP_SPACE_FIGHT: + break; + + case PLANET_ATTACK: + case PLANET_BOMBARDMENT: + case GERM_WARFARE: + case SIEGE: + if (option != engage_option + && option != PLANET_ATTACK) break; + if (nam->item_quantity[PD] > 0) + attacking_pds_here = TRUE; + break; + + default: + fprintf (stderr, "\n\n\tInternal error #2 in fight_par.c - invalid engage option!\n\n"); + exit (-1); + } + } + + if (nam->item_quantity[PD] > 0) defending_pds_here = TRUE; + + /* Add data for this nampla to action array. */ + act->fighting_species_index[num_fighting_units] = species_index; + act->unit_type[num_fighting_units] = NAMPLA; + act->fighting_unit[num_fighting_units] = (char *) nam; + act->original_age_or_PDs[num_fighting_units] = nam->item_quantity[PD]; + ++num_fighting_units; + } + } + + /* Depending on option, see if the right combination of combatants + are present. */ + switch (option) + { + case DEEP_SPACE_FIGHT: + if (!attacking_ships_here || !defending_ships_here) return FALSE; + break; + + case PLANET_ATTACK: + case PLANET_BOMBARDMENT: + if (!attacking_ships_here && !attacking_pds_here) return FALSE; + break; + + case SIEGE: + case GERM_WARFARE: + if (!attacking_ships_here) return FALSE; + break; + + default: + fprintf (stderr, "\n\n\tInternal error #3 in fight_par.c - invalid engage option!\n\n"); + exit (-1); + } + + /* There is at least one attacker and one defender here. See if they + are enemies. */ + for (i = 0; i < num_fighting_units; i++) + { + sp1 = act->fighting_species_index[i]; + for (j = 0; j < num_fighting_units; j++) + { + sp2 = act->fighting_species_index[j]; + if (bat->enemy_mine[sp1][sp2]) goto next_step; + } + } + + return FALSE; + +next_step: + + act->num_units_fighting = num_fighting_units; + + /* Determine number of shots, shield power and weapons power for + all combatants. */ + for (unit_index = 0; unit_index < act->num_units_fighting; unit_index++) + { + type = act->unit_type[unit_index]; + if (type == SHIP) + { + sh = (struct ship_data *) act->fighting_unit[unit_index]; + tons = sh->tonnage; + } + else + { + nam = (struct nampla_data *) act->fighting_unit[unit_index]; + tons = nam->item_quantity[PD]/200; + if (tons < 1 && nam->item_quantity[PD] > 0) tons = 1; + } + + species_index = act->fighting_species_index[unit_index]; + + unit_power = power (tons); + offensive_power = unit_power; + defensive_power = unit_power; + + if (type == SHIP) + { + if (sh->class == TR) + { + /* Transports are not designed for combat. */ + offensive_power /= 10; + defensive_power /= 10; + } + else if (sh->class != BA) + { + /* Add auxiliary shield generator contribution, if any. */ + tons = 5; + for (i = SG1; i <= SG9; i++) + { + if (sh->item_quantity[i] > 0) + defensive_power += + (long) sh->item_quantity[i] * power (tons); + tons += 5; + } + + /* Add auxiliary gun unit contribution, if any. */ + tons = 5; + for (i = GU1; i <= GU9; i++) + { + if (sh->item_quantity[i] > 0) + offensive_power += + (long) sh->item_quantity[i] * power (tons); + tons += 5; + } + } + + /* Adjust for ship aging. */ + offensive_power -= ((long) sh->age * offensive_power) / 50; + defensive_power -= ((long) sh->age * defensive_power) / 50; + } + + /* Adjust values for tech levels. */ + ml = c_species[species_index]->tech_level[ML]; + ls = c_species[species_index]->tech_level[LS]; + offensive_power += (ml * offensive_power) / 50; + defensive_power += (ls * defensive_power) / 50; + + /* Adjust values if this species is hijacking anyone. */ + if (bat->hijacker[species_index] && (option == DEEP_SPACE_FIGHT + || option == PLANET_ATTACK)) + { + offensive_power /= 4; + defensive_power /= 4; + } + + /* Get number of shots per round. */ + n_shots = (offensive_power / 1500) + 1; + if (ml == 0 || offensive_power == 0) n_shots = 0; + if (n_shots > 5) n_shots = 5; + act->num_shots[unit_index] = n_shots; + act->shots_left[unit_index] = n_shots; + + /* Get damage per shot. */ + if (n_shots > 0) + act->weapon_damage[unit_index] = (2 * offensive_power) / n_shots; + else + act->weapon_damage[unit_index] = 0; + + /* Do defensive shields. */ + act->shield_strength[unit_index] = defensive_power; + if (type == SHIP) + { + /* Adjust for results of previous action, if any. "dest_y" + contains the percentage of shields that remained at end + of last action. */ + defensive_power = ((long) sh->dest_y * defensive_power) / 100L; + } + act->shield_strength_left[unit_index] = defensive_power; + + /* Set bomb damage to zero in case this is planet bombardment or + germ warfare. */ + act->bomb_damage[unit_index] = 0; + + /* Set flag for individual unit if species can be surprised. */ + if (bat->can_be_surprised[species_index]) + act->surprised[unit_index] = TRUE; + else + act->surprised[unit_index] = FALSE; + } + + return TRUE; /* There will be a fight here. */ +} + + + +int disbanded_ship (species_index, sh) + +int species_index; +struct ship_data *sh; + +{ + int nampla_index; + + struct nampla_data *nam; + + nam = c_nampla[species_index] - 1; + for (nampla_index = 0; nampla_index < c_species[species_index]->num_namplas; nampla_index++) + { + ++nam; + + if (nam->x != sh->x) continue; + if (nam->y != sh->y) continue; + if (nam->z != sh->z) continue; + if (nam->pn != sh->pn) continue; + if ((nam->status & DISBANDED_COLONY) == 0) continue; + if (sh->type != STARBASE && sh->status == IN_ORBIT) continue; + + /* This ship is either on the surface of a disbanded colony or is + a starbase orbiting a disbanded colony. */ + return TRUE; + } + + return FALSE; +} diff --git a/src/for_jum.c b/src/for_jum.c new file mode 100644 index 0000000..52445e8 --- /dev/null +++ b/src/for_jum.c @@ -0,0 +1,145 @@ + +#include "fh.h" +#include "combat.h" + + +extern int log_summary, ignore_field_distorters; +extern char field_distorted[MAX_SPECIES]; +extern FILE *log_file; +extern struct species_data *c_species[MAX_SPECIES]; +extern struct galaxy_data galaxy; + + +/* This routine will return TRUE if forced jump or misjump units are used, + even if they fail. It will return FALSE if the attacker has none or + not enough. */ + +int forced_jump_units_used (attacker_index, defender_index, total_shots, + bat, act) + +int attacker_index, defender_index, *total_shots; + +struct battle_data *bat; +struct action_data *act; + +{ + int i, att_sp_index, def_sp_index, attacker_gv, defender_gv, + type, fj_num, fm_num, number, success_chance, failure; + + char x, y, z; + + struct ship_data *attacking_ship, *defending_ship; + + + + /* Make sure attacking unit is a starbase. */ + attacking_ship = (struct ship_data *) act->fighting_unit[attacker_index]; + if (attacking_ship->type != STARBASE) return FALSE; + + /* See if attacker has any forced jump units. */ + fj_num = attacking_ship->item_quantity[FJ]; + fm_num = attacking_ship->item_quantity[FM]; + if (fj_num == 0 && fm_num == 0) return FALSE; + + /* If both types are being carried, choose one randomly. */ + if (fj_num > 0 && fm_num > 0) + { + if (rnd (2) == 1) + { + type = FJ; + number = fj_num; + } + else + { + type = FM; + number = fm_num; + } + } + else if (fj_num > 0) + { + type = FJ; + number = fj_num; + } + else + { + type = FM; + number = fm_num; + } + + /* Get gravitics tech levels. */ + att_sp_index = act->fighting_species_index[attacker_index]; + attacker_gv = c_species[att_sp_index]->tech_level[GV]; + + def_sp_index = act->fighting_species_index[defender_index]; + defender_gv = c_species[def_sp_index]->tech_level[GV]; + + /* Check if sufficient units are available. */ + defending_ship = (struct ship_data *) act->fighting_unit[defender_index]; + if (number < defending_ship->tonnage) return FALSE; + + /* Make sure defender is not a starbase. */ + if (defending_ship->type == STARBASE) return FALSE; + + /* Calculate percent chance of success. */ + success_chance = 2 * + ( (number - defending_ship->tonnage) + (attacker_gv - defender_gv) ); + + /* See if it worked. */ + failure = rnd (100) > success_chance; + + log_summary = ! failure; + + log_string (" "); log_string (ship_name (attacking_ship)); + log_string (" attempts to use "); + log_string (item_name[type]); + log_string ("s against "); + + ignore_field_distorters = ! field_distorted[def_sp_index]; + log_string (ship_name (defending_ship)); + ignore_field_distorters = FALSE; + + if (failure) + { + log_string (", but fails.\n"); + return TRUE; + } + + log_string (", and succeeds!\n"); + log_summary = FALSE; + + /* Determine destination. */ + if (type == FM) + { + /* Destination is totally random. */ + x = rnd (100) - 1; + y = rnd (100) - 1; + z = rnd (100) - 1; + } + else + { + /* Random location close to battle. */ + i = 3; while (i == 3) i = rnd(5); + x = bat->x + i - 3; + if (x < 0) x = 0; + + i = 3; while (i == 3) i = rnd(5); + y = bat->y + i - 3; + if (y < 0) y = 0; + + i = 3; while (i == 3) i = rnd(5); + z = bat->z + i - 3; + if (z < 0) z = 0; + } + defending_ship->dest_x = x; + defending_ship->dest_y = y; + defending_ship->dest_z = z; + + /* Make sure this ship can no longer take part in the battle. */ + defending_ship->status = FORCED_JUMP; + defending_ship->pn = -1; + *total_shots -= act->shots_left[defender_index]; + act->shots_left[defender_index] = 0; + act->num_shots[defender_index] = 0; + + return TRUE; +} diff --git a/src/gam_abo.c b/src/gam_abo.c new file mode 100644 index 0000000..462dcfc --- /dev/null +++ b/src/gam_abo.c @@ -0,0 +1,16 @@ + +#include + + +gamemaster_abort_option () + +{ + char answer[16]; + + /* Give the gamemaster a chance to abort. */ + printf ("*** Gamemaster safe-abort option ... type q or Q to quit: "); + fflush (stdout); + fgets (answer, 16, stdin); + if (answer[0] == 'q' || answer[0] == 'Q') + exit (0); +} diff --git a/src/gen_plan.c b/src/gen_plan.c new file mode 100644 index 0000000..52aba13 --- /dev/null +++ b/src/gen_plan.c @@ -0,0 +1,273 @@ + +#include "fh.h" + + +/* Generate planets. */ + +int start_diameter[10] = {0, 5, 12, 13, 7, 20, 143, 121, 51, 49}; +int start_temp_class[10] = {0, 29, 27, 11, 9, 8, 6, 5, 5, 3}; + /* Values for the planets of Earth's solar system will be used + as starting values. Diameters are in thousands of kilometers. + The zeroth element of each array is a placeholder and is not + used. The fifth element corresponds to the asteroid belt, and + is pure fantasy on my part. I omitted Pluto because it is probably + a captured planet, rather than an original member of our solar + system. */ + +generate_planets (first_planet, num_planets) + +struct planet_data *first_planet; + +int num_planets; + +{ + int i, j, n, planet_number, dia, diameter[10], gas_giant, die_size, + density, grav, g[10], tc, temperature_class[10], pc, temp, + pressure_class[10], n_rolls, mining_dif, mining_difficulty[10], + gas[10][5], gas_percent[10][5], first_gas, num_gases_wanted, + num_gases_found, gas_quantity, total_percent; + + char *cp; + + struct planet_data *current_planet; + + + /* Main loop. Generate one planet at a time. */ + for (planet_number = 1; planet_number <= num_planets; planet_number++) + { + /* Start with diameters, temperature classes and pressure classes + based on the planets in Earth's solar system. */ + if (num_planets > 3) + { + i = (9 * planet_number)/num_planets; + dia = start_diameter[i]; + tc = start_temp_class[i]; + } + else + { + i = 2 * planet_number + 1; + dia = start_diameter[i]; + tc = start_temp_class[i]; + } + + /* Randomize the diameter. */ + die_size = dia/4; if (die_size < 2) die_size = 2; + for (i = 1; i <= 4; i++) + { + if (rnd(100) > 50) + dia = dia + rnd(die_size); + else + dia = dia - rnd(die_size); + } + + /* Minimum allowable diameter is 3,000 km. Note that the + maximum diameter we can generate is 283,000 km. */ + while (dia < 3) dia += rnd(4); + + diameter[planet_number] = dia; + + /* If diameter is greater than 40,000 km, assume the planet + is a gas giant. */ + gas_giant = (dia > 40); + + /* Density will depend on whether or not the planet is a gas giant. + Again ignoring Pluto, densities range from 0.7 to 1.6 times the + density of water for the gas giants, and from 3.9 to 5.5 for the + others. We will expand this range slightly and use 100 times the + actual density so that we can use integer arithmetic. */ + if (gas_giant) + density = 58 + rnd(56) + rnd(56); + /* Final values from 60 thru 170. */ + else + density = 368 + rnd(101) + rnd(101); + /* Final values from 370 thru 570. */ + + /* Gravitational acceleration is proportional to the mass divided + by the radius-squared. The radius is proportional to the + diameter, and the mass is proportional to the density times the + radius-cubed. The net result is that "g" is proportional to + the density times the diameter. Our value for "g" will be + a multiple of Earth gravity, and will be further multiplied + by 100 to allow us to use integer arithmetic. */ + grav = (density * diameter[planet_number]) / 72; + /* The factor 72 ensures that "g" will be 100 for + Earth (density=550 and diameter=13). */ + g[planet_number] = grav; + + /* Randomize the temperature class obtained earlier. */ + die_size = tc/4; if (die_size < 2) die_size = 2; + n_rolls = rnd(3) + rnd(3) + rnd(3); + for (i = 1; i <= n_rolls; i++) + { + if (rnd(100) > 50) + tc = tc + rnd(die_size); + else + tc = tc - rnd(die_size); + } + + if (gas_giant) + { + while (tc < 3) tc += rnd(2); + while (tc > 7) tc -= rnd(2); + } + else + { + while (tc < 1) tc += rnd(3); + while (tc > 30) tc -= rnd(3); + } + + /* Sometimes, planets close to the sun in star systems with less + than four planets are too cold. Warm them up a little. */ + if (num_planets < 4 && planet_number < 3) + { + while (tc < 12) tc += rnd(4); + } + + /* Make sure that planets farther from the sun are not warmer + than planets closer to the sun. */ + if (planet_number > 1) + { + if (temperature_class[planet_number-1] < tc) + tc = temperature_class[planet_number-1]; + } + + temperature_class[planet_number] = tc; + + /* Pressure class depends primarily on gravity. Calculate + an approximate value and randomize it. */ + pc = g[planet_number]/10; + die_size = pc/4; if (die_size < 2) die_size = 2; + n_rolls = rnd(3) + rnd(3) + rnd(3); + for (i = 1; i <= n_rolls; i++) + { + if (rnd(100) > 50) + pc = pc + rnd(die_size); + else + pc = pc - rnd(die_size); + } + + if (gas_giant) + { + while (pc < 11) pc += rnd(3); + while (pc > 29) pc -= rnd(3); + } + else + { + while (pc < 0) pc += rnd(3); + while (pc > 12) pc -= rnd(3); + } + + if (grav < 10) pc = 0; + /* Planet's gravity is too low to retain an atmosphere. */ + if (tc < 2 || tc > 27) pc = 0; + /* Planets outside this temperature range have no atmosphere. */ + + pressure_class[planet_number] = pc; + + /* Generate gases, if any, in the atmosphere. */ + for (i = 1; i <= 4; i++) /* Initialize. */ + { + gas[planet_number][i] = 0; + gas_percent[planet_number][i] = 0; + } + if (pc == 0) goto done_gases; /* No atmosphere. */ + + /* Convert planet's temperature class to a value between 1 and 9. + We will use it as the start index into the list of 13 potential + gases. */ + first_gas = 100*tc/225; + if (first_gas < 1) first_gas = 1; + if (first_gas > 9) first_gas = 9; + + /* The following algorithm is something I tweaked until it + worked well. */ + num_gases_wanted = (rnd(4) + rnd(4))/2; + num_gases_found = 0; + gas_quantity = 0; + +get_gases: + for (i = first_gas; i <= first_gas + 4; i++) + { + if (num_gases_wanted == num_gases_found) break; + + if (i == HE) /* Treat Helium specially. */ + { + if (rnd(3) > 1) continue; /* Don't want too many He planets. */ + if (tc > 5) continue; /* Too hot for helium. */ + ++num_gases_found; + gas[planet_number][num_gases_found] = HE; + temp = rnd(20); + gas_percent[planet_number][num_gases_found] = temp; + gas_quantity += temp; + } + else /* Not Helium. */ + { + if (rnd(3) == 3) continue; + ++num_gases_found; + gas[planet_number][num_gases_found] = i; + if (i == O2) + temp = rnd(50); /* Oxygen is self-limiting. */ + else + temp = rnd(100); + gas_percent[planet_number][num_gases_found] = temp; + gas_quantity += temp; + } + } + + if (num_gases_found == 0) goto get_gases; /* Try again. */ + + /* Now convert gas quantities to percentages. */ + total_percent = 0; + for (i = 1; i <= num_gases_found; i++) + { + gas_percent[planet_number][i] = + 100 * gas_percent[planet_number][i] / gas_quantity; + total_percent += gas_percent[planet_number][i]; + } + + /* Give leftover to first gas. */ + gas_percent[planet_number][1] += 100 - total_percent; + + done_gases: + + /* Get mining difficulty. Basically, mining difficulty is + proportional to planetary diameter with randomization and an + occasional big surprise. Actual values will range between 0.80 + and 10.00. Again, the actual value will be multiplied by 100 + to allow use of integer arithmetic. */ + mining_dif = 0; + while (mining_dif < 40 || mining_dif > 500) + mining_dif = (rnd(3) + rnd(3) + rnd(3) - rnd(4)) * rnd(dia) + + rnd(30) + rnd(30); + + mining_dif *= 11; /* Fudge factor. */ + mining_dif /= 5; + + mining_difficulty[planet_number] = mining_dif; + } + + /* Copy planet data to structure. */ + current_planet = first_planet; + for (i = 1; i <= num_planets; i++) + { + /* Initialize all bytes of record to zero. */ + cp = (char *) current_planet; + for (j = 0; j < sizeof (struct planet_data); j++) + *cp++ = 0; + + current_planet->diameter = diameter[i]; + current_planet->gravity = g[i]; + current_planet->mining_difficulty = mining_difficulty[i]; + current_planet->temperature_class = temperature_class[i]; + current_planet->pressure_class = pressure_class[i]; + current_planet->special = 0; + + for (n = 0; n < 4; n++) + { + current_planet->gas[n] = gas[i][n+1]; + current_planet->gas_percent[n] = gas_percent[i][n+1]; + } + + ++current_planet; + } +} diff --git a/src/get_gal.c b/src/get_gal.c new file mode 100644 index 0000000..eb74c58 --- /dev/null +++ b/src/get_gal.c @@ -0,0 +1,34 @@ + +#include "fh.h" + + +extern struct galaxy_data galaxy; + + +get_galaxy_data () + +{ + int galaxy_fd; + + long n, num_bytes, byte_size; + + + /* Open galaxy file. */ + galaxy_fd = open ("galaxy.dat", 0); + if (galaxy_fd < 0) + { + fprintf (stderr, "\n\tCannot open file galaxy.dat!\n"); + exit (-1); + } + + /* Read data. */ + byte_size = sizeof (struct galaxy_data); + num_bytes = read (galaxy_fd, &galaxy, byte_size); + if (num_bytes != byte_size) + { + fprintf (stderr, "\n\tCannot read data in file 'galaxy.dat'!\n\n"); + exit (-1); + } + + close (galaxy_fd); +} diff --git a/src/get_loc.c b/src/get_loc.c new file mode 100644 index 0000000..b2d4efb --- /dev/null +++ b/src/get_loc.c @@ -0,0 +1,189 @@ + +/* This routine will assign values to global variables x, y, z, pn, star + and nampla. If the location is not a named planet, then nampla will be + set to NULL. If planet is not specified, pn will be set to zero. If + location is valid, TRUE will be returned, otherwise FALSE will be + returned. */ + + +#include "fh.h" + + +extern int x, y, z, pn, num_stars, abbr_type; +extern long value; +extern char upper_name[32], *input_line_pointer; +extern struct species_data *species; +extern struct nampla_data *nampla_base, *nampla; +extern struct star_data *star_base, *star; + + +int get_location () +{ + int i, n, found, temp_nampla_index, first_try, name_length, + best_score, next_best_score, best_nampla_index, + minimum_score; + + char upper_nampla_name[32], *temp1_ptr, *temp2_ptr; + + struct nampla_data *temp_nampla; + + + /* Check first if x, y, z are specified. */ + nampla = NULL; + skip_whitespace (); + + if (get_value () == 0) + goto get_planet; + x = value; + + if (get_value () == 0) return FALSE; + y = value; + + if (get_value () == 0) return FALSE; + z = value; + + if (get_value () == 0) + pn = 0; + else + pn = value; + + if (pn == 0) return TRUE; + + /* Get star. Check if planet exists. */ + found = FALSE; + star = star_base - 1; + for (i = 0; i < num_stars; i++) + { + ++star; + + if (star->x != x) continue; + if (star->y != y) continue; + if (star->z != z) continue; + + if (pn > star->num_planets) + return FALSE; + else + return TRUE; + } + + return FALSE; + + +get_planet: + + /* Save pointers in case of error. */ + temp1_ptr = input_line_pointer; + + get_class_abbr (); + + temp2_ptr = input_line_pointer; + + first_try = TRUE; + +again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != PLANET_ID && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get planet name. */ + get_name (); + + /* Search all temp_namplas for name. */ + temp_nampla = nampla_base - 1; + for (temp_nampla_index = 0; temp_nampla_index < species->num_namplas; temp_nampla_index++) + { + ++temp_nampla; + + if (temp_nampla->pn == 99) continue; + + /* Make upper case copy of temp_nampla name. */ + for (i = 0; i < 32; i++) + upper_nampla_name[i] = toupper(temp_nampla->name[i]); + + /* Compare names. */ + if (strcmp (upper_nampla_name, upper_name) == 0) goto done; + } + + if (first_try) + { + first_try = FALSE; + goto again; + } + + + /* Possibly a spelling error. Find the best match that is approximately + the same. */ + + first_try = TRUE; + +yet_again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != PLANET_ID && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get planet name. */ + get_name (); + + best_score = -9999; + next_best_score = -9999; + for (temp_nampla_index = 0; temp_nampla_index < species->num_namplas; temp_nampla_index++) + { + temp_nampla = nampla_base + temp_nampla_index; + + if (temp_nampla->pn == 99) continue; + + /* Make upper case copy of temp_nampla name. */ + for (i = 0; i < 32; i++) + upper_nampla_name[i] = toupper(temp_nampla->name[i]); + + /* Compare names. */ + n = agrep_score (upper_nampla_name, upper_name); + if (n > best_score) + { + best_score = n; /* Best match so far. */ + best_nampla_index = temp_nampla_index; + } + else if (n > next_best_score) + next_best_score = n; + } + + temp_nampla = nampla_base + best_nampla_index; + name_length = strlen (temp_nampla->name); + minimum_score = name_length - ((name_length / 7) + 1); + + if (best_score < minimum_score /* Score too low. */ + || name_length < 5 /* No errors allowed. */ + || best_score == next_best_score) /* Another name with equal + score. */ + { + if (first_try) + { + first_try = FALSE; + goto yet_again; + } + else + return FALSE; + } + +done: + + abbr_type = PLANET_ID; + + x = temp_nampla->x; + y = temp_nampla->y; + z = temp_nampla->z; + pn = temp_nampla->pn; + nampla = temp_nampla; + + return TRUE; +} diff --git a/src/get_plan.c b/src/get_plan.c new file mode 100644 index 0000000..2863d70 --- /dev/null +++ b/src/get_plan.c @@ -0,0 +1,60 @@ + +#include "fh.h" + + +/* In case gamemaster creates new star systems with Edit program. */ +#define NUM_EXTRA_PLANETS 100 + + +int num_planets, planet_data_modified; + +struct planet_data *planet_base; + + +get_planet_data () + +{ + int planet_fd; + + long n, data_size, mem_size; + + + /* Open planet file. */ + planet_fd = open ("planets.dat", 0); + if (planet_fd < 0) + { + fprintf (stderr, "\n\tCannot open file planets.dat!\n"); + exit (-1); + } + + /* Read header data. */ + data_size = read (planet_fd, &num_planets, sizeof(num_planets)); + if (data_size != sizeof(num_planets)) + { + fprintf (stderr, "\n\tCannot read num_planets in file 'planets.dat'!\n\n"); + exit (-1); + } + + /* Allocate enough memory for all planets. */ + mem_size = + (long) (num_planets + NUM_EXTRA_PLANETS) * (long) sizeof(struct planet_data); + data_size = + (long) num_planets * (long) sizeof(struct planet_data); + planet_base = (struct planet_data *) malloc (mem_size); + if (planet_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for planet file!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + n = read (planet_fd, planet_base, data_size); + if (n != data_size) + { + fprintf (stderr, "\nCannot read planet file into memory!\n\n"); + exit (-1); + } + close (planet_fd); + + planet_data_modified = FALSE; +} diff --git a/src/get_ship.c b/src/get_ship.c new file mode 100644 index 0000000..612d498 --- /dev/null +++ b/src/get_ship.c @@ -0,0 +1,159 @@ + +/* The following routine will return TRUE and set global variables "ship" and + "ship_index" if a valid ship designation is found. Otherwise, it will return + FALSE. The algorithm employed allows minor spelling errors, as well as + accidental deletion of a ship abbreviation. */ + + +#include "fh.h" + + +int correct_spelling_required = FALSE; + + +extern int ship_index, abbr_type, abbr_index; +extern char upper_name[32], *input_line_pointer; +extern struct species_data *species; +extern struct ship_data *ship_base, *ship; + + +int get_ship () + +{ + int i, n, name_length, best_score, next_best_score, best_ship_index, + first_try, minimum_score; + + char upper_ship_name[32], *temp1_ptr, *temp2_ptr; + + struct ship_data *best_ship; + + + /* Save in case of an error. */ + temp1_ptr = input_line_pointer; + + /* Get ship abbreviation. */ + if (get_class_abbr () == PLANET_ID) + { + input_line_pointer = temp1_ptr; + return FALSE; + } + + temp2_ptr = input_line_pointer; + + first_try = TRUE; + +again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != SHIP_CLASS && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get ship name. */ + name_length = get_name (); + + /* Search all ships for name. */ + ship = ship_base - 1; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ++ship; + + if (ship->pn == 99) continue; + + /* Make upper case copy of ship name. */ + for (i = 0; i < 32; i++) upper_ship_name[i] = toupper(ship->name[i]); + + /* Compare names. */ + if (strcmp (upper_ship_name, upper_name) == 0) + { + abbr_type = SHIP_CLASS; + abbr_index = ship->class; + correct_spelling_required = FALSE; + return TRUE; + } + } + + if (first_try) + { + first_try = FALSE; + goto again; + } + + if (correct_spelling_required) + { + correct_spelling_required = FALSE; + return FALSE; + } + + + /* Possibly a spelling error. Find the best match that is approximately + the same. */ + + first_try = TRUE; + +yet_again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != SHIP_CLASS && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get ship name. */ + name_length = get_name (); + + best_score = -9999; + next_best_score = -9999; + for (ship_index = 0; ship_index < species->num_ships; ship_index++) + { + ship = ship_base + ship_index; + + if (ship->pn == 99) continue; + + /* Make upper case copy of ship name. */ + for (i = 0; i < 32; i++) upper_ship_name[i] = toupper(ship->name[i]); + + n = agrep_score (upper_ship_name, upper_name); + if (n > best_score) + { + /* Best match so far. */ + best_score = n; + best_ship = ship; + best_ship_index = ship_index; + } + else if (n > next_best_score) + next_best_score = n; + } + + name_length = strlen (best_ship->name); + minimum_score = name_length - ((name_length / 7) + 1); + + if (best_score < minimum_score /* Score too low. */ + || name_length < 5 /* No errors allowed. */ + || best_score == next_best_score) /* Another name with equal + score. */ + { + if (first_try) + { + first_try = FALSE; + goto yet_again; + } + else + { + correct_spelling_required = FALSE; + return FALSE; + } + } + + ship = best_ship; + ship_index = best_ship_index; + abbr_type = SHIP_CLASS; + abbr_index = ship->class; + correct_spelling_required = FALSE; + return TRUE; +} diff --git a/src/get_spnam.c b/src/get_spnam.c new file mode 100644 index 0000000..bc6275b --- /dev/null +++ b/src/get_spnam.c @@ -0,0 +1,144 @@ + + +/* This routine will get a species name and return TRUE if found and if + it is valid. It will also set global values "g_species_number" and + "g_species_name". The algorithm employed allows minor spelling errors, + as well as accidental deletion of the SP abbreviation. */ + + +#include "fh.h" + + +int g_spec_number; +char g_spec_name[32]; + +extern int abbr_type; +extern char upper_name[32], *input_line_pointer; +extern struct galaxy_data galaxy; + + +int get_species_name () +{ + int i, n, species_index, best_score, best_species_index, + next_best_score, first_try, minimum_score, name_length; + + char sp_name[32], *temp1_ptr, *temp2_ptr; + + struct species_data *sp; + + + g_spec_number = 0; + + /* Save pointers in case of error. */ + temp1_ptr = input_line_pointer; + + get_class_abbr (); + + temp2_ptr = input_line_pointer; + + first_try = TRUE; + +again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != SPECIES_ID && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get species name. */ + get_name(); + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (! data_in_memory[species_index]) continue; + + sp = &spec_data[species_index]; + + /* Copy name to g_spec_name and convert it to upper case. */ + for (i = 0; i < 31; i++) + { + g_spec_name[i] = sp->name[i]; + sp_name[i] = toupper(g_spec_name[i]); + } + + if (strcmp (sp_name, upper_name) == 0) + { + g_spec_number = species_index + 1; + abbr_type = SPECIES_ID; + return TRUE; + } + } + + if (first_try) + { + first_try = FALSE; + goto again; + } + + /* Possibly a spelling error. Find the best match that is approximately + the same. */ + + first_try = TRUE; + +yet_again: + + input_line_pointer = temp2_ptr; + + if (abbr_type != SPECIES_ID && ! first_try) + { + /* Assume abbreviation was accidentally omitted. */ + input_line_pointer = temp1_ptr; + } + + /* Get species name. */ + get_name(); + + best_score = -9999; + next_best_score = -9999; + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (! data_in_memory[species_index]) continue; + + sp = &spec_data[species_index]; + + /* Convert name to upper case. */ + for (i = 0; i < 31; i++) sp_name[i] = toupper(sp->name[i]); + + n = agrep_score (sp_name, upper_name); + if (n > best_score) + { + /* Best match so far. */ + best_score = n; + best_species_index = species_index; + } + else if (n > next_best_score) + next_best_score = n; + } + + sp = &spec_data[best_species_index]; + name_length = strlen (sp->name); + minimum_score = name_length - ((name_length / 7) + 1); + + if (best_score < minimum_score /* Score too low. */ + || name_length < 5 /* No errors allowed. */ + || best_score == next_best_score) /* Another name with equal + score. */ + { + if (first_try) + { + first_try = FALSE; + goto yet_again; + } + else + return FALSE; + } + + /* Copy name to g_spec_name. */ + for (i = 0; i < 31; i++) g_spec_name[i] = sp->name[i]; + g_spec_number = best_species_index + 1; + abbr_type = SPECIES_ID; + return TRUE; +} diff --git a/src/get_star.c b/src/get_star.c new file mode 100644 index 0000000..c3d2948 --- /dev/null +++ b/src/get_star.c @@ -0,0 +1,59 @@ + +#include "fh.h" + + +/* In case gamemaster creates new star systems with Edit program. */ +#define NUM_EXTRA_STARS 20 + + +int num_stars, star_data_modified; + +struct star_data *star_base; + + +get_star_data () + +{ + int star_fd; + + long byte_size, star_data_size, mem_size; + + + /* Open star file. */ + star_fd = open ("stars.dat", 0); + if (star_fd < 0) + { + fprintf (stderr, "\n\tCannot open file stars.dat!\n"); + exit (999); + } + + byte_size = read (star_fd, &num_stars, sizeof(num_stars)); + if (byte_size != sizeof(num_stars)) + { + fprintf (stderr, "\n\tCannot read num_stars in file 'stars.dat'!\n\n"); + exit (999); + } + + /* Allocate enough memory for all stars. */ + mem_size = + (long) (num_stars + NUM_EXTRA_STARS) * (long) sizeof(struct star_data); + star_data_size = + (long) num_stars * (long) sizeof(struct star_data); + star_base = (struct star_data *) malloc (mem_size); + if (star_base == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for star file!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + byte_size = read (star_fd, star_base, star_data_size); + if (byte_size != star_data_size) + { + fprintf (stderr, "\nCannot read star file into memory!\n\n"); + exit (-1); + } + close (star_fd); + + star_data_modified = FALSE; +} diff --git a/src/get_transact.c b/src/get_transact.c new file mode 100644 index 0000000..5628915 --- /dev/null +++ b/src/get_transact.c @@ -0,0 +1,46 @@ + +#include "fh.h" + + +int num_transactions; + +struct trans_data transaction[MAX_TRANSACTIONS]; + + +get_transaction_data () + + +{ + int i, trans_fd; + long num_bytes; + + + /* Open file for reading. */ + trans_fd = open ("interspecies.dat", 0); + + if (trans_fd < 0) + { + num_transactions = 0; + return; + } + + /* Read transactions from file. */ + i = 0; + while (1) + { + num_bytes = read (trans_fd, &transaction[i], sizeof(struct trans_data)); + if (num_bytes == 0) break; /* End of file. */ + + if (num_bytes != sizeof(struct trans_data)) + { + fprintf (stderr, "\n\n\tError reading transaction from file 'interspecies.dat'!\n\n"); + exit (-1); + } + + ++i; + } + + num_transactions = i; + + close (trans_fd); +} diff --git a/src/get_transfer.c b/src/get_transfer.c new file mode 100644 index 0000000..ad58d74 --- /dev/null +++ b/src/get_transfer.c @@ -0,0 +1,30 @@ + +#include "fh.h" + + +extern int correct_spelling_required; +extern char *input_line_pointer; +extern struct nampla_data *nampla; + + +int get_transfer_point () +{ + char *temp_ptr; + + + /* Find out if it is a ship or a planet. First try for a correctly + spelled ship name. */ + temp_ptr = input_line_pointer; + correct_spelling_required = TRUE; + if (get_ship ()) return TRUE; + + /* Probably not a ship. See if it's a planet. */ + input_line_pointer = temp_ptr; + if (get_location ()) return (nampla != NULL); + + /* Now check for an incorrectly spelled ship name. */ + input_line_pointer = temp_ptr; + if (get_ship ()) return TRUE; + + return FALSE; +} diff --git a/src/make.all b/src/make.all new file mode 100755 index 0000000..0ed26a8 --- /dev/null +++ b/src/make.all @@ -0,0 +1,31 @@ +#!/bin/sh + +if [ ! -d ../bin ] +then + mkdir ../bin +fi + +make -f mk.newgal +make -f mk.mho +make -f mk.home +make -f mk.listgal +make -f mk.mapgal +make -f mk.showgal +make -f mk.addsp +make -f mk.combat +make -f mk.pre +make -f mk.jump +make -f mk.pro +make -f mk.post +make -f mk.finish +make -f mk.loc +make -f mk.report +make -f mk.scan +make -f mk.stats +make -f mk.near +make -f mk.edit +make -f mk.turn +make -f mk.no +make -f mk.asc +make -f mk.bin +make -f mk.set diff --git a/src/mask.c b/src/mask.c new file mode 100644 index 0000000..0abdcd3 --- /dev/null +++ b/src/mask.c @@ -0,0 +1,35 @@ + +#include + +main (argc, argv) + +int argc; +char *argv[]; + +{ + int i, bit_number, word_number, species_number; + + long mask, bit_mask; + + + /* Check for valid command line. */ + if (argc == 1) + { + fprintf (stderr, "\n Usage: Mask species_number species_number ...\n\n"); + exit (-1); + } + + mask = 0; + for (i = 1; i < argc; i++) + { + species_number = atoi (argv[i]); + word_number = (species_number - 1) / 32; + bit_number = (species_number - 1) % 32; + bit_mask = 1 << bit_number; + printf ("Species number = %d, word number = %d, bit number = %d, bit mask = %lx\n", + species_number, word_number, bit_number, bit_mask); + mask |= bit_mask; + } + + printf ("\nFinal single-word bit mask = %lx\n", mask); +} diff --git a/src/mk.addsp b/src/mk.addsp new file mode 100644 index 0000000..12aec1a --- /dev/null +++ b/src/mk.addsp @@ -0,0 +1,30 @@ + +ADD_OBJS = AddSpecies.o utils.o get_gal.o get_star.o get_plan.o scan.o gam_abo.o sav_star.o + + +AddSpecies: $(ADD_OBJS) + cc $(ADD_OBJS) -o ../bin/AddSpecies + +AddSpecies.o: AddSpecies.c fh.h + cc -c AddSpecies.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +scan.o: scan.c fh.h + cc -c scan.c + +gam_abo.o: gam_abo.c fh.h + cc -c gam_abo.c diff --git a/src/mk.asc b/src/mk.asc new file mode 100644 index 0000000..1c20cd5 --- /dev/null +++ b/src/mk.asc @@ -0,0 +1,25 @@ + +ASCII1 = AsciiToBinary.o get_star.o get_plan.o sav_star.o sav_plan.o utils.o + +ASCII_OBJS = $(ASCII1) + +AsciiToBinary: $(ASCII_OBJS) + cc -o ../bin/AsciiToBinary $(ASCII_OBJS) + +AsciiToBinary.o: AsciiToBinary.c fh.h + cc -c AsciiToBinary.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c diff --git a/src/mk.bin b/src/mk.bin new file mode 100644 index 0000000..80665cf --- /dev/null +++ b/src/mk.bin @@ -0,0 +1,22 @@ + +BINARY1 = BinaryToAscii.o get_gal.o get_star.o get_plan.o utils.o + +BINARY_OBJS = $(BINARY1) + +BinaryToAscii: $(BINARY_OBJS) + cc -o ../bin/BinaryToAscii $(BINARY_OBJS) + +BinaryToAscii.o: BinaryToAscii.c fh.h + cc -c BinaryToAscii.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c diff --git a/src/mk.combat b/src/mk.combat new file mode 100644 index 0000000..b1d6904 --- /dev/null +++ b/src/mk.combat @@ -0,0 +1,75 @@ + +COM1 = combat_utils.o utils.o parse.o for_jum.o cons_op.o do_germ.o get_ship.o +COM2 = fight_par.o do_bat.o do_round.o do_bomb.o do_siege.o get_spnam.o with_check.o +COM3 = regen_sh.o get_gal.o get_plan.o sav_plan.o get_transact.o sav_transact.o + +COMBAT_OBJS = Combat.o $(COM1) $(COM2) $(COM3) + + +Combat: $(COMBAT_OBJS) + cc $(COMBAT_OBJS) -o ../bin/Combat + rm -f ../bin/Strike + ln -s ../bin/Combat ../bin/Strike + +Combat.o: Combat.c fh.h combat.h + cc -c Combat.c + +combat_utils.o: combat_utils.c + cc -c combat_utils.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +for_jum.o: for_jum.c fh.h combat.h + cc -c for_jum.c + +do_round.o: do_round.c fh.h combat.h + cc -c do_round.c + +fight_par.o: fight_par.c fh.h combat.h + cc -c fight_par.c + +cons_op.o: cons_op.c fh.h combat.h + cc -c cons_op.c + +do_bomb.o: do_bomb.c fh.h combat.h + cc -c do_bomb.c + +do_germ.o: do_germ.c fh.h combat.h + cc -c do_germ.c + +do_siege.o: do_siege.c fh.h combat.h + cc -c do_siege.c + +regen_sh.o: regen_sh.c fh.h combat.h + cc -c regen_sh.c + +with_check.o: with_check.c fh.h combat.h + cc -c with_check.c + +do_bat.o: do_bat.c fh.h combat.h + cc -c do_bat.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +sav_transact.o: sav_transact.c fh.h + cc -c sav_transact.c + +get_spnam.o: get_spnam.c fh.h + cc -c get_spnam.c + +get_ship.o: get_ship.c fh.h + cc -c get_ship.c diff --git a/src/mk.edit b/src/mk.edit new file mode 100644 index 0000000..69e6f29 --- /dev/null +++ b/src/mk.edit @@ -0,0 +1,30 @@ + +EDIT_OBJS = Edit.o utils.o get_gal.o get_star.o get_plan.o do_locs.o sav_plan.o sav_star.o gen_plan.o + + +Edit: $(EDIT_OBJS) + cc $(EDIT_OBJS) -o ../bin/Edit + +Edit.o: Edit.c fh.h + cc -c Edit.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +gen_plan.o: gen_plan.c fh.h + cc -c gen_plan.c diff --git a/src/mk.finish b/src/mk.finish new file mode 100644 index 0000000..6b76493 --- /dev/null +++ b/src/mk.finish @@ -0,0 +1,32 @@ + +FIN1 = utils.o get_transact.o +FIN2 = get_gal.o get_star.o get_plan.o sav_plan.o do_locs.o + +FIN_OBJS = Finish.o $(FIN1) $(FIN2) + +Finish: $(FIN_OBJS) + cc $(FIN_OBJS) -o ../bin/Finish + +Finish.o: Finish.c fh.h + cc -c Finish.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +do_locs.o: do_locs.c fh.h + cc -c do_locs.c diff --git a/src/mk.home b/src/mk.home new file mode 100644 index 0000000..a97a360 --- /dev/null +++ b/src/mk.home @@ -0,0 +1,31 @@ + +HOM_OBJS = HomeSystem.o utils.o get_gal.o get_star.o sav_star.o get_plan.o sav_plan.o gam_abo.o + + +HomeSystem: $(HOM_OBJS) + cc $(HOM_OBJS) -o ../bin/HomeSystem + +HomeSystem.o: HomeSystem.c fh.h + cc -c HomeSystem.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +gam_abo.o: gam_abo.c fh.h + cc -c gam_abo.c + diff --git a/src/mk.jump b/src/mk.jump new file mode 100644 index 0000000..f6ccea8 --- /dev/null +++ b/src/mk.jump @@ -0,0 +1,69 @@ + +JUMP1 = utils.o parse.o do_jump.o get_transact.o do_move.o do_vis.o +JUMP2 = get_gal.o get_star.o get_plan.o sav_transact.o sav_star.o sav_plan.o +JUMP3 = get_loc.o get_ship.o gam_abo.o dis_ship.o do_worm.o + +JUMP_OBJS = Jump.o $(JUMP1) $(JUMP2) $(JUMP3) + +Jump: $(JUMP_OBJS) + cc $(JUMP_OBJS) -o ../bin/Jump + +Jump.o: Jump.c fh.h + cc -c Jump.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +sav_transact.o: sav_transact.c fh.h + cc -c sav_transact.c + +get_loc.o: get_loc.c fh.h + cc -c get_loc.c + +get_ship.o: get_ship.c fh.h + cc -c get_ship.c + +do_scan.o: do_scan.c fh.h + cc -c do_scan.c + +scan.o: scan.c fh.h + cc -c scan.c + +do_jump.o: do_jump.c fh.h + cc -c do_jump.c + +do_move.o: do_move.c fh.h + cc -c do_move.c + +do_vis.o: do_vis.c fh.h + cc -c do_vis.c + +do_worm.o: do_worm.c fh.h + cc -c do_worm.c + +dis_ship.o: dis_ship.c fh.h + cc -c dis_ship.c + +gam_abo.o: gam_abo.c + cc -c gam_abo.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c diff --git a/src/mk.listgal b/src/mk.listgal new file mode 100644 index 0000000..69fb305 --- /dev/null +++ b/src/mk.listgal @@ -0,0 +1,21 @@ + +LIST_OBJS = ListGalaxy.o utils.o get_gal.o get_star.o get_plan.o + + +ListGalaxy: $(LIST_OBJS) + cc $(LIST_OBJS) -o ../bin/ListGalaxy + +ListGalaxy.o: ListGalaxy.c fh.h + cc -c ListGalaxy.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c diff --git a/src/mk.loc b/src/mk.loc new file mode 100644 index 0000000..c9e5f8b --- /dev/null +++ b/src/mk.loc @@ -0,0 +1,29 @@ + +LOC1 = utils.o do_locs.o +LOC2 = get_gal.o get_plan.o get_star.o sav_plan.o + +LOC_OBJS = Locations.o $(LOC1) $(LOC2) + +Locations: $(LOC_OBJS) + cc $(LOC_OBJS) -o ../bin/Locations + +Locations.o: Locations.c fh.h + cc -c Locations.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_star: get_star.c fh.h + cc -c get_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +do_locs.o: do_locs.c fh.h + cc -c do_locs.c diff --git a/src/mk.mapgal b/src/mk.mapgal new file mode 100644 index 0000000..7838606 --- /dev/null +++ b/src/mk.mapgal @@ -0,0 +1,15 @@ + +MAP_OBJS = MapGalaxy.o get_gal.o get_star.o + + +MapGalaxy: $(MAP_OBJS) + cc $(MAP_OBJS) -o ../bin/MapGalaxy + +MapGalaxy.o: MapGalaxy.c fh.h + cc -c MapGalaxy.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c diff --git a/src/mk.mho b/src/mk.mho new file mode 100644 index 0000000..602d43e --- /dev/null +++ b/src/mk.mho @@ -0,0 +1,15 @@ + +MHO_OBJS = MakeHomes.o get_star.o utils.o + + +MakeHomes: $(MHO_OBJS) + cc $(MHO_OBJS) -o ../bin/MakeHomes + +MakeHomes.o: MakeHomes.c fh.h + cc -c MakeHomes.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_star.o: get_star.c fh.h + cc -c get_star.c diff --git a/src/mk.near b/src/mk.near new file mode 100644 index 0000000..e02f068 --- /dev/null +++ b/src/mk.near @@ -0,0 +1,24 @@ + +NEAR_OBJS = Near.o utils.o get_gal.o get_star.o get_plan.o scan.o + + +Near: $(NEAR_OBJS) + cc $(NEAR_OBJS) -o ../bin/Near + +Near.o: Near.c fh.h + cc -c Near.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +scan.o: scan.c fh.h + cc -c scan.c diff --git a/src/mk.newgal b/src/mk.newgal new file mode 100644 index 0000000..ae374c6 --- /dev/null +++ b/src/mk.newgal @@ -0,0 +1,18 @@ + +NEW_OBJS = NewGalaxy.o get_star.o utils.o gen_plan.o + + +NewGalaxy: $(NEW_OBJS) + cc $(NEW_OBJS) -o ../bin/NewGalaxy + +NewGalaxy.o: NewGalaxy.c fh.h + cc -c NewGalaxy.c + +utils.o: utils.c fh.h + cc -c utils.c + +gen_plan.o: gen_plan.c fh.h + cc -c gen_plan.c + +get_star.o: get_star.c fh.h + cc -c get_star.c diff --git a/src/mk.no b/src/mk.no new file mode 100644 index 0000000..9153efe --- /dev/null +++ b/src/mk.no @@ -0,0 +1,27 @@ + +NOO1 = utils.o parse.o +NOO2 = get_gal.o get_plan.o get_star.o + +NOO_OBJS = NoOrders.o $(NOO1) $(NOO2) + + +NoOrders: $(NOO_OBJS) + cc $(NOO_OBJS) -o ../bin/NoOrders + +NoOrders.o: NoOrders.c fh.h + cc -c NoOrders.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_star.o: get_star.c fh.h + cc -c get_star.c diff --git a/src/mk.post b/src/mk.post new file mode 100644 index 0000000..24125cf --- /dev/null +++ b/src/mk.post @@ -0,0 +1,112 @@ + +POST1 = utils.o parse.o do_scan.o scan.o sav_plan.o sav_transact.o do_neutral.o do_rep.o +POST2 = get_gal.o get_star.o get_plan.o do_land.o dis_ship.o do_deep.o do_ally.o do_tran.o +POST3 = get_transact.o get_spnam.o do_name.o do_orbit.o do_tech.o do_send.o do_des.o +POST4 = sav_star.o get_loc.o get_ship.o gam_abo.o do_mes.o do_terr.o do_enemy.o do_tel.o do_teach.o get_transfer.o + +POST_OBJS = PostArrival.o $(POST1) $(POST2) $(POST3) $(POST4) + +PostArrival: $(POST_OBJS) + cc $(POST_OBJS) -o ../bin/PostArrival + +PostArrival.o: PostArrival.c fh.h + cc -c PostArrival.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +sav_transact.o: sav_transact.c fh.h + cc -c sav_transact.c + +get_loc.o: get_loc.c fh.h + cc -c get_loc.c + +get_spnam.o: get_spnam.c fh.h + cc -c get_spnam.c + +get_ship.o: get_ship.c fh.h + cc -c get_ship.c + +do_send.o: do_send.c fh.h + cc -c do_send.c + +do_scan.o: do_scan.c fh.h + cc -c do_scan.c + +scan.o: scan.c fh.h + cc -c scan.c + +do_name.o: do_name.c fh.h + cc -c do_name.c + +do_tran.o: do_tran.c fh.h + cc -c do_tran.c + +do_ally.o: do_ally.c fh.h + cc -c do_ally.c + +do_enemy.o: do_enemy.c fh.h + cc -c do_enemy.c + +do_neutral.o: do_neutral.c fh.h + cc -c do_neutral.c + +do_land.o: do_land.c fh.h + cc -c do_land.c + +do_deep.o: do_deep.c fh.h + cc -c do_deep.c + +do_orbit.o: do_orbit.c fh.h + cc -c do_orbit.c + +do_mes.o: do_mes.c fh.h + cc -c do_mes.c + +do_rep.o: do_rep.c fh.h + cc -c do_rep.c + +do_tech.o: do_tech.c fh.h + cc -c do_tech.c + +do_teach.o: do_teach.c fh.h + cc -c do_teach.c + +do_terr.o: do_terr.c fh.h + cc -c do_terr.c + +do_des.o: do_des.c fh.h + cc -c do_des.c + +do_tel.o: do_tel.c fh.h + cc -c do_tel.c + +dis_ship.o: dis_ship.c fh.h + cc -c dis_ship.c + +gam_abo.o: gam_abo.c + cc -c gam_abo.c + +get_transfer.o: get_transfer.c fh.h + cc -c get_transfer.c diff --git a/src/mk.pre b/src/mk.pre new file mode 100644 index 0000000..b0716d2 --- /dev/null +++ b/src/mk.pre @@ -0,0 +1,112 @@ + +PRE1 = utils.o parse.o do_scan.o scan.o do_tran.o do_deep.o do_ally.o do_base.o do_disband.o +PRE2 = get_gal.o get_star.o get_plan.o do_inst.o get_transact.o do_neutral.o do_des.o +PRE3 = do_land.o do_unl.o do_mes.o do_orbit.o sav_transact.o do_send.o do_enemy.o +PRE4 = sav_star.o sav_plan.o get_loc.o get_ship.o gam_abo.o do_name.o get_spnam.o dis_ship.o do_rep.o get_transfer.o + +PRE_OBJS = PreDeparture.o $(PRE1) $(PRE2) $(PRE3) $(PRE4) + +PreDeparture: $(PRE_OBJS) + cc $(PRE_OBJS) -o ../bin/PreDeparture + +PreDeparture.o: PreDeparture.c fh.h + cc -c PreDeparture.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +sav_transact.o: sav_transact.c fh.h + cc -c sav_transact.c + +get_loc.o: get_loc.c fh.h + cc -c get_loc.c + +get_spnam.o: get_spnam.c fh.h + cc -c get_spnam.c + +get_ship.o: get_ship.c fh.h + cc -c get_ship.c + +do_tran.o: do_tran.c fh.h + cc -c do_tran.c + +do_send.o: do_send.c fh.h + cc -c do_send.c + +do_scan.o: do_scan.c fh.h + cc -c do_scan.c + +scan.o: scan.c fh.h + cc -c scan.c + +do_inst.o: do_inst.c fh.h + cc -c do_inst.c + +do_ally.o: do_ally.c fh.h + cc -c do_ally.c + +do_enemy.o: do_enemy.c fh.h + cc -c do_enemy.c + +do_neutral.o: do_neutral.c fh.h + cc -c do_neutral.c + +do_name.o: do_name.c fh.h + cc -c do_name.c + +do_deep.o: do_deep.c fh.h + cc -c do_deep.c + +do_land.o: do_land.c fh.h + cc -c do_land.c + +do_orbit.o: do_orbit.c fh.h + cc -c do_orbit.c + +do_mes.o: do_mes.c fh.h + cc -c do_mes.c + +do_rep.o: do_rep.c fh.h + cc -c do_rep.c + +do_unl.o: do_unl.c fh.h + cc -c do_unl.c + +do_des.o: do_des.c fh.h + cc -c do_des.c + +do_base.o: do_base.c fh.h + cc -c do_base.c + +do_disband.o: do_disband.c fh.h + cc -c do_disband.c + +dis_ship.o: dis_ship.c fh.h + cc -c dis_ship.c + +gam_abo.o: gam_abo.c + cc -c gam_abo.c + +get_transfer.o: get_transfer.c fh.h + cc -c get_transfer.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c diff --git a/src/mk.pro b/src/mk.pro new file mode 100644 index 0000000..af7c518 --- /dev/null +++ b/src/mk.pro @@ -0,0 +1,97 @@ + +PRO1 = utils.o parse.o money.o do_prod.o get_ship.o do_est.o do_enemy.o do_dev.o +PRO2 = get_gal.o get_plan.o do_recy.o sav_plan.o do_upg.o do_shipyard.o do_neutral.o +PRO3 = gam_abo.o do_build.o do_res.o get_spnam.o do_hide.o do_ally.o get_transfer.o +PRO4 = get_loc.o do_amb.o get_transact.o sav_transact.o do_int.o get_star.o + +PRO_OBJS = Production.o $(PRO1) $(PRO2) $(PRO3) $(PRO4) + +Production: $(PRO_OBJS) + cc $(PRO_OBJS) -o ../bin/Production + +Production.o: Production.c fh.h + cc -c Production.c + +utils.o: utils.c fh.h + cc -c utils.c + +parse.o: parse.c fh.h + cc -c parse.c + +money.o: money.c fh.h + cc -c money.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_ship.o: get_ship.c fh.h + cc -c get_ship.c + +get_spnam.o: get_spnam.c fh.h + cc -c get_spnam.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c + +do_prod.o: do_prod.c fh.h + cc -c do_prod.c + +do_build.o: do_build.c fh.h + cc -c do_build.c + +do_recy.o: do_recy.c fh.h + cc -c do_recy.c + +do_res.o: do_res.c fh.h + cc -c do_res.c + +do_est.o: do_est.c fh.h + cc -c do_est.c + +do_upg.o: do_upg.c fh.h + cc -c do_upg.c + +do_amb.o: do_amb.c fh.h + cc -c do_amb.c + +do_int.o: do_int.c fh.h + cc -c do_int.c + +do_hide.o: do_hide.c fh.h + cc -c do_hide.c + +do_ally.o: do_ally.c fh.h + cc -c do_ally.c + +do_enemy.o: do_enemy.c fh.h + cc -c do_enemy.c + +do_neutral.o: do_neutral.c fh.h + cc -c do_neutral.c + +do_shipyard.o: do_shipyard.c fh.h + cc -c do_shipyard.c + +do_dev.o: do_dev.c fh.h + cc -c do_dev.c + +gam_abo.o: gam_abo.c + cc -c gam_abo.c + +get_transact.o: get_transact.c fh.h + cc -c get_transact.c + +get_loc.o: get_loc.c fh.h + cc -c get_loc.c + +sav_transact.o: sav_transact.c fh.h + cc -c sav_transact.c + +get_transfer.o: get_transfer.c fh.h + cc -c get_transfer.c diff --git a/src/mk.report b/src/mk.report new file mode 100644 index 0000000..39c55c9 --- /dev/null +++ b/src/mk.report @@ -0,0 +1,20 @@ + +REP_OBJS = Report.o get_gal.o get_star.o get_plan.o utils.o + +Report: $(REP_OBJS) + cc $(REP_OBJS) -o ../bin/Report + +Report.o: Report.c fh.h + cc -c Report.c + +utils.o: utils.c fh.h + cc -c utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +get_star.o: get_star.c fh.h + cc -c get_star.c diff --git a/src/mk.scan b/src/mk.scan new file mode 100644 index 0000000..c5d409c --- /dev/null +++ b/src/mk.scan @@ -0,0 +1,30 @@ + +SCAN1 = scan.o utils.o +SCAN2 = get_gal.o get_star.o get_plan.o + +SCAN_OBJS = ScanSpXYZ.o $(SCAN1) $(SCAN2) + + +ScanSpXYZ: $(SCAN_OBJS) + cc $(SCAN_OBJS) -o ../bin/ScanSpXYZ + +ScanSpXYZ.o: ScanSpXYZ.c fh.h + cc -c ScanSpXYZ.c + +get_spec.o: get_spec.c fh.h + cc -c get_spec.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +scan.o: scan.c fh.h + cc -c scan.c + +utils.o: utils.c fh.h + cc -c utils.c diff --git a/src/mk.set b/src/mk.set new file mode 100644 index 0000000..64a0ef3 --- /dev/null +++ b/src/mk.set @@ -0,0 +1,24 @@ + +SET_OBJS = Set.o get_gal.o get_star.o get_plan.o sav_star.o sav_plan.o + + +Set: $(SET_OBJS) + cc -o ../bin/Set $(SET_OBJS) + +Set.o: Set.c fh.h + cc -c Set.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c + +sav_star.o: sav_star.c fh.h + cc -c sav_star.c + +sav_plan.o: sav_plan.c fh.h + cc -c sav_plan.c diff --git a/src/mk.setup b/src/mk.setup new file mode 100644 index 0000000..0fe3ac2 --- /dev/null +++ b/src/mk.setup @@ -0,0 +1,18 @@ + +SETUP_OBJS = Setup.o parse.o get_gal.o gam_abo.o + + +Setup: $(SETUP_OBJS) + cc $(SETUP_OBJS) -o FH:bin/Setup + +Setup.o: Setup.c fh.h + cc -c Setup.c + +parse.o: parse.c fh.h + cc -c parse.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +gam_abo.o: gam_abo.c + cc -c gam_abo.c diff --git a/src/mk.showgal b/src/mk.showgal new file mode 100644 index 0000000..75346ac --- /dev/null +++ b/src/mk.showgal @@ -0,0 +1,18 @@ + +SHOW_OBJS = ShowGalaxy.o get_gal.o get_star.o get_plan.o + + +ShowGalaxy: $(SHOW_OBJS) + cc $(SHOW_OBJS) -o ../bin/ShowGalaxy + +ShowGalaxy.o: ShowGalaxy.c fh.h + cc -c ShowGalaxy.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_star.o: get_star.c fh.h + cc -c get_star.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c diff --git a/src/mk.stats b/src/mk.stats new file mode 100644 index 0000000..b52220d --- /dev/null +++ b/src/mk.stats @@ -0,0 +1,20 @@ + +STAT_OBJS = Stats.o get_gal.o get_star.o get_plan.o utils.o combat_utils.o + +Stats: $(STAT_OBJS) + cc $(STAT_OBJS) -o ../bin/Stats + +Stats.o: Stats.c fh.h + cc -c Stats.c + +utils.o: utils.c fh.h + cc -c utils.c + +combat_utils.o: combat_utils.c + cc -c combat_utils.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c + +get_plan.o: get_plan.c fh.h + cc -c get_plan.c diff --git a/src/mk.turn b/src/mk.turn new file mode 100644 index 0000000..2839266 --- /dev/null +++ b/src/mk.turn @@ -0,0 +1,12 @@ + +TURN_OBJS = TurnNumber.o get_gal.o + + +TurnNumber: $(TURN_OBJS) + cc $(TURN_OBJS) -o ../bin/TurnNumber + +TurnNumber.o: TurnNumber.c fh.h + cc -c TurnNumber.c + +get_gal.o: get_gal.c fh.h + cc -c get_gal.c diff --git a/src/money.c b/src/money.c new file mode 100644 index 0000000..e4fe5ff --- /dev/null +++ b/src/money.c @@ -0,0 +1,103 @@ + +#include "fh.h" + + +long balance, raw_material_units, production_capacity, EU_spending_limit; + + +extern FILE *log_file; +extern struct species_data *species; +extern struct nampla_data *nampla; + + +int check_bounced (amount_needed) + +long amount_needed; + +{ + long take_from_EUs, limiting_balance; + + + /* Check if we have sufficient funds for this purchase. */ + if (amount_needed > balance) + { + take_from_EUs = amount_needed - balance; + + if (take_from_EUs <= EU_spending_limit + && take_from_EUs <= species->econ_units) + { + species->econ_units -= take_from_EUs; + EU_spending_limit -= take_from_EUs; + balance = amount_needed; + } + else + return TRUE; + } + + /* Reduce various balances appropriately. */ + if (raw_material_units >= amount_needed) + { + if (production_capacity >= amount_needed) + { + /* Enough of both. */ + raw_material_units -= amount_needed; + production_capacity -= amount_needed; + } + else + { + /* Enough RMs but not enough PC. */ + raw_material_units -= production_capacity; + production_capacity = 0; + } + } + else + { + if (production_capacity >= amount_needed) + { + /* Enough PC but not enough RMs. */ + production_capacity -= raw_material_units; + raw_material_units = 0; + } + else + { + /* Not enough RMs or PC. */ + limiting_balance = (raw_material_units > production_capacity) + ? production_capacity : raw_material_units; + raw_material_units -= limiting_balance; + production_capacity -= limiting_balance; + } + } + + balance -= amount_needed; + + return FALSE; +} + + + +transfer_balance () +{ + long limiting_amount; + + + /* Log end of production. Do not print ending balance for mining + or resort colonies. */ + limiting_amount = 0; + fprintf (log_file, " End of production on PL %s.", nampla->name); + if ( ! (nampla->status & (MINING_COLONY | RESORT_COLONY)) ) + { + limiting_amount = (raw_material_units > production_capacity) + ? production_capacity : raw_material_units; + fprintf (log_file, " (Ending balance is %ld.)", limiting_amount); + } + fprintf (log_file, "\n"); + + /* Convert unused balance to economic units. */ + species->econ_units += limiting_amount; + raw_material_units -= limiting_amount; + + /* Carry over unused raw material units into next turn. */ + nampla->item_quantity[RM] += raw_material_units; + + balance = 0; +} diff --git a/src/parse.c b/src/parse.c new file mode 100644 index 0000000..cc1ec3e --- /dev/null +++ b/src/parse.c @@ -0,0 +1,430 @@ + +#include "fh.h" + + +int end_of_file = FALSE; +int abbr_type, abbr_index, sub_light, tonnage, just_opened_file; +char input_abbr[256], input_line[256], original_line[256], *input_line_pointer; +char original_name[32], upper_name[32]; +long value; +FILE *input_file; + + +/* Skip white space and comments. */ +skip_junk () +{ +again: + + /* Read next line. */ + input_line_pointer = fgets (input_line, 256, input_file); + if (input_line_pointer == NULL) + { + end_of_file = TRUE; + return; + } + + if (just_opened_file) /* Skip mail header, if any. */ + { + if (*input_line == '\n') goto again; + + just_opened_file = FALSE; + + if (strncmp (input_line, "From ", 5) == 0) /* This is a mail header. */ + { + while (TRUE) + { + input_line_pointer = fgets (input_line, 256, input_file); + if (input_line_pointer == NULL) + { + end_of_file = TRUE; /* Weird. */ + return; + } + if (*input_line == '\n') break; /* End of header. */ + } + + goto again; + } + } + + strcpy (original_line, input_line); /* Make a copy. */ + + /* Skip white space and comments. */ + while (TRUE) + { + switch (*input_line_pointer) + { + case ';': /* Semi-colon. */ + case '\n': /* Newline. */ + goto again; + + case '\t': /* Tab. */ + case ' ': /* Space. */ + case ',': /* Comma. */ + ++input_line_pointer; + continue; + + default: + return; + } + } +} + + +skip_whitespace () +{ + while (TRUE) + { + switch (*input_line_pointer) + { + case '\t': /* Tab. */ + case ' ': /* Space. */ + case ',': /* Comma. */ + ++input_line_pointer; + break; + + default: + return; + } + } +} + + + +/* The following "get" routines will return 0 if the item found was not + of the appropriate type, and 1 or greater if an item of the correct + type was found. */ + + +/* Get a command and return its index. */ +int get_command () +{ + int i, cmd_n; + char c, cmd_s[4]; + + + skip_junk(); + if (end_of_file) + return -1; + + c = *input_line_pointer; + /* Get first three characters of command word. */ + for (i = 0; i < 3; i++) + { + if (! isalpha (c)) return 0; + cmd_s[i] = toupper (c); + ++input_line_pointer; + c = *input_line_pointer; + } + cmd_s[3] = '\0'; + + /* Skip everything after third character of command word. */ + while (1) + { + switch (c) + { + case '\t': + case '\n': + case ' ': + case ',': + case ';': + goto find_cmd; + + default: + ++input_line_pointer; + c = *input_line_pointer; + } + } + + find_cmd: + + /* Find corresponding string in list. */ + cmd_n = UNKNOWN; + for (i = 1; i < NUM_COMMANDS; i++) + { + if (strcmp(cmd_s, command_abbr[i]) == 0) + { + cmd_n = i; + break; + } + } + + return cmd_n; +} + + +/* Get a class abbreviation and return TECH_ID, ITEM_CLASS, SHIP_CLASS, + PLANET_ID, SPECIES_ID or ALLIANCE_ID as appropriate, or UNKNOWN if it + cannot be identified. Also, set "abbr_type" to this value. If it is + TECH_ID, ITEM_CLASS or SHIP_CLASS, "abbr_index" will contain the + abbreviation index. If it is a ship, "tonnage" will contain tonnage/10,000, + and "sub_light" will be TRUE or FALSE. (Tonnage value returned is based + ONLY on abbreviation.) */ + +int get_class_abbr () +{ + int i; + + char *digit_start; + + + skip_whitespace(); + + abbr_type = UNKNOWN; + + if (! isalnum (*input_line_pointer)) return UNKNOWN; + input_abbr[0] = toupper(*input_line_pointer); + ++input_line_pointer; + + if (! isalnum (*input_line_pointer)) return UNKNOWN; + input_abbr[1] = toupper(*input_line_pointer); + ++input_line_pointer; + + input_abbr[2] = '\0'; + + /* Check for IDs that are followed by one or more digits or letters. */ + i = 2; + digit_start = input_line_pointer; + while (isalnum (*input_line_pointer)) + { + input_abbr[i++] = *input_line_pointer++; + input_abbr[i] = '\0'; + } + + /* Check tech ID. */ + for (i = 0; i < 6; i++) + { + if (strcmp(input_abbr, tech_abbr[i]) == 0) + { + abbr_index = i; + abbr_type = TECH_ID; + return abbr_type; + } + } + + /* Check item abbreviations. */ + for (i = 0; i < MAX_ITEMS; i++) + { + if (strcmp(input_abbr, item_abbr[i]) == 0) + { + abbr_index = i; + abbr_type = ITEM_CLASS; + return abbr_type; + } + } + + /* Check ship abbreviations. */ + for (i = 0; i < NUM_SHIP_CLASSES; i++) + { + if (strncmp(input_abbr, ship_abbr[i], 2) == 0) + { + input_line_pointer = digit_start; + abbr_index = i; + tonnage = ship_tonnage[i]; + if (i == TR) + { + tonnage = 0; + while (isdigit(*input_line_pointer)) + { + tonnage = (10 * tonnage) + (*input_line_pointer - '0'); + ++input_line_pointer; + } + } + + if (toupper(*input_line_pointer) == 'S') + { + sub_light = TRUE; + ++input_line_pointer; + } + else + sub_light = FALSE; + + if (isalnum (*input_line_pointer)) break; /* Garbage. */ + + abbr_type = SHIP_CLASS; + return abbr_type; + } + } + + /* Check for planet name. */ + if (strcmp(input_abbr, "PL") == 0) + { + abbr_type = PLANET_ID; + return abbr_type; + } + + /* Check for species name. */ + if (strcmp(input_abbr, "SP") == 0) + { + abbr_type = SPECIES_ID; + return abbr_type; + } + + abbr_type = UNKNOWN; + return abbr_type; +} + + +/* Get a name and copy original version to "original_name" and upper + case version to "upper_name". Return length of name. */ +int get_name () +{ + int name_length; + + char c; + + + skip_whitespace(); + + name_length = 0; + while (TRUE) + { + c = *input_line_pointer; + if (c == ';') break; + ++input_line_pointer; + if (c == ',' || c == '\t' || c == '\n') + break; + if (name_length < 31) + { + original_name[name_length] = c; + upper_name[name_length] = toupper(c); + ++name_length; + } + } + + /* Remove any final spaces in name. */ + while (name_length > 0) + { + c = original_name[name_length-1]; + if (c != ' ') + break; + --name_length; + } + + /* Terminate strings. */ + original_name[name_length] = '\0'; + upper_name[name_length] = '\0'; + + return name_length; +} + + +/* Read a long decimal and place its value in 'value'. */ +int get_value () +{ + int n; + + + skip_whitespace(); + + n = sscanf (input_line_pointer, "%ld", &value); + if (n != 1) return 0; /* Not a numeric value. */ + + /* Skip numeric string. */ + ++input_line_pointer; /* Skip first sign or digit. */ + while (isdigit(*input_line_pointer)) ++input_line_pointer; + + return 1; +} + + + +/* The following routine will check that the next argument in the current + command line is followed by a comma or tab. If not present, it will + try to insert a comma in the proper position. This routine should + be called only AFTER an error has been detected. */ + +fix_separator () + +{ + int n, first_class, fix_made, num_commas; + + char c, *temp_ptr, *temp2_ptr, *first_comma; + + + skip_whitespace (); + + if (isdigit (*input_line_pointer)) return; /* Nothing can be done. */ + + if (strchr (input_line_pointer, ' ') == NULL) return; /* Ditto. */ + + fix_made = FALSE; + + /* Look for a ship, planet, or species abbreviation after the first one. + If it is preceeded by a space, convert the space to a comma. */ + temp_ptr = input_line_pointer; + first_class = get_class_abbr (); /* Skip first one but remember what it was. */ + while (1) + { + skip_whitespace (); + temp2_ptr = input_line_pointer - 1; + if (*input_line_pointer == '\n') break; + if (*input_line_pointer == ';') break; + + /* The following is to prevent an infinite loop. */ + if (! isalnum (*input_line_pointer)) + { + ++input_line_pointer; + continue; + } + + n = get_class_abbr (); + if (n == SHIP_CLASS || n == PLANET_ID || n == SPECIES_ID) + { + /* Convert space preceeding abbreviation to a comma. */ + if (*temp2_ptr == ' ') + { + *temp2_ptr = ','; + fix_made = TRUE; + } + } + } + input_line_pointer = temp_ptr; + + if (fix_made) return; + + /* Look for a space followed by a digit. If found, convert the space + to a comma. If exactly two or four commas are added, re-convert + the first one back to a space; e.g. Jump TR1 Seeker,7,99,99,99 or + Build TR1 Seeker,7,50. */ + num_commas = 0; + while (1) + { + c = *temp_ptr++; + + if (c == '\n') break; + if (c == ';') break; + + if (c != ' ') continue; + if (isdigit (*temp_ptr)) + { + --temp_ptr; /* Convert space to a comma. */ + *temp_ptr = ','; + if (num_commas++ == 0) first_comma = temp_ptr; + ++temp_ptr; + fix_made = TRUE; + } + } + + if (fix_made) + { + if (num_commas == 2 || num_commas == 4) *first_comma = ' '; + return; + } + + /* Now's the time for wild guesses. */ + temp_ptr = input_line_pointer; + + /* If first word is a valid abbreviation, put a comma after the + second word. */ + if (first_class == SHIP_CLASS || first_class == PLANET_ID || first_class == SPECIES_ID) + { + temp_ptr = strchr (temp_ptr, ' ') + 1; + temp_ptr = strchr (temp_ptr, ' '); + if (temp_ptr != NULL) *temp_ptr = ','; + return; + } + + /* First word is not a valid abbreviation. Put a comma after it. */ + temp_ptr = strchr (temp_ptr, ' '); + if (temp_ptr != NULL) *temp_ptr = ','; +} diff --git a/src/regen_sh.c b/src/regen_sh.c new file mode 100644 index 0000000..e289d55 --- /dev/null +++ b/src/regen_sh.c @@ -0,0 +1,34 @@ + +#include "fh.h" +#include "combat.h" + + +extern struct species_data *c_species[MAX_SPECIES]; + + +regenerate_shields (act) + +struct action_data *act; + +{ + int i, species_index, unit_index; + + long ls, max_shield_strength, percent; + + struct ship_data *sh; + + + /* Shields are regenerated by 5 + LS/10 percent per round. */ + for (unit_index = 0; unit_index < act->num_units_fighting; unit_index++) + { + species_index = act->fighting_species_index[unit_index]; + ls = c_species[species_index]->tech_level[LS]; + max_shield_strength = act->shield_strength[unit_index]; + + percent = (ls/10L) + 5L; + act->shield_strength_left[unit_index] += + (percent * max_shield_strength) / 100L; + if (act->shield_strength_left[unit_index] > max_shield_strength) + act->shield_strength_left[unit_index] = max_shield_strength; + } +} diff --git a/src/sav_plan.c b/src/sav_plan.c new file mode 100644 index 0000000..74dc1bb --- /dev/null +++ b/src/sav_plan.c @@ -0,0 +1,44 @@ + +#include "fh.h" + + +extern int num_planets; + +extern struct planet_data *planet_base; + + +save_planet_data () + +{ + int planet_fd; + + long n, byte_size; + + + /* Open planet file for writing. */ + planet_fd = creat ("planets.dat", 0600); + if (planet_fd < 0) + { + fprintf (stderr, "\n\tCannot create file 'planets.dat'!\n"); + exit (-1); + } + + /* Write header data. */ + byte_size = write (planet_fd, &num_planets, sizeof(num_planets)); + if (byte_size != sizeof(num_planets)) + { + fprintf (stderr, "\n\tCannot write num_planets to file 'planets.dat'!\n\n"); + exit (-1); + } + + /* Write planet data to disk. */ + byte_size = (long) num_planets * sizeof(struct planet_data); + n = write (planet_fd, planet_base, byte_size); + if (n != byte_size) + { + fprintf (stderr, "\nCannot write planet data to disk!\n\n"); + exit (-1); + } + + close (planet_fd); +} diff --git a/src/sav_star.c b/src/sav_star.c new file mode 100644 index 0000000..b1ea87a --- /dev/null +++ b/src/sav_star.c @@ -0,0 +1,44 @@ + +#include "fh.h" + + +extern int num_stars; + +extern struct star_data *star_base; + + +save_star_data () + +{ + int star_fd; + + long n, byte_size; + + + /* Open star file for writing. */ + star_fd = creat ("stars.dat", 0600); + if (star_fd < 0) + { + fprintf (stderr, "\n\tCannot create file 'stars.dat'!\n"); + exit (-1); + } + + /* Write header data. */ + byte_size = write (star_fd, &num_stars, sizeof(num_stars)); + if (byte_size != sizeof(num_stars)) + { + fprintf (stderr, "\n\tCannot write num_stars to file 'stars.dat'!\n\n"); + exit (-1); + } + + /* Write star data to disk. */ + byte_size = (long) num_stars * sizeof(struct star_data); + n = write (star_fd, star_base, byte_size); + if (n != byte_size) + { + fprintf (stderr, "\nCannot write star data to disk!\n\n"); + exit (-1); + } + + close (star_fd); +} diff --git a/src/sav_transact.c b/src/sav_transact.c new file mode 100644 index 0000000..f050b38 --- /dev/null +++ b/src/sav_transact.c @@ -0,0 +1,39 @@ + +#include "fh.h" + + +extern int num_transactions; + +extern struct trans_data transaction[MAX_TRANSACTIONS]; + + +save_transaction_data () + +{ + int i, trans_fd; + long num_bytes; + + + /* Open file for writing. */ + trans_fd = creat ("interspecies.dat", 0600); + + if (trans_fd < 0) + { + fprintf (stderr, "\n\n\tCannot create file 'interspecies.dat'!\n\n"); + exit (-1); + } + + /* Write transactions to file. */ + for (i = 0; i < num_transactions; i++) + { + num_bytes = write (trans_fd, &transaction[i], sizeof(struct trans_data)); + + if (num_bytes != sizeof(struct trans_data)) + { + fprintf (stderr, "\n\n\tError writing transaction to file 'interspecies.dat'!\n\n"); + exit (-1); + } + } + + close (trans_fd); +} diff --git a/src/scan.c b/src/scan.c new file mode 100644 index 0000000..32bbe83 --- /dev/null +++ b/src/scan.c @@ -0,0 +1,128 @@ + +#include "fh.h" + + +int print_LSN = TRUE; + +extern int num_stars; +extern FILE *log_file; +extern struct star_data *star_base; +extern struct planet_data *planet_base; +extern struct species_data *species; +extern struct nampla_data *nampla_base; + + +scan (x, y, z) + +char x, y, z; + +{ + int i, j, k, n, found, num_gases, ls_needed; + + char filename[32]; + + struct star_data *star; + struct planet_data *planet, *home_planet; + struct nampla_data *home_nampla; + + + /* Find star. */ + star = star_base; + found = FALSE; + for (i = 0; i < num_stars; i++) + { + if (star->x == x && star->y == y && star->z == z) + { + found = TRUE; + break; + } + ++star; + } + + if (! found) + { + fprintf (log_file, + "Scan Report: There is no star system at x = %d, y = %d, z = %d.\n", + x, y, z); + return; + } + + /* Print data for star, */ + fprintf (log_file, "Coordinates:\tx = %d\ty = %d\tz = %d", x, y, z); + fprintf (log_file, "\tstellar type = %c%c%c", type_char[star->type], + color_char[star->color], size_char[star->size]); + + fprintf (log_file, " %d planets.\n\n", star->num_planets); + + if (star->worm_here) + fprintf (log_file, + "This star system is the terminus of a natural wormhole.\n\n"); + + /* Print header. */ + fprintf (log_file, " Temp Press Mining\n"); + fprintf (log_file, " # Dia Grav Class Class Diff LSN Atmosphere\n"); + fprintf (log_file, " ---------------------------------------------------------------------\n"); + + /* Check for nova. */ + if (star->num_planets == 0) + { + fprintf (log_file, "\n\tThis star is a nova remnant. Any planets it may have once\n"); + fprintf (log_file, "\thad have been blown away.\n\n"); + return; + } + + /* Print data for each planet. */ + planet = planet_base + (long) star->planet_index; + if (print_LSN) + { + home_nampla = nampla_base; + home_planet = planet_base + (long) home_nampla->planet_index; + } + + for (i = 1; i <= star->num_planets; i++) + { + /* Get life support tech level needed. */ + if (print_LSN) + ls_needed = life_support_needed (species, home_planet, planet); + else + ls_needed = 99; + + fprintf (log_file, " %d %3d %d.%02d %2d %2d %d.%02d %4d ", + i, + planet->diameter, + planet->gravity/100, + planet->gravity%100, + planet->temperature_class, + planet->pressure_class, + planet->mining_difficulty/100, + planet->mining_difficulty%100, + ls_needed); + + num_gases = 0; + for (n = 0; n < 4; n++) + { + if (planet->gas_percent[n] > 0) + { + if (num_gases > 0) fprintf (log_file, ","); + fprintf (log_file, "%s(%d%%)", gas_string[planet->gas[n]], + planet->gas_percent[n]); + ++num_gases; + } + } + + if (num_gases == 0) fprintf (log_file, "No atmosphere"); + + fprintf (log_file, "\n"); + ++planet; + } + + if (star->message) + { + /* There is a message that must be logged whenever this star + system is scanned. */ + sprintf (filename, "message%ld.txt\0", star->message); + log_message (filename); + } + + return; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 0000000..dfd4c5b --- /dev/null +++ b/src/utils.c @@ -0,0 +1,966 @@ + +#include "fh.h" + +/* This routine will return a random int between 1 and max, inclusive. + It uses the so-called "Algorithm M" method, which is a combination + of the congruential and shift-register methods. */ + +unsigned long last_random = 1924085713L; /* Random seed. */ + +int rnd (max) + +unsigned int max; + +{ + unsigned long a, b, c, cong_result, shift_result; + + /* For congruential method, multiply previous value by the + prime number 16417. */ + a = last_random; + b = last_random << 5; + c = last_random << 14; + cong_result = a + b + c; /* Effectively multiply by 16417. */ + + /* For shift-register method, use shift-right 15 and shift-left 17 + with no-carry addition (i.e., exclusive-or). */ + a = last_random >> 15; + shift_result = a ^ last_random; + a = shift_result << 17; + shift_result ^= a; + + last_random = cong_result ^ shift_result; + + a = last_random & 0x0000FFFF; + + return (int) ((a * (long) max) >> 16) + 1L; +} + + + +/* Routine "get_species_data" will read in data files for all species, + "save_species_data" will write all data that has been modified, and + "free_species_data" will free memory used for all species data. */ + +/* Additional memory must be allocated for routines that build ships or + name planets. Here are the default 'extras', which may be changed, if + necessary, by the main program. */ + +long extra_namplas = NUM_EXTRA_NAMPLAS; +long extra_ships = NUM_EXTRA_SHIPS; + +extern struct galaxy_data galaxy; + + +get_species_data () + +{ + int species_fd, species_index; + + long n, num_bytes; + + char filename[16]; + + struct species_data *sp; + + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + data_modified[species_index] = FALSE; + + sp = &spec_data[species_index]; + + /* Open the species data file. */ + sprintf (filename, "sp%02d.dat\0", species_index + 1); + species_fd = open (filename, 0); + if (species_fd < 0) + { + sp->pn = 0; /* Extinct! */ + data_in_memory[species_index] = FALSE; + continue; + } + + /* Read in species data. */ + num_bytes = read (species_fd, sp, sizeof(struct species_data)); + if (num_bytes != sizeof(struct species_data)) + { + fprintf (stderr, "\n\tCannot read species record in file '%s'!\n\n", + filename); + exit (-1); + } + + /* Allocate enough memory for all namplas. */ + num_bytes = (sp->num_namplas + extra_namplas) * sizeof (struct nampla_data); + namp_data[species_index] = (struct nampla_data *) malloc (num_bytes); + if (namp_data[species_index] == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for nampla data!\n\n"); + exit (-1); + } + + /* Read it all into memory. */ + num_bytes = (long) sp->num_namplas * sizeof (struct nampla_data); + n = read (species_fd, namp_data[species_index], num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read nampla data into memory!\n\n"); + exit (-1); + } + + /* Allocate enough memory for all ships. */ + num_bytes = (sp->num_ships + extra_ships) * sizeof (struct ship_data); + ship_data[species_index] = (struct ship_data *) malloc (num_bytes); + if (ship_data[species_index] == NULL) + { + fprintf (stderr, "\nCannot allocate enough memory for ship data!\n\n"); + exit (-1); + } + + if (sp->num_ships > 0) + { + /* Read it all into memory. */ + num_bytes = (long) sp->num_ships * sizeof (struct ship_data); + n = read (species_fd, ship_data[species_index], num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot read ship data into memory!\n\n"); + exit (-1); + } + } + + close (species_fd); + + data_in_memory[species_index] = TRUE; + num_new_namplas[species_index] = 0; + num_new_ships[species_index] = 0; + } +} + + + +save_species_data () + +{ + int species_fd, species_index; + + long n, num_bytes; + + char filename[16]; + + struct species_data *sp; + + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (! data_modified[species_index]) continue; + + sp = &spec_data[species_index]; + + /* Open the species data file. */ + sprintf (filename, "sp%02d.dat\0", species_index + 1); + species_fd = creat (filename, 0600); + if (species_fd < 0) + { + fprintf (stderr, "\n Cannot create new version of file '%s'!\n", + filename); + exit (-1); + } + + /* Write species data. */ + num_bytes = write (species_fd, sp, sizeof(struct species_data)); + if (num_bytes != sizeof(struct species_data)) + { + fprintf (stderr, "\n\tCannot write species record to file '%s'!\n\n", + filename); + exit (-1); + } + + /* Write nampla data. */ + num_bytes = sp->num_namplas * sizeof (struct nampla_data); + n = write (species_fd, namp_data[species_index], num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot write nampla data to file!\n\n"); + exit (-1); + } + + if (sp->num_ships > 0) + { + /* Write ship data. */ + num_bytes = (long) sp->num_ships * sizeof (struct ship_data); + n = write (species_fd, ship_data[species_index], num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\nCannot write ship data to file!\n\n"); + exit (-1); + } + } + + close (species_fd); + + data_modified[species_index] = FALSE; + } +} + + + +free_species_data () + +{ + int species_index; + + + for (species_index = 0; species_index < galaxy.num_species; species_index++) + { + if (data_in_memory[species_index]) + { + free (namp_data[species_index]); + + if (spec_data[species_index].num_ships > 0) + free (ship_data[species_index]); + + data_in_memory[species_index] = FALSE; + data_modified[species_index] = FALSE; + } + } +} + + + +/* The following two routines will delete a ship or nampla record. */ + +delete_ship (ship) + +struct ship_data *ship; + +{ + int i; + + char *cp; + + + /* Set all bytes of record to zero. */ + cp = (char *) ship; + for (i = 0; i < sizeof (struct ship_data); i++) + *cp++ = 0; + + ship->pn = 99; + strcpy (ship->name, "Unused"); +} + + +delete_nampla (nampla) + +struct nampla_data *nampla; + +{ + int i; + + char *cp; + + + /* Set all bytes of record to zero. */ + cp = (char *) nampla; + for (i = 0; i < sizeof (struct nampla_data); i++) + *cp++ = 0; + + nampla->pn = 99; + strcpy (nampla->name, "Unused"); +} + + + + +/* This routine is intended to take a long argument and return a pointer + to a string that has embedded commas to make the string more readable. */ + +char result_plus_commas[33]; + +char *commas (value) + +long value; + +{ + int i, j, n, length, negative; + + char *ptr, temp[32]; + + long abs_value; + + + if (value < 0) + { + abs_value = -value; + negative = TRUE; + } + else + { + abs_value = value; + negative = FALSE; + } + + sprintf (temp, "%ld\0", abs_value); + + length = strlen (temp); + + i = length - 1; + j = 31; + result_plus_commas[32] = '\0'; + for (n = 0; n < length; n++) + { + result_plus_commas[j--] = temp[i--]; + if (j % 4 == 0) + result_plus_commas[j--] = ','; + } + + j++; + if (result_plus_commas[j] == ',') j++; + + if (negative) + result_plus_commas[--j] = '-'; + + return &result_plus_commas[j]; +} + + + +/* This routine will return a pointer to a string containing a complete + ship name, including its orbital/landed status and age. If global + variable "truncate_name" is TRUE, then orbital/landed status and age + will not be included. */ + +int truncate_name = FALSE; +int ignore_field_distorters = FALSE; + +char full_ship_id[64]; + +char *ship_name (ship) + +struct ship_data *ship; + +{ + int effective_age, status, ship_is_distorted; + + char temp[16]; + + + if (ship->item_quantity[FD] == ship->tonnage) + ship_is_distorted = TRUE; + else + ship_is_distorted = FALSE; + + if (ship->status == ON_SURFACE) ship_is_distorted = FALSE; + + if (ignore_field_distorters) ship_is_distorted = FALSE; + + if (ship_is_distorted) + { + if (ship->class == TR) + sprintf (full_ship_id, "%s%d ???\0", ship_abbr[ship->class], + ship->tonnage); + else if (ship->class == BA) + sprintf (full_ship_id, "BAS ???\0"); + else + sprintf (full_ship_id, "%s ???\0", ship_abbr[ship->class]); + } + else if (ship->class == TR) + { + sprintf (full_ship_id, "%s%d%s %s\0", + ship_abbr[ship->class], ship->tonnage, ship_type[ship->type], + ship->name); + } + else + { + sprintf (full_ship_id, "%s%s %s\0", + ship_abbr[ship->class], ship_type[ship->type], ship->name); + } + + if (truncate_name) return &full_ship_id[0]; + + strcat (full_ship_id, " ("); + + effective_age = ship->age; + if (effective_age < 0) effective_age = 0; + + if (! ship_is_distorted) + { + if (ship->status != UNDER_CONSTRUCTION) + { + /* Do age. */ + sprintf (temp, "A%d,\0", effective_age); + strcat (full_ship_id, temp); + } + } + + status = ship->status; + switch (status) + { + case UNDER_CONSTRUCTION: + sprintf (temp, "C\0"); + break; + case IN_ORBIT: + sprintf (temp, "O%d\0", ship->pn); + break; + case ON_SURFACE: + sprintf (temp, "L%d\0", ship->pn); + break; + case IN_DEEP_SPACE: + sprintf (temp, "D\0"); + break; + case FORCED_JUMP: + sprintf (temp, "FJ\0"); + break; + case JUMPED_IN_COMBAT: + sprintf (temp, "WD\0"); + break; + default: + sprintf (temp, "***???***\0"); + fprintf (stderr, "\n\tWARNING!!! Internal error in subroutine 'ship_name'\n\n"); + } + + strcat (full_ship_id, temp); + + if (ship->type == STARBASE) + { + sprintf (temp, ",%ld tons\0", 10000L * (long) ship->tonnage); + strcat (full_ship_id, temp); + } + + strcat (full_ship_id, ")"); + + return &full_ship_id[0]; +} + + + +/* The following routines will post an item to standard output and to + an externally defined log file and summary file. */ + +FILE *log_file, *summary_file; + +int log_start_of_line = TRUE; +int log_indentation = 0; +int log_position = 0; +int logging_disabled = FALSE; +int log_to_file = TRUE; +int log_summary = FALSE; +int log_stdout = TRUE; + +char log_line[128]; + + +log_char (c) + +char c; + +{ + int i, temp_position; + + char temp_char; + + + if (logging_disabled) return; + + /* Check if current line is getting too long. */ + if ((c == ' ' || c == '\n') && log_position > 77) + { + /* Find closest preceeding space. */ + temp_position = log_position - 1; + while (log_line[temp_position] != ' ') --temp_position; + + /* Write front of line to files. */ + temp_char = log_line[temp_position+1]; + log_line[temp_position] = '\n'; + log_line[temp_position+1] = '\0'; + if (log_to_file) fputs (log_line, log_file); + if (log_stdout) fputs (log_line, stdout); + if (log_summary) fputs (log_line, summary_file); + log_line[temp_position+1] = temp_char; + + /* Copy overflow word to beginning of next line. */ + log_line[log_position] = '\0'; + log_position = log_indentation + 2; + for (i = 0; i < log_position; i++) + log_line[i] = ' '; + strcpy (&log_line[log_position], &log_line[temp_position+1]); + + log_position = strlen (log_line); + + if (c == ' ') + { + log_line[log_position++] = ' '; + return; + } + } + + /* Check if line is being manually terminated. */ + if (c == '\n') + { + /* Write current line to output. */ + log_line[log_position] = '\n'; + log_line[log_position+1] = '\0'; + if (log_to_file) fputs (log_line, log_file); + if (log_stdout) fputs (log_line, stdout); + if (log_summary) fputs (log_line, summary_file); + + /* Set up for next line. */ + log_position = 0; + log_indentation = 0; + log_start_of_line = TRUE; + + return; + } + + /* Save this character. */ + log_line[log_position] = c; + ++log_position; + + if (log_start_of_line && c == ' ') /* Determine number of indenting */ + ++log_indentation; /* spaces for current line. */ + else + log_start_of_line = FALSE; +} + + +log_string (string) + +char string[]; + +{ + int i, length; + + + if (logging_disabled) return; + + length = strlen (string); + for (i = 0; i < length; i++) + log_char (string[i]); +} + + +log_int (value) + +int value; + +{ + char string[16]; + + + if (logging_disabled) return; + + sprintf (string, "%d\0", value); + log_string (string); +} + + +log_long (value) + +long value; + +{ + char string[16]; + + + if (logging_disabled) return; + + sprintf (string, "%ld\0", value); + log_string (string); +} + + + +int num_locs = 0; + +struct sp_loc_data loc[MAX_LOCATIONS]; + +get_location_data () + +{ + int locations_fd; + + long n, file_size; + + + /* Open locations file. */ + locations_fd = open ("locations.dat", 0); + if (locations_fd < 0) + { + fprintf (stderr, "\nCannot open file 'locations.dat' for reading!\n\n"); + exit (-1); + } + + /* Get size of file. */ + file_size = lseek (locations_fd, 0L, 2); + num_locs = file_size / sizeof (struct sp_loc_data); + + /* Read it all into memory. */ + lseek (locations_fd, 0L, 0); /* Rewind first. */ + n = read (locations_fd, loc, file_size); + if (n != file_size) + { + fprintf (stderr, "\nCannot read file 'locations.dat' into memory!\n\n"); + exit (-1); + } + + close (locations_fd); +} + + + +save_location_data () + +{ + int locations_fd; + + long n, num_bytes; + + + /* Open file 'locations.dat' for writing. */ + locations_fd = creat ("locations.dat", 0600); + if (locations_fd < 0) + { + fprintf (stderr, "\n\tCannot create file 'locations.dat'!\n\n"); + exit (-1); + } + + if (num_locs == 0) + { + close (locations_fd); + return; + } + + /* Write array to disk. */ + num_bytes = (long) num_locs * (long) sizeof(struct sp_loc_data); + + n = write (locations_fd, loc, num_bytes); + if (n != num_bytes) + { + fprintf (stderr, "\n\n\tCannot write to 'locations.dat'!\n\n"); + exit (-1); + } + + close (locations_fd); +} + + + +/* The following routine provides the 'distorted' species number used to + identify a species that uses field distortion units. The input + variable 'species_number' is the same number used in filename + creation for the species. */ + +int distorted (species_number) + +int species_number; + +{ + int i, j, n, ls; + + + /* We must use the LS tech level at the start of the turn because + the distorted species number must be the same throughout the + turn, even if the tech level changes during production. */ + + ls = spec_data[species_number-1].init_tech_level[LS]; + + i = species_number & 0x000F; /* Lower four bits. */ + j = (species_number >> 4) & 0x000F; /* Upper four bits. */ + + n = (ls % 5 + 3) * (4 * i + j) + (ls % 11 + 7); + + return n; +} + +int undistorted (distorted_species_number) + +int distorted_species_number; + +{ + int i, species_number; + + + for (i = 0; i < MAX_SPECIES; i++) + { + species_number = i + 1; + + if (distorted (species_number) == distorted_species_number) + return species_number; + } + + return 0; /* Not a legitimate species. */ +} + + + +log_message (message_filename) + +char *message_filename; + +{ + char message_line[256]; + + FILE *message_file; + + + /* Open message file. */ + message_file = fopen (message_filename, "r"); + if (message_file == NULL) + { + fprintf (stderr, "\n\tWARNING! utils.c: cannot open message file '%s'!\n\n", message_filename); + return; + } + + /* Copy message to log file. */ + while (fgets(message_line, 256, message_file) != NULL) + fputs (message_line, log_file); + + fclose (message_file); +} + + + +/* This routine will set or clear the POPULATED bit for a nampla. It will + return TRUE if the nampla is populated or FALSE if not. It will also + check if a message associated with this planet should be logged. */ + +int check_population (nampla) + +struct nampla_data *nampla; + +{ + int is_now_populated, was_already_populated; + + long total_pop; + + char filename[32]; + + + if (nampla->status & POPULATED) + was_already_populated = TRUE; + else + was_already_populated = FALSE; + + total_pop = nampla->mi_base + + nampla->ma_base + + nampla->IUs_to_install + + nampla->AUs_to_install + + nampla->item_quantity[PD] + + nampla->item_quantity[CU] + + nampla->pop_units; + + if (total_pop > 0) + { + nampla->status |= POPULATED; + is_now_populated = TRUE; + } + else + { + nampla->status &= ~( POPULATED | MINING_COLONY + | RESORT_COLONY ); + is_now_populated = FALSE; + } + + if (is_now_populated && ! was_already_populated) + { + if (nampla->message) + { + /* There is a message that must be logged whenever this planet + becomes populated for the first time. */ + sprintf (filename, "message%ld.txt\0", nampla->message); + log_message (filename); + } + } + + return is_now_populated; +} + +/* Get life support tech level needed. */ + +int life_support_needed (species, home, colony) + +struct species_data *species; +struct planet_data *home, *colony; + +{ + int i, j, k, ls_needed; + + + i = colony->temperature_class - home->temperature_class; + if (i < 0) i = -i; + ls_needed = 3 * i; /* Temperature class. */ + + i = colony->pressure_class - home->pressure_class; + if (i < 0) i = -i; + ls_needed += 3 * i; /* Pressure class. */ + + /* Check gases. Assume required gas is NOT present. */ + ls_needed += 3; + for (j = 0; j < 4; j++) /* Check gases on planet. */ + { + if (colony->gas_percent[j] == 0) continue; + for (i = 0; i < 6; i++) /* Compare with poisonous gases. */ + { + if (species->poison_gas[i] == colony->gas[j]) + ls_needed += 3; + } + if (colony->gas[j] == species->required_gas) + { + if (colony->gas_percent[j] >= species->required_gas_min + && colony->gas_percent[j] <= species->required_gas_max) + ls_needed -= 3; + } + } + + return ls_needed; +} + + + +check_high_tech_items (tech, old_tech_level, new_tech_level) + +int tech, old_tech_level, new_tech_level; + +{ + int i; + + + for (i = 0; i < MAX_ITEMS; i++) + { + if (item_critical_tech[i] != tech) continue; + if (new_tech_level < item_tech_requirment[i]) continue; + if (old_tech_level >= item_tech_requirment[i]) continue; + + log_string (" You now have the technology to build "); + log_string (item_name[i]); + log_string ("s.\n"); + } + + /* Check for high tech abilities that are not associated with specific + items. */ + if (tech == MA && old_tech_level < 25 && new_tech_level >= 25) + log_string (" You now have the technology to do interspecies construction.\n"); +} + + + + +/* The following routine will return a score indicating how closely two + strings match. If the score is exactly 10000, then the strings are + identical. Otherwise, the value returned is the number of character + matches, allowing for accidental transpositions, insertions, and + deletions. Excess characters in either string will subtract from + the score. Thus, it's possible for a score to be negative. + + In general, if the strings are at least 7 characters each, then you can + assume the strings are the same if the highest score equals the length of + the correct string, length-1, or length-2, AND if the score of the next + best match is less than the highest score. A non-10000 score will never + be higher than the length of the correct string. */ + +int agrep_score (correct_string, unknown_string) + +char *correct_string, *unknown_string; + +{ + int score; + + char c1, c2, *p1, *p2; + + + if (strcmp (correct_string, unknown_string) == 0) return 10000; + + score = 0; + p1 = correct_string; + p2 = unknown_string; + + while (1) + { + if ((c1 = *p1++) == '\0') + { + score -= strlen (p2); /* Reduce score by excess characters, + if any. */ + break; + } + + if ((c2 = *p2++) == '\0') + { + score -= strlen (p1); /* Reduce score by excess characters, + if any. */ + break; + } + + if (c1 == c2) + ++score; + else if (c1 == *p2 && c2 == *p1) + { + /* Transposed. */ + score += 2; + ++p1; + ++p2; + } + else if (c1 == *p2) + { + /* Unneeded character. */ + ++score; + ++p2; + } + else if (c2 == *p1) + { + /* Missing character. */ + ++score; + ++p1; + } + } + + return score; +} + + +extern int num_stars, species_number, star_data_modified; +extern struct star_data *star_base; + + +/* The following routine will check if coordinates x-y-z contain a star and, + if so, will set the appropriate bit in the "visited_by" variable for the + star. If the star exists, TRUE will be returned; otherwise, FALSE will + be returned. */ + +int star_visited (x, y, z) + +int x, y, z; + +{ + int i, found, species_array_index, species_bit_number; + + long species_bit_mask; + + struct star_data *star; + + + /* Get array index and bit mask. */ + species_array_index = (species_number - 1) / 32; + species_bit_number = (species_number - 1) % 32; + species_bit_mask = 1 << species_bit_number; + + found = FALSE; + + for (i = 0; i < num_stars; i++) + { + star = star_base + i; + + if (x != star->x) continue; + if (y != star->y) continue; + if (z != star->z) continue; + + found = TRUE; + + /* Check if bit is already set. */ + if (star->visited_by[species_array_index] & species_bit_mask) break; + + /* Set the appropriate bit. */ + star->visited_by[species_array_index] |= species_bit_mask; + star_data_modified = TRUE; + break; + } + + return found; +} diff --git a/src/with_check.c b/src/with_check.c new file mode 100644 index 0000000..b5d4b35 --- /dev/null +++ b/src/with_check.c @@ -0,0 +1,147 @@ + + +#include "fh.h" +#include "combat.h" + + +extern int truncate_name, ignore_field_distorters; +extern char field_distorted[MAX_SPECIES]; +extern FILE *log_file, *summary_file; + + +withdrawal_check (bat, act) + +struct battle_data *bat; +struct action_data *act; + +{ + /* This routine will check all fighting ships and see if any wish to + withdraw. If so, it will set the ship's status to JUMPED_IN_COMBAT. + The actual jump will be handled by the Jump program. */ + + int i, old_trunc, ship_index, species_index, percent_loss, + num_ships_gone[MAX_SPECIES], num_ships_total[MAX_SPECIES]; + + char withdraw_age; + + struct ship_data *sh; + + + for (i = 0; i < MAX_SPECIES; i++) + { + num_ships_gone[i] = 0; + num_ships_total[i] = 0; + } + + old_trunc = truncate_name; /* Show age of ship here. */ + truncate_name = FALSE; + + /* Compile statistics and handle individual ships that must leave. */ + for (ship_index = 0; ship_index < act->num_units_fighting; ship_index++) + { + if (act->unit_type[ship_index] != SHIP) + continue; + + sh = (struct ship_data *) act->fighting_unit[ship_index]; + species_index = act->fighting_species_index[ship_index]; + ++num_ships_total[species_index]; + + if (sh->status == JUMPED_IN_COMBAT) /* Already withdrawn. */ + { + ++num_ships_gone[species_index]; + continue; + } + + if (sh->status == FORCED_JUMP) /* Forced to leave. */ + { + ++num_ships_gone[species_index]; + continue; + } + + if (sh->age > 49) /* Already destroyed. */ + { + ++num_ships_gone[species_index]; + continue; + } + + if (sh->type != FTL) continue; /* Ship can't jump. */ + + if (sh->class == TR) + { + withdraw_age = bat->transport_withdraw_age[species_index]; + if (withdraw_age == 0) continue; + /* Transports will withdraw only when entire fleet withdraws. */ + } + else + withdraw_age = bat->warship_withdraw_age[species_index]; + + if (sh->age > withdraw_age) + { + act->num_shots[ship_index] = 0; + act->shots_left[ship_index] = 0; + sh->pn = 0; + + ignore_field_distorters = ! field_distorted[species_index]; + + fprintf (log_file, " %s jumps away from the battle.\n", + ship_name (sh)); + fprintf (summary_file, " %s jumps away from the battle.\n", + ship_name (sh)); + + ignore_field_distorters = FALSE; + + sh->dest_x = bat->haven_x[species_index]; + sh->dest_y = bat->haven_y[species_index]; + sh->dest_z = bat->haven_z[species_index]; + + sh->status = JUMPED_IN_COMBAT; + + ++num_ships_gone[species_index]; + } + } + + /* Now check if a fleet has reached its limit. */ + for (ship_index = 0; ship_index < act->num_units_fighting; ship_index++) + { + if (act->unit_type[ship_index] != SHIP) + continue; + + sh = (struct ship_data *) act->fighting_unit[ship_index]; + species_index = act->fighting_species_index[ship_index]; + + if (sh->type != FTL) continue; /* Ship can't jump. */ + if (sh->status == JUMPED_IN_COMBAT) continue; /* Already withdrawn. */ + if (sh->status == FORCED_JUMP) continue; /* Already gone. */ + if (sh->age > 49) continue; /* Already destroyed. */ + + if (bat->fleet_withdraw_percentage[species_index] == 0) + percent_loss = 101; /* Always withdraw immediately. */ + else + percent_loss = (100 * num_ships_gone[species_index]) + / num_ships_total[species_index]; + + if (percent_loss > bat->fleet_withdraw_percentage[species_index]) + { + act->num_shots[ship_index] = 0; + act->shots_left[ship_index] = 0; + sh->pn = 0; + + ignore_field_distorters = ! field_distorted[species_index]; + + fprintf (log_file, " %s jumps away from the battle.\n", + ship_name (sh)); + fprintf (summary_file, " %s jumps away from the battle.\n", + ship_name (sh)); + + ignore_field_distorters = FALSE; + + sh->dest_x = bat->haven_x[species_index]; + sh->dest_y = bat->haven_y[species_index]; + sh->dest_z = bat->haven_z[species_index]; + + sh->status = JUMPED_IN_COMBAT; + } + } + + truncate_name = old_trunc; +} diff --git a/svn-commit.tmp b/svn-commit.tmp new file mode 100644 index 0000000..d1f33a6 --- /dev/null +++ b/svn-commit.tmp @@ -0,0 +1,5 @@ +initial import + +--This line, and those below, will be ignored-- + +A .