pax_global_header00006660000000000000000000000064147606172540014526gustar00rootroot0000000000000052 comment=1e14fd54f082868c98a3c71292e9c109c360a7d2 1oom-1.11.2/000077500000000000000000000000001476061725400124635ustar00rootroot000000000000001oom-1.11.2/.gitignore000066400000000000000000000003141476061725400144510ustar00rootroot00000000000000*.[oa] .a*.out .deps/ Makefile Makefile.in config.log config.status configure aclocal.m4 autom4te.cache/ build-*/ src/config.h* src/version.inc stamp-h1 src/1oom* localtest/ *.lbx 1oom-*.tar* 1oom-*.zip 1oom-1.11.2/AUTHORS000066400000000000000000000003411476061725400135310ustar00rootroot00000000000000Kilgore Trout Mask Replicant Tapani Max Fillinger Ignatius Zachary KLine Duzh 54 1oom-1.11.2/CHANGES000066400000000000000000000157661476061725400134750ustar00rootroot000000000000001oom-v1.11.2 ------------ This release corrects several fundamental differences from the original: - The behavior of ships with bio-weapons has been restored - The code responsible for landing troops on a planet with zero population has been restored - Restored original bugs in the pathfinding code on the battlefield - Fixed the location of rocks near the planet - Restored the sound effect of the Ships button on the star map - Several AI diplomacy fixes moved to Classic+ 1oom-v1.11.1 ------------ This release contains a significant number of experimental features: - Added several global research cost modifiers - Main menu slightly sorted - First tech cost fix (Classic+ AI) is now a separate rule - Added the ability to lock the slider for all colonies of the same type - Added some fixes for slider_respect_locks rule (still experimental) - The distance hint has been replaced with a new Alt+o mode - Added the ability to rename planets and ship designs - Smoother scrolling of the star map is now optional - Added experimental ability to load saves from MOO 1.3 - Added some minor corrections 1oom-v1.11 ---------- This release is almost completely identical to v1.10.6: - lbxview: Fixed window update - All 4 pages of the video buffer are now allocated as a solid piece of memory similar to the original, but this version has no padding, which may lead to rare, subtle graphic artifacts (will be fixed in future releases) - Reverted one cumbersome fix related to video buffer overflow - Some hidden AI fixes moved to Classic+ AI - The Git tree has been cleaned and refined to make future changes easier 1oom-v1.10.6 ------------ - Fixed a critical issue in Classic+ AI 1oom-v1.10.5 ------------ - Planets UI: Added max population column as in 1.7.6 - AI: 4th colony curse fix is now a separate rule - AI: Doom stack fix is now a separate rule and disabled by default 1oom-v1.10.4 ------------ This release adds the ability to change sliders for all colonies at once in one click: - Added dialog box code - Holding the Ctrl key while locking a colony slider allows you to lock sliders for all colonies at once - Holding the Alt or Ctrl key while clicking on the frame with the slider value text allows you to adjust sliders for all colonies at once - Most smart slider manipulations now depend on the slider_respects_locks rule, with the exception of the new technologies UI 1oom-v1.10.3 ------------ This release is a general cleanup and improvement to the game_update_eco_on_waste code: - The old implementation of waste_adjust_fix has been replaced with a simpler and clearer one, based on the original code - Added slider_respects_locks rule, which prevents the functions above from changing locked sliders The changes above are in preparation for the introduction of more extensive game controls. Bug reports are welcome. 1oom-v1.10.2 ------------ - Added challenge mode (special difficulty map) - Improved distance indicator 1oom-v1.10.1 ------------ - Pressing g on the battlefield screen shows the grid 1oom-v1.10.0 ------------ This release is the second interim release since v1.8.1, the goal of which is to clean the code as much as possible from additions that cause a large number of errors or are outdated. List of positive changes: - the RNG is non-deterministic by default - implemented Improved Robotic Controls behavior close to OSG - F4/F5 now cycles through enemy fleets, like in v1.7.6 - Eco slider can show "MAX", like in v1.7.6 - the map on the Map screen is now clickable - added several vanilla rules that were "fixed" in v1.0 - more hidden rules from v1.0 have been added to the menu - some smart features have been added/moved to cheats - simplified implementation of the message filter List of removed features after f1.8.1: - governor - extra menu (bottom-left corner) - (Ctrl-)1-9 to tag/recall planet - screenshot - Game screen options overhaul - X11 HW (unfinished) Many simple changes of the same type or rollbacks of erroneous changes have been grouped to simplify work with the history. Some fixes have been confirmed by reverse engineering and are now explicitly marked as 1oom typo fixes. Bug reports and suggestions are welcome. 1oom-v1.9 --------- This release by default uses the original rules of the game as much as 1oom v1.0 allowed and even better. Summary: - Fixed several cosmetic differences - Fixed broken rebellions - Rules settings menu options have been improved - The bug that causes AI to build an obscenely large fleet is now a separate rule - Added a few minor interface features - Removed several minor 1oom interface features that were outdated, conflicted, or interfered with the development of the project - A significant amount of useless 1oom code has been removed Bug reports are welcome. 1oom-f1.8.1 ----------- This release is special. For the first time since the release of v1.0, a large number of corrections have been verified with the original. In addition, some fundamental new improvements have been made. Summary: - Classic AI is now competitive and selected by default - Restored vanilla Tutor map - Random number generator changed to vanilla - Fixed the chances of rich/poor planets when creating a galaxy - Fixed autoretreat behavior - The vanilla copy protection dialog has been restored - Added optional fix for scanners on ships - Fixed numerous visual differences from vanilla - Fixed several minor bugs The main goal of the project is now explicitly stated on the main page. Bug reports are welcome. 1oom-fork-v1.8.0 ---------------- Disclaimer: This release is an interim release. I'm posting this to give people the opportunity to enjoy a relatively high quality build that still contains many bugs inherited from v1.0. Previous 1oom-fork versions are now considered defective. It is recommended to close the old version of 1oom-fork and delete config file if you want to run this version. Saved games from an older version of 1oom-fork may not work or refuse to load if you try them from this version. This (v1.8.0) version of fork does not change save game format compared to the point when it's forked from Tapani-fork (9b9cf63...) This version of fork is based on reworked version of Tapani-fork mixed with reworked and filtered version of 1oom-fork-v1.7.6 (1oom-v1.0-rev-5) The commit history is now can be used as detailed changelog Summary: - most of the 1oom-fork commits were rewritten from scratch with improvements - removed or rewrote most of the later commits from the Tapani branch, with special attention to those that added bugs or problems for developers - it is now possible to use absolute mouse in DOSBox on Andriod by enabling absolute mouse in both the game and DOSBox configurations - most rule bug fixes is enabled and can only be disabled via PBX - added UI Presets This is not a complete list of changes Bug reports are welcome 1oom-fork-v1.7.6 ---------------- The list of changes for this version of the fork is irrelevant, since subsequent versions reject or modify most of the changes in order to improve the quality of the project and its compliance with the original. 1oom-1.11.2/COMPILING000066400000000000000000000175221476061725400137360ustar00rootroot00000000000000######## # 1oom # ######## 1. Options =========== The configuration options: --enable-static enable static builds (experimental) --enable-modebug add debugging options --without-readline do not try to use the readline library (used by 1oom_cmdline) --without-samplerate do not try to use libsamplerate --disable-tools disables extra tools (do not build 1oom_pbxmake, 1oom_gfxconv, ...) --disable-uiclassic disables classic UI (do not build 1oom_classic_*) --disable-uicmdline disables cmdline UI (do not build 1oom_cmdline) --disable-hwsdl1 disables SDL1 HW (do not build 1oom_*_sdl1) --disable-hwsdl1audio disables SDL1 HW audio support (no audio for 1oom_*_sdl1) --disable-hwsdl1gl disables SDL1 HW OpenGL support (no graphics resizing for 1oom_*_sdl1) --disable-hwsdl2 disables SDL2 HW (do not build 1oom_*_sdl2) --disable-hwsdl2audio disables SDL2 HW audio support (no audio for 1oom_*_sdl2) --disable-hwalleg4 disables Allegro 4 HW (do not build 1oom_*_alleg4) Parameters for configure: CFLAGS SDL1_CFLAGS SDL1_LIBS SDL1MIXER_LIBS SDL2_CFLAGS SDL2_LIBS SDL2MIXER_LIBS 2. Preparing build tools ========================= You'll need autotools, make and a C99 compiler. You will most likely also want to have SDL development libraries. Both SDL 1.2.x and SDL2.x are supported. OpenGL libraries are highly recommended. 2.1. Compiling on Linux =============================== If you want to use SDL1: aptitude install libsdl1.2-dev libsdl-mixer1.2-dev If you prefer SDL2: aptitude install libsdl2-dev libsdl2-mixer-dev For better audio quality, also get libsamplerate. aptitude install libsamplerate-dev For custom sound fonts support: aptitude install libfluidsynth-dev You are now ready to configure and build 1oom as described in Section 3. 2.2. Compiling on Windows ========================== To compile 1oom, you need a GNU build environment. 2.2.1. Compiling with MinGW ---------------------------- Note: This method is deprecated. Follow 2.2.2 if you want FluidSynth support. Download and install mingw-get-setup.exe from: https://osdn.net/projects/mingw/releases/ This will install a graphical package manager. Ensure that you have the latest autoconf, automake and make versions available and also MSYS. Download the SDL2 development libarary for MinGW from: https://github.com/libsdl-org/SDL/releases Download the SDL2 mixer development library for MinGW from: https://github.com/libsdl-org/SDL_mixer/releases Then unzip the two archives you downloaded. Then, run: C:\MinGW\msys\1.0\msys.bat which gives you a UNIX-style command prompt with the correct PATHs already configured. Then, go to the directory where you extracted SDL2 and enter: make native Do the same for SDL2 Mixer. You are now ready to configure and build 1oom as described in Section 3. When running configure, pass the following options: ../configure --disable-hwsdl1 --disable-hwalleg4 To run 1oom, place the *32-bit* versions of SDL2.dll and SDL2_mixer.dll in the same directory as the binary. 2.2.2. Compiling with MSYS2 ---------------------------- https://kilgoretroutmaskreplicant.gitlab.io/plain-html/howto_build_windows.html For Windows 7, you can download the old version of MSYS2 here: https://github.com/msys2/msys2-installer/releases/tag/2022-10-28 Note: Add the --enable-static flag for static build when you run ./configure. To run 1oom with FluidSynth support, before building you need to install the appropriate fluidsynth package in MSYS2 and copy the fluidsynth DLLs to same directory as 1oom binary (even for static build). 3. Compiling 1oom ================== The following needs to be run from the 1oom folder. If you checked this out with git, do this first: autoreconf -fi Make a build directory: mkdir build-native cd build-native Then the usual: ../configure make -j 3 !!! You need the data files from the original Master of Orion to run 1oom. !!! Actual install step is not needed: src/1oom_classic_sdl1 -data /path/to/moo src/1oom_classic_sdl2 -data /path/to/moo 4. Cross-compiling =================== Something like this may work: mkdir build-win32d cd build-win32d ../configure --host=i686-w64-mingw32.shared If the libraries are not found, try something like: ../configure --host=i686-w64-mingw32.shared SDL1_CFLAGS="`i686-w64-mingw32.shared-sdl-config --cflags`" \ SDL1_LIBS="`i686-w64-mingw32.shared-sdl-config --libs`" \ SDL1MIXER_LIBS="`i686-w64-mingw32.shared-pkg-config --libs SDL_mixer`" \ SDL2_CFLAGS="`i686-w64-mingw32.shared-sdl2-config --cflags`" \ SDL2_LIBS="`i686-w64-mingw32.shared-sdl2-config --libs`" \ SDL2MIXER_LIBS="`i686-w64-mingw32.shared-pkg-config --libs SDL2_mixer`" Good luck! 4.1. Unix to win32 =================== This is a quick guide to make a cross compiler based on MXE: http://mxe.cc/ First we build MXE: git clone https://github.com/mxe/mxe.git cd mxe make MXE_TARGETS='i686-w64-mingw32.shared' gcc sdl sdl_mixer sdl2 sdl2_mixer libsamplerate readline (or i686-w64-mingw32.static if you want static binaries, or maybe both) Edit your .bashrc, .profile or equivalent and add/edit: export PATH="/MXE_path/usr/bin:$PATH" (If you are unsure of the MXE_path, run pwd.) Run the export line on the current terminal to set the PATH for this session. Now to cross compile 1oom: cd ~/path/to/1oom mkdir build-win32d cd build-win32d ../configure --host=i686-w64-mingw32.shared && make -j 3 If you want to make distributable packages of .shared compiles: mkdir extrabindist_win32 cp /MXE_path/usr/i686-w64-mingw32.shared/bin/{SDL*,libgcc_s_sjlj-1.dll,libsamplerate.dll} extrabindist_win32 (the list may be incomplete; run the EXEs in wine and see the error messages) 4.2. Unix to msdos =================== This is a quick guide to cross compile a MSDOS binary. First get a cross compiler: git clone https://github.com/andrewwutw/build-djgpp.git ... (or just grab a prebuilt one from the GitHub page) Edit your .bashrc, .profile or equivalent and add/edit: export PATH="/djgpp_path/bin:$PATH" Run the export line on the current terminal to set the PATH for this session. Get allegro-4.2.3.1.tar.gz from http://liballeg.org/ tar xaf allegro-4.2.3.1.tar.gz cd allegro-4.2.3.1 "Fix" it for djgpp: ./fix.sh djgpp Apply patches: patch -p1 < /path/to/1oom/doc/ext/allegro-4.2.3.1-p1-modern-xmake.patch patch -p1 < /path/to/1oom/doc/ext/allegro-4.2.3.1-p2-remove-mouse-cursor.patch patch -p1 < /path/to/1oom/doc/ext/allegro-4.2.3.1-p3-disable-unused.patch Edit xmake.sh and check that the paths and compiler name are correct. ./xmake.sh Copy the header files to the cross compiler: cp -r include/* /opt/djgpp/i586-pc-msdosdjgpp/include Copy the library file to the cross compiler: cp lib/djgpp/lib*a /opt/djgpp/i586-pc-msdosdjgpp/lib Now to cross compile 1oom: cd ~/path/to/1oom mkdir build-msdos cd build-msdos ../configure --host=i586-pc-msdosdjgpp && make -j 3 5. Building distributable packages =================================== Build a tarball requiring no Autotools: make dist Some OS targets support building binary distributions. The bindist scripts use git for version information if .git/ exists, otherwise the version is "vUnknown". Files from extrabindist_common/ and extrabindist_$OS/ are copied to the distribution. Build a binary distribution: make -j 3 && make bindist Build a binary distribution zip: make -j 3 && make bindistzip 1oom-1.11.2/COPYING000066400000000000000000000431621476061725400135240ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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. 1oom-1.11.2/HACKING000066400000000000000000000115101476061725400134500ustar00rootroot00000000000000# Coding style guidelines ## Structure The code is divided into the following directories: * src/ - utility functions, tools * game/ - game logic * ui/ - UI implementations * classic/ - the 1993 UI * cmdline/ - experimental command line UI * nop/ - dummy UI for tools * hw/ - hardware abstraction * sdl/ - libSDL * 1/ - libSDL 1.2.x * 2/ - libSDL 2.x * alleg/ - Allegro * 4/ - Allegro 4.x * nop/ - dummy HW for tools * os/ - Operating System; file paths * unix/ - yay * win32/ - boo * msdos/ - wtf Some facts: * main is in hw/ (due to SDL) * os/ knows nothing about game/, ui/ or hw/ * hw/ knows nothing about game/ or ui/ * game/ knows nothing about hw/ * ui/ is known via src/ui.h * hw/ is known via src/hw.h * os/ is known via src/os.h * src/ knows game via the very narrow src/gameapi.h (the exception is saveconv.c) * ui/ knows all about game/ Different hw/ and ui/ implementations can be built with a single configure. The resulting binaries follow a "1oom_$UI_$HW" naming convention. ## Style - no tabs, 4 spaces for indentation - always add the { } braces to if, do, while, for statements - one space after a ',', if, do, while, for and return statements, no space after function name: if (func(4, 5) < 0) { return (foo * 4) + 2; } - add spaces around +, -, *, /, =, == etc: a = (22 + b * 4) / 7; - have the opening brace on the same line as the statement, unless the condition spills to multiple lines: if (foo) { ... } if (1 && really_long_name && (function_call(with_parameters) < and_a_comparison) ) { ... } - have the opening brace of a function in the next line: int func(void) { ... } - use C-style comments /* like here */ - function and variable names are lowercase with '_' for space - defines and enums are UPPERCASE with '_' for space - avoid global variables - declare functions / data which are not used outside the module as static - group static functions / data above others, separate with a /* --.. */ line - avoid memory allocations after game startup Do not use unsafe string functions like strcpy, strcat and sprintf. 1oom pbx files may redefine most in-game strings, and besides, it's good practice. There are replacement functions in src/lib.c which take an additional buffer size argument and crash instead of overflowing the buffer. Avoid declaring variables after the start of scope: if (foo) { int this_is_ok; v = 123; int this_is_frowned_upon; ... } Note that declaring the loop variable inside for is ok: for (int i = 0; i < FOO; ++i) { ... } Otherwise, try to keep close to C89. Avoid #ifdefs! No OS-specific #ifdefs are allowed in game/, ui/ or src/. Acceptable ones include HAVE_SAMPLERATE etc and FEATURE_MODEBUG. ## On brevity Comment only the unobvious or the big picture. Do not add inane comments like: /* do stuff */ do_stuff(); Keep the commit message as one line of 70 characters or less. Do not end it with a '.'. Save any explanatory paragraphs for the merge request. Don't try to remove code that you don't think makes sense. It always has value if it strictly matches the original. ## Portability 1oom is designed to be cross-platform and work on different Operating Systems, processors and libraries. Bear this in mind when writing code. Each hardware abstraction library will have its own directory in hw/. Any and all of these must be buildable with one configure and produce differently named binaries. Do not use the `long` type (its size differs across platforms; use `int` or `int64_t` depending on which you want). Be careful with platform dependencies: do not use Windows API functions outside os/win32/, for example. Do not use SDL outside of hw/sdl/. Tests for OS in configure.ac and use for example `IS_WINDOWS` instead of the preprocessor `_WIN32`. The #defines can be used to identify the OS if necessary. Try to avoid this if possible. Only consider them in hw/ or os/. Hey, you there, OS X porter! Do not turn os/unix/ into an #ifdef shithole, just copy it to os/osx/ and hack away. Be careful of endianness! The the macros in bits.h to do endianness conversion. Never assume that integer types have a particular byte ordering. Similarly, never assume that fields inside a structure are aligned in a particular way. This is most relevant when reading or writing data to a file or a network pipe. For signed integers, you shouldn’t assume that `(i >> n)` is the same as `(i / (1 << n))`. However, most processors handle bitshifts of signed integers properly, so it’s not a huge problem. ## GNU GPL and licensing All code submitted to the project must be licensed under the GNU GPLv2 or a compatible license. 1oom-1.11.2/MIRRORS000066400000000000000000000000421476061725400135370ustar00rootroot00000000000000https://gitlab.com/1oom-fork/1oom 1oom-1.11.2/Makefile.am000066400000000000000000000005401476061725400145160ustar00rootroot00000000000000SUBDIRS = src DIST_SUBDIRS = doc src bindist: $(SHELL) @BINDIST_SCRIPT@ $(STRIP) $(top_srcdir) nozip bindistzip: $(SHELL) @BINDIST_SCRIPT@ $(STRIP) $(top_srcdir) zip EXTRA_DIST = \ AUTHORS COPYING HACKING COMPILING NEWS PHILOSOPHY README.md \ make-bindist_install.sh \ make-bindist_msdos.sh \ make-bindist_win32.sh \ .gitignore 1oom-1.11.2/NEWS000066400000000000000000000103451476061725400131650ustar00rootroot000000000000002018-11-14: v1.0 released, project finished - quit brings back to main menu - clicking on the Tech screen lights sets the slider to bonus limit - a handful of bugs fixed 2018-10-03: v0.9 released - map scroll speed is adjustable - Planets and Fleet screen lists sortable by name/count/bases/etc - keys! * UHJK scroll the map * / to search for a planet by name * space bar for Continue/dismiss/OK/etc * 1-5 as portrait click on Races - almost 20 bugs fixed, notably: * a cause for the infamous 32000 doom stacks indentified and fixed * AI scrapped wrong ship designs resulting in obsolete fleets * AI II armor bias fixed, resulting in overall better ship designs * all but a few of the 1.40m fixes are now implemented - doc/pbxin_fixbugs.txt expanded, including fix for waste calculation 2018-09-06: MOO turns 25, v0.8 released - click again to accept for transport redirection - all Advanced Technology are available for research - multiplayer player switching reduced - fix several music bugs - fix ship visibility during movement - fix ship scanner range - a handful of small fixes 2018-08-17: v0.7 released - game is deterministic by default - new -yearsave option for yearly saves (1oom_save_YYYY.bin) - new -uiextra UI features: * 1.40m-like research bonus lights - about 30 bugs fixed, notably: * many memory corruption crashes fixed (C is fun) * ETA is now correct * spy cost in Races screen matches actual costs - doc/pbxin_fixbugs.txt expanded, including fix for Oracle Interface 2018-07-29: v0.6 released - fix mouse handling on large resolutions, replace -mousediv with -mousespd - extend mouse wheel support for counts, add options for inverting - clicking cycles selection of overlapping fleets/transports - new -uiextra UI features, notably: * space combat autoresolve for skipping uninteresting battles * partial fleet send does not deselect fleet * click destination again to Accept - less than 100 bugs fixed, notably: * AI expansion was hindered by several bugs * space combat had issues * fixed a few crashes - doc/pbxin_fixbugs.txt expanded, including fixed starting ship costs - cmdline UI is now complete - 1oom_lbxedit (which you should ignore and use 1oom_pbxmake instead) 2018-07-01: v0.5 released - support mouse wheel for lists, sliders and zooming - add -uiextra for enabling extra UI features, notably: * new New Game screen with opponent selection (including AI/player) - SDL: support 15/16/24 bpp - added documentation on differences to v1.3 - some improvements from the unofficial patch v1.40m have been implemented - add Classic+ AI with small fixes, some from v1.40m - about 100 bugs fixed, notably: * the AI should now provide a worthy challenge * space combat works as it should * fixed many crashes - added doc/pbxin_fixbugs.txt for optional bug fixes - last and least: the "No Events" text overlay is implemented 2018-06-05: v0.4 released - add -uiscale N for viewing more of the galaxy at once - local multiplayer is ready for testing (use -new to start) - 1oom_pbxdump as the counterpart to 1oom_pbxmake - bug genocide marches on, notably: - AI fleets disappearing when sent fixed - AI ship design phase can no longer hang - MSDOS port should not crash at the slightest provocation 2018-05-19: v0.3 released - new HW libraries: SDL2 and Allegro 4 - new OS: MSDOS - win32 version now actually compiles - numerous bugs fixed - a log file is written by default - cmdline UI has emerged but is not fully playable yet - pkg-config support added for easier compiling - saveconv supports text input for debugging 2018-04-30: v0.2 released - help dialogs and news transition implemented; all done!? - configuration files implemented - add -user - documentation added - full screen toggling with Alt-Enter - 1oom_gfxconv for converting graphics to LBX format - various bugs fixed 2018-04-10: v0.1 released - first public alpha release 2017-11-16: project start 1oom-1.11.2/PHILOSOPHY000066400000000000000000000076611476061725400141160ustar00rootroot00000000000000(Much of this text is stolen/edited from Chocolate Doom.) 1oom has been designed around a careful and deliberate philosophy that attempts to recreate the original (“Vanilla”) DOS executables for Master of Orion. This document describes some of that philosophy and the reasoning behind it. This document is descriptive, not proscriptive. # Vanilla behavior Ideally 1oom aims to recreate the behavior of the Vanilla binaries, but different aspects of Vanilla behavior are held to varying degrees of importance. It can be imagined as different “tiers” of compatibility: * The game and gameplay itself is of central importance. Here, the Vanilla behavior ought to be maintained as accurately as possible. This includes the look, feel and sound. * The surrounding aspects of the game that aren’t part of the central gameplay experience can be extended as long as there’s a good reason and Vanilla behavior is respected. “Vanilla” is defined as: * Master of Orion v1.3. Compatibility with older versions of the DOS binaries is out of scope. # Compatibility 1oom aims to be compatible with Vanilla MOO1 in several different ways. Examples are: * Data file compatibility: the original data files (LBX) are used. No additional data files are required or provided. * Bug compatibility: the aim is to emulate compatibility of the original game down to bugs that were present in the DOS executables. Most bugs are fixed, but the AI behaviour is maintained as closely as possible. * Savegame file compatibility: 1oom provides a tool to convert savegames to/from Vanilla format. # Exceptions 1oom differs from Vanilla MOO1 in a number of ways. Here are some examples of situations where changes are considered acceptable: 1. Vanilla behavior can be broken that is harmful, eg. can damage the player’s computer, or is just outright misleading. For example: - Vanilla has crashes that force the user to reboot the machine. 2. Supporting obsolete technology is not a goal: it’s considered acceptable that 1oom does not support every type of hardware from 1993. However, 1oom should aim to recreate the functionality in a modern way. Examples of technologies that aren’t supported are: - No 286 version. 3. Fixes from the unofficial patch 1.40m which do not alter the Vanilla behaviour much may be included unconditionally. Examples: - Psilon leader "Zygot " name correction. A good litmus test of when it’s acceptable to break from Vanilla behavior is to ask the question: “Although this is Vanilla behavior, is there anyone who would want this?” # New features While 1oom recreates the Vanilla behaviour, it also extends it: * The "classic" UI (1oom_classic_*) will always remain reasonably close to the one in the DOS binaries, but alternative UIs are within the scope. The UI can be scaled to allow the player to see more of the galaxy at once. New/improved UI features are documented and enabled using appropriate flags in the configuration file. * The "Classic" AI will always remain reasonably close to the one in the DOS binaries, but alternative AIs are within the scope. * The "Classic+" AI will always remain somewhat close to the one in the DOS binaries, but includes small fixes (some from the unofficial patch). * Doom-like file patching is supported via PBX files. PBX files can be used for enabling fixes for Vanilla bugs. * Multiplayer! (only local for now) # Other philosophical aspects 1oom aims for maximal portability. That includes running on many different CPUs, different operating systems and different devices (ie. not just a desktop machine with a keyboard and mouse). 1oom does not need to be installed. The only required data files are the LBX files from the original game. The other data files are the savegame, configuration and log files. 1oom is and will always remain Free Software. It will never include code that is not compatible with the GNU GPL. 1oom-1.11.2/README.md000066400000000000000000000076231476061725400137520ustar00rootroot000000000000001oom ==== 1oom aims to accurately reproduce the original DOS version of Master of Orion (1993) in a form that can be run on modern computers. 1oom is Free Software (GPLv2), see [COPYING](COPYING). 1 Installation =============== 1oom requires a copy of the Master of Orion (v1.3) LBX files. Please note that older saved games may not work in newer versions of 1oom. Read the [changelog](CHANGES) to learn more about the breaking changes. 1.1 Windows, MSDOS ------------------ Simply extract the desired [release](https://github.com/1oom-fork/1oom/releases) to your MOO1 directory. Alternatively copy your MOO1 LBX files (and saved games if needed) to your 1oom directory. See [usage_common](doc/usage_common.txt) if you prefer to use a separate directory. 1.2 Unix (Linux) ---------------- 1oom requires the following libraries: - SDL (libsdl1.2 or libsdl2): http://www.libsdl.org - SDL_mixer (libsdl-mixer1.2 or libsdl2-mixer): http://www.libsdl.org/projects/SDL_mixer/ Also recommended: - libsamplerate: http://www.mega-nerd.com/libsamplerate/ Check your distribution's package manager or the library website on how to install them. 1.3 Android (DOSBox) -------------------- To play on Android you will need the 1oom executable for MSDOS, DOSBox application for Android and DPMI extension, for example CWSDPMI. You can build the 1oom executable for MSDOS using i586 DJGPP and Allegro4. 2 Configuration =============== See [usage_common](doc/usage_common.txt). 3 Development ============= See [COMPILING](COMPILING) and [HACKING](HACKING) for more information. 4 Executables ============= 1oom consists of a few executables: - [1oom_classic_*](doc/usage_classic.txt) (the 1993 UI) - [1oom_cmdline](doc/usage_cmdline.txt) (proof of concept textual UI) - [1oom_lbxview_*](doc/usage_lbxview.txt) (for viewing LBX files) - [1oom_lbxedit](doc/usage_lbxedit.txt) (for editing LBX files) - [1oom_pbxmake](doc/usage_pbxmake.txt) (for creating PBX files) - [1oom_pbxdump](doc/usage_pbxdump.txt) (for dumping PBX files) - [1oom_gfxconv](doc/usage_gfxconv.txt) (for converting GFX for use in PBX files) - [1oom_saveconv](doc/usage_saveconv.txt) (for converting save game files) - 1oom_*_sdl1 (using SDL 1.2.x) - 1oom_*_sdl2 (using SDL 2.x) - 1oom_*_alleg4 (using Allegro 4.x) See [usage_common](doc/usage_common.txt) for common documentation. Some ports have shorter filenames due to filesystem limitations. 5 Abbreviations =============== The following abbreviations appear in the documentation and code: - MOO1: Master of Orion 1 as represented by the v1.3 DOS binaries - OSG: The Official Strategy Guide (ISBN 1-55958-507-2) 6 Acknowledgements ================== Most of the credit for this software belongs to the progammer who authored [1oom v1.0](https://kilgoretroutmaskreplicant.gitlab.io/plain-html) under the pseudonym Kilgore Trout Mask Replicant. Thank you for creating this and publishing it free and open source! The original game Master of Orion was developed by Simtex Software and published 1993 by MicroProse. Thanks for the great game! Thanks to Alan Emrich and Tom Hughes for documenting the game mechanics and AI decision making in great detail in the official strategy guide. Ideas and text snippets have been taken from kyrub's unofficial patch 1.40m Readme. Thanks for the patch! Thanks to [shikadi.net](http://www.shikadi.net) for documenting the [music format](http://www.shikadi.net/wiki/modding/index.php?title=XMI_Format&oldid=6874). Thanks to CivFanatics forum user sargon0 for [partial save game format info](http://forums.civfanatics.com/threads/moo-save-file-layout.275055/). Special thanks to Zachary Kline (BlindGuyNW) for improving the text version of the game. Thanks to those who contributed code, ideas or bug reports. Some code has been pilfered from Chocolate Doom and VICE. The files [HACKING](HACKING) and [PHILOSOPHY](PHILOSOPHY) are based on Chocolate Doom. 1oom-1.11.2/configure.ac000066400000000000000000000520531476061725400147560ustar00rootroot00000000000000AC_INIT([1oom], [1.11.2]) VERSION_1OOM=v1.11.2 AC_ARG_ENABLE(static, AS_HELP_STRING([--enable-static], [enable static builds])) AC_ARG_ENABLE(modebug, AS_HELP_STRING([--enable-modebug], [add debugging options])) AC_ARG_WITH(readline, AS_HELP_STRING([--without-readline], [do not try to use the readline library])) AC_ARG_WITH(samplerate, AS_HELP_STRING([--without-samplerate], [do not try to use libsamplerate])) AC_ARG_ENABLE(tools, AS_HELP_STRING([--disable-tools], [disables extra tools])) AC_ARG_ENABLE(uiclassic, AS_HELP_STRING([--disable-uiclassic], [disables classic UI])) AC_ARG_ENABLE(uicmdline, AS_HELP_STRING([--disable-uicmdline], [disables cmdline UI])) AC_ARG_ENABLE(hwsdl1, AS_HELP_STRING([--disable-hwsdl1], [disables SDL1 HW])) AC_ARG_ENABLE(hwsdl1audio, AS_HELP_STRING([--disable-hwsdl1audio], [disables SDL1 HW audio support])) AC_ARG_ENABLE(hwsdl1gl, AS_HELP_STRING([--disable-hwsdl1gl], [disables SDL1 HW OpenGL support])) AC_ARG_ENABLE(hwsdl2, AS_HELP_STRING([--disable-hwsdl2], [disables SDL2 HW])) AC_ARG_ENABLE(hwsdl2audio, AS_HELP_STRING([--disable-hwsdl2audio], [disables SDL2 HW audio support])) AC_ARG_ENABLE(hwalleg4, AS_HELP_STRING([--disable-hwalleg4], [disables Allegro 4 HW])) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wall foreign]) AM_SILENT_RULES AC_CANONICAL_HOST user_cflags=$CFLAGS AC_PROG_CC_C99 AC_PROG_CPP m4_ifdef([AM_PROG_AR], [AM_PROG_AR]) AC_CHECK_TOOL(RANLIB, ranlib, :) AC_CHECK_TOOL(STRIP, strip, :) AC_CHECK_PROG(GIT, git, git, :) AC_PROG_INSTALL AC_C_BIGENDIAN if test -z "$user_cflags" ; then dnl Check for the type of compiler first. if test x"$GCC" = "xyes" ; then warnings_c="-Wall -std=c99 -pedantic -Wno-inline -Wstrict-prototypes -Wshadow=local" dnl Set appropriate optimization options (better than the default -g -O) dnl if using GCC. dnl If the user has specified her own `CFLAGS', we do not override them. optimization_c="-O3" dnl Use -g if available. if test x"$ac_cv_prog_cc_g" = "xyes" ; then CFLAGS="-g $optimization_c $warnings_c" else CFLAGS="$optimization_c $warnings_c" fi fi dnl (If not on GCC, just keep the defaults, which are very conservative). fi dnl Check whether the options are OK. AC_PROG_CC_C99 dnl - check common stuff AC_CHECK_HEADERS(inttypes.h stdbool.h) AC_CHECK_FUNCS(atexit strcasecmp) dnl - git version USE_GIT="no" if test x"$GIT" != "x"; then gitversion=`$GIT -C $srcdir describe --tags` if test x"$gitversion" != "x"; then USE_GIT=$GIT fi fi AC_SUBST(USE_GIT) dnl - OS detection dnl - check for win32 headers AC_CHECK_HEADERS([wtypes.h winnt.h], [is_win32=yes; AC_DEFINE(IS_WINDOWS,, [Compiling for Windows])], [is_win32=no], [[#ifdef HAVE_WTYPES_H #include #endif #ifdef HAVE_WINNT_H #include #endif ]]) dnl - check for msdos if test x"$host_vendor" = "xgo32" -o x"$host_vendor" = "xmsdos" -o x"$host_os" = "xmsdosdjgpp"; then AC_DEFINE(IS_MSDOS,, [Compiling for MSDOS]) is_msdos=yes else is_msdos=false fi dnl - optional features if test x"$enable_static" = "xyes"; then LDFLAGS="$LDFLAGS -static" fi if test x"$enable_modebug" = "xyes"; then AC_DEFINE(FEATURE_MODEBUG,,[Add debugging options.]) fi dnl - check for pkg-config dnl The failing result is "false" for $pkg_config --exists foo to fail. AC_CHECK_TOOLS(pkg_config, pkg-config, false) dnl - readline dnl Check whether we have GNU readline. dnl The user can force us to not use it with `--without-readline'. READLINE="" READLINE_LIBS= if test x"$with_readline" != "xno"; then unset ac_cv_lib_readline_readline old_LIBS="$LIBS" AC_CHECK_LIB(readline, readline, [ READLINE="" READLINE_LIBS="-lreadline"], [],,) if test "$ac_cv_lib_readline_readline" = "no"; then unset ac_cv_lib_readline_readline AC_CHECK_LIB(readline, readline, [ READLINE="" READLINE_LIBS="-lreadline -ltermcap"], [], [-ltermcap],) fi if test "$ac_cv_lib_readline_readline" = "no"; then unset ac_cv_lib_readline_readline AC_CHECK_LIB(readline, readline, [ READLINE="" READLINE_LIBS="-lreadline -lncurses"], [], [-lncurses],) fi if test "$ac_cv_lib_readline_readline" = "yes"; then AC_CHECK_HEADERS(readline/readline.h, [AC_DEFINE(HAVE_READLINE,, [readline available])]) AC_CHECK_LIB(readline, rl_readline_name, [ AC_DEFINE(HAVE_RLNAME,, [Does the `readline' library support `rl_readline_name'?]) ],,) fi LIBS="${old_LIBS}" fi AC_SUBST(READLINE) AC_SUBST(READLINE_LIBS) dnl - libsamplerate SAMPLERATE_LIBS= AS_IF([test x"$with_samplerate" != "xno"], [ AC_CHECK_LIB(samplerate, src_new, [have_samplerate=yes; SAMPLERATE_LIBS="-lsamplerate"], [ AS_IF([test "x$with_samplerate" = "xyes"], [AC_MSG_FAILURE( [--with-samplerate was given, but test for libsamplerate failed]) ]) ]) ]) AC_SUBST(SAMPLERATE_LIBS) if test x"$have_samplerate" = "xyes"; then AC_DEFINE(HAVE_SAMPLERATE,,[Enable libsamplerate]) fi dnl - SDL1 dnl Check and setup SDL 1.2 compilation. AM_CONDITIONAL(COMPILE_HW_SDL, false) AM_CONDITIONAL(COMPILE_HW_SDL1, false) HW_SDL1_CFLAGS= HW_SDL1_LIBS= if test x"$enable_hwsdl1" != "xno"; then dnl check for sdl-config AC_CHECK_TOOLS(sdl_config, sdl-config, no) old_cflags=$CFLAGS old_LIBS="$LIBS" old_sdl_libs=$HW_SDL1_LIBS dnl First check for user supplied libs/cflags. dnl In none are given, try sdl-config. dnl If no sdl-config was found, try pkg-config. dnl If this fails, we assume that there are no extra CFLAGS dnl and that libSDL can be found in the default lib search path. if test x"$SDL1_LIBS" != "x" -o x"$SDL1_CFLAGS" != "x"; then HW_SDL1_CFLAGS="$CFLAGS $SDL1_CFLAGS" HW_SDL1_LIBS="$SDL1_LIBS" elif test x"$sdl_config" != "xno"; then HW_SDL1_CFLAGS="$CFLAGS `$sdl_config --cflags`" if test x"$enable_static" = "xyes"; then HW_SDL1_LIBS="`$sdl_config --static-libs`" else HW_SDL1_LIBS="`$sdl_config --libs`" fi elif $pkg_config --exists sdl; then HW_SDL1_CFLAGS="$CFLAGS `$pkg_config --cflags sdl`" if test x"$enable_static" = "xyes"; then HW_SDL1_LIBS="`$pkg_config --static --libs sdl`" else HW_SDL1_LIBS="`$pkg_config --libs sdl`" fi else HW_SDL1_LIBS="-lSDL" fi CFLAGS="$HW_SDL1_CFLAGS" LIBS="$HW_SDL1_LIBS" dnl check for the SDL.h header AC_CHECK_HEADERS(SDL.h,[AC_CHECK_LIB(SDL, SDL_SetVideoMode, [], [CFLAGS=$old_cflags; break],$EXTRA_SDL1_LIBS)], [CFLAGS=$old_cflags; break],$EXTRA_SDL1_LIBS) LIBS="$old_LIBS" if test x"$ac_cv_lib_SDL_SDL_SetVideoMode" != "xyes"; then AC_MSG_WARN([SDL1 headers and/or libraries missing!]) else AC_DEFINE(USE_HWSDL1,,[Enable SDL1 HW support.]) AM_CONDITIONAL(COMPILE_HW_SDL1, true) AM_CONDITIONAL(COMPILE_HW_SDL, true) have_sdl1=yes if test x"$enable_hwsdl1audio" != "xno"; then dnl check for SDL_mixer AC_MSG_CHECKING(for the SDL_mixer library) old_sdl_libs="$HW_SDL1_LIBS" if test x"$SDL1MIXER_LIBS" != "x"; then HW_SDL1_LIBS="$HW_SDL1_LIBS $SDL1MIXER_LIBS" elif $pkg_config --exists SDL_mixer; then if test x"$enable_static" = "xyes"; then if $pkg_config --exists mad; then HW_SDL1_LIBS="`$pkg_config --static --libs SDL_mixer` `$pkg_config --static --libs mad`" else HW_SDL1_LIBS="`$pkg_config --static --libs SDL_mixer`" fi else HW_SDL1_LIBS="`$pkg_config --libs SDL_mixer`" fi else HW_SDL1_LIBS="$HW_SDL1_LIBS -lSDL_mixer" fi LIBS="$old_LIBS $HW_SDL1_LIBS" AC_TRY_LINK([#include "SDL_mixer.h"], [Mix_LoadMUS(0)], [AC_MSG_RESULT(yes); have_sdl1mixer=yes], [AC_MSG_RESULT(no); HW_SDL1_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" if test x"$have_sdl1mixer" = "xyes"; then AC_DEFINE(HAVE_SDL1MIXER,,[Enable SDL_mixer]) else AC_MSG_ERROR([SDL_mixer not found! Either install it or use --disable-hwsdl1audio to disable audio for the SDL1 binaries.]) fi fi if test x"$enable_hwsdl1gl" != "xno"; then dnl check for OpenGL libs AC_MSG_CHECKING(for the OpenGL library) old_sdl_libs="$HW_SDL1_LIBS" HW_SDL1_LIBS="$HW_SDL1_LIBS -lGL" LIBS="$old_LIBS $HW_SDL1_LIBS" AC_TRY_LINK([#include "SDL_opengl.h"], [glViewport(1,2,3,4)], [AC_MSG_RESULT(yes); have_sdl1gl_lib=yes], [AC_MSG_RESULT(no); HW_SDL1_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" if test x"$have_sdl1gl_lib" != "xyes"; then AC_MSG_CHECKING(whether we can use the opengl32 library) old_sdl_libs="$HW_SDL1_LIBS" HW_SDL1_LIBS="$HW_SDL1_LIBS -lopengl32" LIBS="$LIBS $HW_SDL1_LIBS" AC_TRY_LINK([#include "SDL_opengl.h"], [glViewport(1,2,3,4)], [AC_MSG_RESULT(yes); have_sdl1gl_lib=yes], [AC_MSG_RESULT(no); HW_SDL1_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" fi if test x"$have_sdl1gl_lib" = "xyes"; then AC_DEFINE(HAVE_SDL1GL,,[Enable SDL1 OpenGL]) else AC_MSG_ERROR([SDL1 OpenGL not available! Either fix it or use --disable-hwsdl1gl to disable graphics resizing for the SDL1 binaries.]) fi fi AC_MSG_CHECKING(for the SDLmain library) old_sdl_libs="$HW_SDL1_LIBS" HW_SDL1_LIBS="$HW_SDL1_LIBS -lSDLmain -lSDL" LIBS="$LIBS $HW_SDL1_LIBS" AC_TRY_LINK([#include "SDL_main.h" int main(int argc, char *argv[]) { return 0; } #undef main #define main something_else], [return 0;], [AC_MSG_RESULT(yes); have_sdlmain=yes], [AC_MSG_RESULT(no); HW_SDL1_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" if test x"$have_sdlmain" != "xyes"; then AC_MSG_CHECKING(whether we can use the SDLmain library when adding -lmingw32) old_sdl_libs="$HW_SDL1_LIBS" HW_SDL1_LIBS="$HW_SDL1_LIBS -lmingw32 -lSDLmain -lSDL" LIBS="$LIBS $HW_SDL1_LIBS" AC_TRY_LINK([#include "SDL_main.h" int main(int argc, char *argv[]) { return 0; } #undef main #define main something_else], [return 0;], [AC_MSG_RESULT(yes); have_sdlmain=yes], [AC_MSG_RESULT(no); HW_SDL1_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" fi if test x"$have_sdlmain" = "xyes"; then AC_DEFINE(HAVE_SDLMAIN,,[Enable SDLmain replacement]) fi fi CFLAGS="$old_cflags" LIBS="$old_LIBS" fi AC_SUBST(HW_SDL1_CFLAGS) AC_SUBST(HW_SDL1_LIBS) dnl - SDL2 dnl Check and setup SDL 2 compilation. AM_CONDITIONAL(COMPILE_HW_SDL2, false) HW_SDL2_CFLAGS= HW_SDL2_LIBS= if test x"$enable_hwsdl2" != "xno"; then dnl check for sdl2-config AC_CHECK_TOOLS(sdl2_config, sdl2-config, no) old_cflags=$CFLAGS old_LIBS="$LIBS" old_sdl_libs=$HW_SDL2_LIBS dnl First check for user supplied libs/cflags. dnl In none are given, try sdl2-config. dnl If no sdl2-config was found, try pkg-config. dnl If this fails, we assume that there are no extra CFLAGS dnl and that libSDL2 can be found in the default lib search path. if test x"$SDL2_LIBS" != "x" -o x"$SDL2_CFLAGS" != "x"; then HW_SDL2_CFLAGS="$CFLAGS $SDL2_CFLAGS" HW_SDL2_LIBS="$SDL2_LIBS" elif test x"$sdl2_config" != "xno"; then HW_SDL2_CFLAGS="$CFLAGS `$sdl2_config --cflags`" if test x"$enable_static" = "xyes"; then HW_SDL2_LIBS="`$sdl2_config --static-libs`" else HW_SDL2_LIBS="`$sdl2_config --libs`" fi elif $pkg_config --exists sdl2; then HW_SDL2_CFLAGS="$CFLAGS `$pkg_config --cflags sdl2`" if test x"$enable_static" = "xyes"; then HW_SDL2_LIBS="`$pkg_config --static --libs sdl2`" else HW_SDL2_LIBS="`$pkg_config --libs sdl2`" fi else HW_SDL2_LIBS="-lSDL2" fi CFLAGS="$HW_SDL2_CFLAGS" LIBS="$HW_SDL2_LIBS" dnl check for the SDL.h header AS_UNSET(ac_cv_header_SDL_h) AC_CHECK_HEADERS(SDL.h,[AC_CHECK_LIB(SDL2, SDL_CreateTexture, [], [CFLAGS=$old_cflags; break],$EXTRA_SDL2_LIBS)], [CFLAGS=$old_cflags; break],$EXTRA_SDL2_LIBS) LIBS="$old_LIBS" if test x"$ac_cv_lib_SDL2_SDL_CreateTexture" != "xyes"; then AC_MSG_WARN([SDL2 headers and/or libraries missing!]) else AC_DEFINE(USE_HWSDL2,,[Enable SDL2 HW support.]) AM_CONDITIONAL(COMPILE_HW_SDL2, true) AM_CONDITIONAL(COMPILE_HW_SDL, true) have_sdl2=yes if test x"$enable_hwsdl2audio" != "xno"; then dnl check for SDL2_mixer AC_MSG_CHECKING(for the SDL2_mixer library) old_sdl_libs="$HW_SDL2_LIBS" if test x"$SDL2MIXER_LIBS" != "x"; then HW_SDL2_LIBS="$HW_SDL2_LIBS $SDL2MIXER_LIBS" elif $pkg_config --exists SDL2_mixer; then if test x"$enable_static" = "xyes"; then HW_SDL2_LIBS="`$pkg_config --libs --static SDL2_mixer`" else HW_SDL2_LIBS="`$pkg_config --libs SDL2_mixer`" fi else HW_SDL2_LIBS="$HW_SDL2_LIBS -lSDL2_mixer" fi LIBS="$old_LIBS $HW_SDL2_LIBS" AS_UNSET(ac_cv_header_SDL_mixer_h) AC_TRY_LINK([#include "SDL_mixer.h"], [Mix_LoadMUS(0)], [AC_MSG_RESULT(yes); have_sdl2mixer=yes], [AC_MSG_RESULT(no); HW_SDL2_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" if test x"$have_sdl2mixer" = "xyes"; then AC_DEFINE(HAVE_SDL2MIXER,,[Enable SDL2_mixer]) else AC_MSG_ERROR([SDL2_mixer not found! Either install it or use --disable-hwsdl2audio to disable audio for the SDL2 binaries.]) fi fi AC_MSG_CHECKING(for the SDL2main library) old_sdl_libs="$HW_SDL2_LIBS" HW_SDL2_LIBS="$HW_SDL2_LIBS -lSDL2main -lSDL2" LIBS="$LIBS $HW_SDL2_LIBS" AC_TRY_LINK([#include "SDL_main.h" int main(int argc, char *argv[]) { return 0; } #undef main #define main something_else], [return 0;], [AC_MSG_RESULT(yes); have_sdl2main=yes], [AC_MSG_RESULT(no); HW_SDL2_LIBS="$old_sdl_libs"]) LIBS="$old_LIBS" if test x"$have_sdl2main" = "xyes"; then AC_DEFINE(HAVE_SDL2MAIN,,[Enable SDL2main replacement]) fi fi CFLAGS="$old_cflags" LIBS="$old_LIBS" fi AC_SUBST(HW_SDL2_CFLAGS) AC_SUBST(HW_SDL2_LIBS) dnl - Allegro 4 dnl Check and setup Allegro 4 compilation. AM_CONDITIONAL(COMPILE_HW_ALLEG4, false) HW_ALLEG4_LIBS= if test x"$enable_hwalleg4" != "xno"; then old_LIBS="$LIBS" dnl check for the allegro.h header AC_CHECK_HEADERS(allegro.h,[AC_CHECK_LIB(alleg, allegro_exit, [], [break],$EXTRA_ALLEG4_LIBS)], [break],$EXTRA_ALLEG4_LIBS) if test x"$ac_cv_lib_alleg_allegro_exit" != "xyes"; then AC_MSG_WARN([Allegro 4 headers and/or libraries missing!]) else AC_MSG_CHECKING(for Allegro version 4) AC_TRY_LINK([#include "allegro.h" #if ALLEGRO_VERSION != 4 #error "not version 4" #endif ], [return 0;], [AC_MSG_RESULT(yes); have_alleg4=yes], [AC_MSG_RESULT(no); have_alleg4=no]) if test x"$have_alleg4" = "xyes"; then AC_DEFINE(USE_HWALLEG4,,[Enable Allegro 4 HW support.]) AM_CONDITIONAL(COMPILE_HW_ALLEG4, true) HW_ALLEG4_LIBS="-lalleg" else AC_MSG_WARN([Allegro is not version 4!]) fi fi LIBS="$old_LIBS" fi AC_SUBST(HW_ALLEG4_LIBS) dnl - setup the system-specific object files if test x"$is_win32" = "xyes"; then OS_DIR="\$(top_builddir)/src/os/win32" OS_SRC_DIR="\$(top_srcdir)/src/os/win32" BINDIST_SCRIPT="\$(top_srcdir)/make-bindist_win32.sh" AM_CONDITIONAL(COMPILE_UNIX, false) AM_CONDITIONAL(COMPILE_WIN32, true) AM_CONDITIONAL(COMPILE_MSDOS, false) elif test x"$is_msdos" = "xyes"; then OS_DIR="\$(top_builddir)/src/os/msdos" OS_SRC_DIR="\$(top_srcdir)/src/os/msdos" BINDIST_SCRIPT="\$(top_srcdir)/make-bindist_msdos.sh" AM_CONDITIONAL(COMPILE_UNIX, false) AM_CONDITIONAL(COMPILE_WIN32, false) AM_CONDITIONAL(COMPILE_MSDOS, true) else OS_DIR="\$(top_builddir)/src/os/unix" OS_SRC_DIR="\$(top_srcdir)/src/os/unix" BINDIST_SCRIPT="\$(top_srcdir)/make-bindist_install.sh" AM_CONDITIONAL(COMPILE_UNIX, true) AM_CONDITIONAL(COMPILE_WIN32, false) AM_CONDITIONAL(COMPILE_MSDOS, false) fi OS_LIBS="$OS_DIR/libos.a" OS_INCLUDES="-I$OS_SRC_DIR" dnl - build exe opions if test x"$enable_uicmdline" != "xno"; then AM_CONDITIONAL(COMPILE_UICMDLINE, true) else AM_CONDITIONAL(COMPILE_UICMDLINE, false) fi if test x"$enable_uiclassic" != "xno"; then AM_CONDITIONAL(COMPILE_UICLASSIC, true) if test x"$have_sdl1" = "xyes"; then AM_CONDITIONAL(COMPILE_UICLASSIC_SDL1, true) have_classic_hw=yes else AM_CONDITIONAL(COMPILE_UICLASSIC_SDL1, false) fi if test x"$have_sdl2" = "xyes"; then AM_CONDITIONAL(COMPILE_UICLASSIC_SDL2, true) have_classic_hw=yes else AM_CONDITIONAL(COMPILE_UICLASSIC_SDL2, false) fi if test x"$have_alleg4" = "xyes"; then AM_CONDITIONAL(COMPILE_UICLASSIC_ALLEG4, true) have_classic_hw=yes else AM_CONDITIONAL(COMPILE_UICLASSIC_ALLEG4, false) fi else AM_CONDITIONAL(COMPILE_UICLASSIC, false) AM_CONDITIONAL(COMPILE_UICLASSIC_SDL1, false) AM_CONDITIONAL(COMPILE_UICLASSIC_SDL2, false) AM_CONDITIONAL(COMPILE_UICLASSIC_ALLEG4, false) fi if test x"$enable_tools" != "xno"; then AM_CONDITIONAL(COMPILE_TOOLS, true) if test x"$have_sdl1" = "xyes"; then AM_CONDITIONAL(COMPILE_TOOLS_SDL1, true) else AM_CONDITIONAL(COMPILE_TOOLS_SDL1, false) fi if test x"$have_sdl2" = "xyes"; then AM_CONDITIONAL(COMPILE_TOOLS_SDL2, true) else AM_CONDITIONAL(COMPILE_TOOLS_SDL2, false) fi if test x"$have_alleg4" = "xyes"; then AM_CONDITIONAL(COMPILE_TOOLS_ALLEG4, true) else AM_CONDITIONAL(COMPILE_TOOLS_ALLEG4, false) fi else AM_CONDITIONAL(COMPILE_TOOLS, false) AM_CONDITIONAL(COMPILE_TOOLS_SDL1, false) AM_CONDITIONAL(COMPILE_TOOLS_SDL2, false) AM_CONDITIONAL(COMPILE_TOOLS_ALLEG4, false) fi if test x"$enable_uiclassic" != "xno" -a x"$have_classic_hw" != "xyes"; then AC_MSG_ERROR([classic UI enabled but no suitable HW library found!]) fi dnl - finish up AC_SUBST(VERSION_1OOM) AC_SUBST(HAVE_READLINE) AC_SUBST(EXTRA_SDL1_LIBS) AC_SUBST(EXTRA_SDL2_LIBS) AC_SUBST(EXTRA_ALLEG4_LIBS) AC_SUBST(OS_INCLUDES) AC_SUBST(OS_LIBS) AC_SUBST(OS_DIR) AC_SUBST(OS_SRC_DIR) AC_SUBST(BINDIST_SCRIPT) AC_CONFIG_HEADERS([src/config.h]) AC_CONFIG_FILES([Makefile doc/Makefile doc/ext/Makefile src/Makefile src/game/Makefile src/os/Makefile src/os/unix/Makefile src/os/win32/Makefile src/os/msdos/Makefile src/ui/Makefile src/ui/cmdline/Makefile src/ui/classic/Makefile src/ui/nop/Makefile src/hw/Makefile src/hw/nop/Makefile src/hw/sdl/Makefile src/hw/sdl/1/Makefile src/hw/sdl/2/Makefile src/hw/alleg/Makefile src/hw/alleg/4/Makefile ]) AC_OUTPUT 1oom-1.11.2/doc/000077500000000000000000000000001476061725400132305ustar00rootroot000000000000001oom-1.11.2/doc/Makefile.am000066400000000000000000000010151476061725400152610ustar00rootroot00000000000000DIST_SUBDIRS = ext docdir = $(prefix)/share/doc/1oom doc_DATA = \ format_gam.txt \ format_lbx.txt \ format_moo.txt \ format_pbx.txt \ format_save.txt \ lbxmd5.txt \ list_gamediff.txt \ list_pbxnum.txt \ pbxin_example.txt \ pbxin_fixbugs.txt \ usage_classic.txt \ usage_cmdline.txt \ usage_common.txt \ usage_gfxconv.txt \ usage_lbxedit.txt \ usage_lbxview.txt \ usage_pbxdump.txt \ usage_pbxmake.txt \ usage_saveconv.txt EXTRA_DIST = $(doc_DATA) 1oom-1.11.2/doc/ext/000077500000000000000000000000001476061725400140305ustar00rootroot000000000000001oom-1.11.2/doc/ext/Makefile.am000066400000000000000000000002551476061725400160660ustar00rootroot00000000000000EXTRA_DIST = \ allegro-4.2.3.1-p1-modern-xmake.patch \ allegro-4.2.3.1-p2-remove-mouse-cursor.patch \ allegro-4.2.3.1-p3-disable-unused.patch \ fontdump.asm 1oom-1.11.2/doc/ext/allegro-4.2.3.1-p1-modern-xmake.patch000066400000000000000000000153421476061725400222070ustar00rootroot00000000000000From cb45ae601811d05dec9787d08be8dc8c1cc34616 Mon Sep 17 00:00:00 2001 From: Kilgore Trout Mask Replicant Date: Mon, 21 May 2018 17:49:35 +0300 Subject: [PATCH] Fix djgpp target for modern(ish) gcc cross compile This patch assumes the cross compiler is named i586-pc-msdosdjgpp-gcc and resides in /opt/djgpp Edit the affected files afterwards if this is not true for you. The inline changes in alconfig.h needed to avoid hundreds of "multiple definitions of FOO" errors on linking even the most simple test C file. I suppose the semantics for __inline__ have changed somewhat since gcc 2.95. saved_ds in src/misc/vbeafex.c seems to be optimized away if not declared volatile. Another way to fix it would be editing the load_ds() asm block constraints. aldjgpp.h did not declare ALLEGRO_HAVE_INTTYPES_H which broke code including inttypes.h after allegro.h. makefile.dj setting CC = gcc is just bizarre. makefile.lst tests etc are dropped. makefile.tst uses "as". Use the one from the cross compiler instead. xmake.sh is edited for the assumed cross compiler. Edit as appropriate. --- include/allegro/internal/alconfig.h | 5 ++-- include/allegro/platform/aldjgpp.h | 3 +-- makefile.dj | 6 ++--- makefile.lst | 46 +++++++++++++++++++------------------ makefile.tst | 4 ++-- src/misc/vbeafex.c | 2 +- xmake.sh | 11 +++++---- 7 files changed, 39 insertions(+), 38 deletions(-) diff --git a/include/allegro/internal/alconfig.h b/include/allegro/internal/alconfig.h index 15f751f..7131175 100644 --- a/include/allegro/internal/alconfig.h +++ b/include/allegro/internal/alconfig.h @@ -79,15 +79,14 @@ static inline type name args code #else #define AL_INLINE(type, name, args, code) \ - extern __inline__ type name args; \ - extern __inline__ type name args code + static inline type name args code #endif #endif #define AL_PRINTFUNC(type, name, args, a, b) AL_FUNC(type, name, args) __attribute__ ((format (printf, a, b))) #ifndef INLINE - #define INLINE __inline__ + #define INLINE inline #endif #if __GNUC__ >= 3 diff --git a/include/allegro/platform/aldjgpp.h b/include/allegro/platform/aldjgpp.h index 9f1b0cf..02b74cd 100644 --- a/include/allegro/platform/aldjgpp.h +++ b/include/allegro/platform/aldjgpp.h @@ -32,8 +32,7 @@ #define ALLEGRO_DOS #define ALLEGRO_I386 #define ALLEGRO_LITTLE_ENDIAN -#define ALLEGRO_GUESS_INTTYPES_OK - /* inttypes.h and stdint.h not available in djgpp 2.02 */ +#define ALLEGRO_HAVE_INTTYPES_H #define ALLEGRO_CONSOLE_OK #define ALLEGRO_VRAM_SINGLE_SURFACE #define ALLEGRO_USE_CONSTRUCTOR diff --git a/makefile.dj b/makefile.dj index 034f3ef..d5ec6a5 100644 --- a/makefile.dj +++ b/makefile.dj @@ -11,7 +11,7 @@ # -------- define some variables that the primary makefile will use -------- PLATFORM = djgpp -CC = gcc +CC = i586-pc-msdosdjgpp-gcc EXE = .exe OBJ = .o @@ -330,7 +330,7 @@ include makefile.tst # -------- finally, we get to the fun part... -------- define MAKE_LIB - ar rs $(LIB_NAME) $(OBJECTS) + i586-pc-msdosdjgpp-ar rs $(LIB_NAME) $(OBJECTS) endef COMPILE_FLAGS = $(subst src/,-DALLEGRO_SRC ,$(findstring src/, $<))$(CFLAGS) @@ -409,7 +409,7 @@ endef endif define MAKE_PLUGIN_LIB - ar rs $(PLUGIN_LIB) $(PLUGIN_OBJS) + i586-pc-msdosdjgpp-ar rs $(PLUGIN_LIB) $(PLUGIN_OBJS) endef define LINK_WITH_PLUGINS diff --git a/makefile.lst b/makefile.lst index 718a047..7663309 100644 --- a/makefile.lst +++ b/makefile.lst @@ -480,28 +480,30 @@ ALLEGRO_LIB_X_EXE_SOURCES = \ tools/x11/xkeymap.c \ tools/x11/xf2pcx.c -ALLEGRO_LIB_EXES = \ - setup/setup \ - tests/afinfo \ - tests/akaitest \ - tests/digitest \ - tests/filetest \ - tests/gfxinfo \ - tests/mathtest \ - tests/miditest \ - tests/play \ - tests/playfli \ - tests/test \ - tests/vesainfo \ - tools/colormap \ - tools/dat2c \ - tools/exedat \ - tools/pack \ - tools/rgbmap \ - tools/textconv - -ALLEGRO_LIB_CPP_EXES = \ - tests/cpptest +ALLEGRO_LIB_EXES = +# \ +# setup/setup \ +# tests/afinfo \ +# tests/akaitest \ +# tests/digitest \ +# tests/filetest \ +# tests/gfxinfo \ +# tests/mathtest \ +# tests/miditest \ +# tests/play \ +# tests/test +# tests/playfli \ +# tests/vesainfo \ +# tools/colormap \ +# tools/dat2c \ +# tools/exedat \ +# tools/pack \ +# tools/rgbmap \ +# tools/textconv + +ALLEGRO_LIB_CPP_EXES = +# \ +# tests/cpptest ALLEGRO_LIB_X_EXES = \ tools/x11/xkeymap \ diff --git a/makefile.tst b/makefile.tst index 03f6656..a3d56f2 100644 --- a/makefile.tst +++ b/makefile.tst @@ -15,7 +15,7 @@ else endif test-mmx: - as --defsym ASMCAPA_MMX_TEST=1 -o $(PLATFORM_DIR_U)/asmcapa$(OBJ) src/misc/asmcapa.s + i586-pc-msdosdjgpp-as --defsym ASMCAPA_MMX_TEST=1 -o $(PLATFORM_DIR_U)/asmcapa$(OBJ) src/misc/asmcapa.s ifdef UNIX_TOOLS echo "#define ALLEGRO_MMX" >> $(PLATFORM_DIR_U)/asmcapa.h else @@ -23,7 +23,7 @@ else endif test-sse: - as --defsym ASMCAPA_SSE_TEST=1 -o $(PLATFORM_DIR_U)/asmcapa$(OBJ) src/misc/asmcapa.s + i586-pc-msdosdjgpp-as --defsym ASMCAPA_SSE_TEST=1 -o $(PLATFORM_DIR_U)/asmcapa$(OBJ) src/misc/asmcapa.s ifdef UNIX_TOOLS echo "#define ALLEGRO_SSE" >> $(PLATFORM_DIR_U)/asmcapa.h else diff --git a/src/misc/vbeafex.c b/src/misc/vbeafex.c index 2c09f6c..8748bf7 100644 --- a/src/misc/vbeafex.c +++ b/src/misc/vbeafex.c @@ -343,7 +343,7 @@ static void *map_to_process(void *linear, unsigned long limit) /* for the save_ds() / load_ds() functions */ -static unsigned short saved_ds = 0; +static volatile unsigned short saved_ds = 0; diff --git a/xmake.sh b/xmake.sh index 00a893f..355c727 100755 --- a/xmake.sh +++ b/xmake.sh @@ -8,14 +8,14 @@ # 1. Put here the path on which the cross compiler and other tools # for the target will be found with standard names. -XC_PATH=/usr/local/cross-tools/i386-mingw32msvc/bin:/usr/local/cross-tools/bin -XPREFIX=i386-mingw32msvc- +XC_PATH=/opt/djgpp/bin +XPREFIX=i586-pc-msdosdjgpp- # 2. Put here the path for where things are to be installed. # You should have created the lib, info and include directories # in this directory. -INSTALL_BASE=/usr/local/cross-tools/i386-mingw32msvc +INSTALL_BASE=/opt/djgpp/i586-pc-msdosdjgpp # Set up some environment variables and export them to GNU make. @@ -23,10 +23,11 @@ CROSSCOMPILE=1 MINGDIR=$INSTALL_BASE DJDIR=$INSTALL_BASE NATIVEPATH=$PATH -PATH=$XC_PATH:$NATIVEPATH +# PATH=$XC_PATH:$NATIVEPATH -export CROSSCOMPILE MINGDIR DJDIR NATIVEPATH PATH XPREFIX +export CROSSCOMPILE MINGDIR DJDIR NATIVEPATH XPREFIX # Then run make and pass through all command line parameters to it. +#./configure --host=i586-pc-msdosdjgpp --enable-static make $* -- 2.11.0 1oom-1.11.2/doc/ext/allegro-4.2.3.1-p2-remove-mouse-cursor.patch000066400000000000000000000502651476061725400235620ustar00rootroot00000000000000From 0b270ad91907fd6ad6bdf533c65379b219af0155 Mon Sep 17 00:00:00 2001 From: Kilgore Trout Mask Replicant Date: Mon, 28 May 2018 01:58:19 +0300 Subject: [PATCH] Remove mouse cursor --- src/mouse.c | 532 +----------------------------------------------------------- 1 file changed, 3 insertions(+), 529 deletions(-) diff --git a/src/mouse.c b/src/mouse.c index ce4a5e6..1073547 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -72,63 +72,8 @@ int mouse_y_focus = 1; #define MOUSE_OFFSCREEN -4096 /* somewhere to put unwanted cursors */ - -/* default mouse cursor sizes */ -#define DEFAULT_SPRITE_W 16 -#define DEFAULT_SPRITE_H 16 - -/* Default cursor shapes */ -/* TODO: add other shapes! */ -static char mouse_arrow_data[DEFAULT_SPRITE_H * DEFAULT_SPRITE_W] = -{ - 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 1, 1, 1, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 1, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 2, 1, 2, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 2, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 1, 1, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0 -}; - -static char mouse_busy_data[DEFAULT_SPRITE_H * DEFAULT_SPRITE_W] = -{ - 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, - 0, 0, 0, 2, 1, 1, 1, 0, 0, 1, 1, 1, 2, 0, 0, 0, - 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, - 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 2, 0, - 0, 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 0, - 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 2, - 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 2, - 0, 2, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 0, - 0, 2, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 2, 0, - 0, 0, 2, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 2, 0, 0, - 0, 0, 0, 2, 1, 1, 1, 0, 0, 1, 1, 1, 2, 0, 0, 0, - 0, 0, 0, 0, 2, 1, 1, 1, 1, 1, 1, 2, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 2, 2, 1, 1, 2, 2, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 2, 2, 0, 0, 0, 0, 0, 0, 0 -}; - - -BITMAP *_mouse_pointer = NULL; /* default mouse pointer */ - -BITMAP *mouse_sprite = NULL; /* current mouse pointer */ - BITMAP *_mouse_screen = NULL; /* where to draw the pointer */ -static BITMAP *default_cursors[AL_NUM_MOUSE_CURSORS]; -static BITMAP *cursors[AL_NUM_MOUSE_CURSORS]; - static int allow_system_cursor; /* Allow native OS cursor? */ static int use_system_cursor = FALSE; /* Use native OS cursor? */ static int got_hw_cursor = FALSE; /* hardware pointer available? */ @@ -136,125 +81,12 @@ static int hw_cursor_dirty = FALSE; /* need to set a new pointer? */ static int current_cursor = MOUSE_CURSOR_ALLEGRO; static int mx, my; /* previous mouse pointer position */ -static BITMAP *ms = NULL; /* previous screen data */ -static BITMAP *mtemp = NULL; /* double-buffer drawing area */ - -#define SCARED_SIZE 16 /* for unscare_mouse() */ - -static BITMAP *scared_screen[SCARED_SIZE]; -static int scared_freeze[SCARED_SIZE]; -static int scared_size = 0; static int mouse_polled = FALSE; /* are we in polling mode? */ static int mouse_semaphore = FALSE; /* reentrant interrupt? */ - -/* draw_mouse_doublebuffer: - * Eliminates mouse-cursor flicker by using an off-screen buffer for - * updating the cursor, and blitting only the final screen image. - * newx and newy contain the new cursor position, and mx and my are - * assumed to contain previous cursor pos. This routine is called if - * mouse cursor is to be erased and redrawn, and the two position overlap. - */ -static void draw_mouse_doublebuffer(int newx, int newy) -{ - int x1, y1, w, h; - - /* grab bit of screen containing where we are and where we'll be */ - x1 = MIN(mx, newx) - mouse_x_focus; - y1 = MIN(my, newy) - mouse_y_focus; - - /* get width of area */ - w = MAX(mx, newx) - MIN(mx, newx) + mouse_sprite->w+1; - h = MAX(my, newy) - MIN(my, newy) + mouse_sprite->h+1; - - /* make new co-ords relative to 'mtemp' bitmap co-ords */ - newx -= mouse_x_focus+x1; - newy -= mouse_y_focus+y1; - - /* save screen image in 'mtemp' */ - blit(_mouse_screen, mtemp, x1, y1, 0, 0, w, h); - - /* blit saved image in 'ms' to corect place in this buffer */ - blit(ms, mtemp, 0, 0, mx-mouse_x_focus-x1, my-mouse_y_focus-y1, - mouse_sprite->w, mouse_sprite->h); - - /* draw mouse at correct place in 'mtemp' */ - blit(mtemp, ms, newx, newy, 0, 0, mouse_sprite->w, mouse_sprite->h); - draw_sprite(mtemp, mouse_sprite, newx, newy); - - /* blit 'mtemp' to screen */ - blit(mtemp, _mouse_screen, 0, 0, x1, y1, w, h); -} - -END_OF_STATIC_FUNCTION(draw_mouse_doublebuffer); - - - -/* draw_mouse: - * Mouse pointer drawing routine. If remove is set, deletes the old mouse - * pointer. If add is set, draws a new one. - */ -static void draw_mouse(int remove, int add) -{ - int normal_draw = (remove ^ add); - - int newmx = _mouse_x; - int newmy = _mouse_y; - - int cf = _mouse_screen->clip; - int cl = _mouse_screen->cl; - int cr = _mouse_screen->cr; - int ct = _mouse_screen->ct; - int cb = _mouse_screen->cb; - - _mouse_screen->clip = TRUE; - _mouse_screen->cl = _mouse_screen->ct = 0; - _mouse_screen->cr = _mouse_screen->w; - _mouse_screen->cb = _mouse_screen->h; - - if (!_mouse_on) { - newmx = MOUSE_OFFSCREEN; - newmy = MOUSE_OFFSCREEN; - mon = FALSE; - } - else - mon = TRUE; - - if (!normal_draw) { - if ((newmx <= mx-mouse_sprite->w) || (newmx >= mx+mouse_sprite->w) || - (newmy <= my-mouse_sprite->h) || (newmy >= my+mouse_sprite->h)) - normal_draw = 1; - } - - if (normal_draw) { - if (remove) - blit(ms, _mouse_screen, 0, 0, mx-mouse_x_focus, my-mouse_y_focus, mouse_sprite->w, mouse_sprite->h); - - if (add) { - blit(_mouse_screen, ms, newmx-mouse_x_focus, newmy-mouse_y_focus, 0, 0, mouse_sprite->w, mouse_sprite->h); - draw_sprite(_mouse_screen, cursors[current_cursor], newmx-mouse_x_focus, newmy-mouse_y_focus); - } - } - else - draw_mouse_doublebuffer(newmx, newmy); - - mx = newmx; - my = newmy; - - _mouse_screen->clip = cf; - _mouse_screen->cl = cl; - _mouse_screen->cr = cr; - _mouse_screen->ct = ct; - _mouse_screen->cb = cb; -} - -END_OF_STATIC_FUNCTION(draw_mouse); - - - /* update_mouse: * Worker function to update the mouse position variables with new values. */ @@ -352,35 +184,6 @@ static void mouse_move(void) update_mouse(); } - /* redraw pointer */ - if ((!freeze_mouse_flag) && (_mouse_screen) && ((mx != _mouse_x) || (my != _mouse_y) || (mon != _mouse_on))) { - acquire_bitmap(_mouse_screen); - - if (gfx_capabilities & GFX_HW_CURSOR) { - if (_mouse_on) { - gfx_driver->move_mouse(mx=_mouse_x, my=_mouse_y); - mon = TRUE; - } - else { - gfx_driver->move_mouse(mx=MOUSE_OFFSCREEN, my=MOUSE_OFFSCREEN); - mon = FALSE; - } - } - else { -#ifdef ALLEGRO_DOS - /* bodge to avoid using non legacy 386 asm code inside a timer handler */ - int old_capabilities = cpu_capabilities; - cpu_capabilities = 0; -#endif - draw_mouse(TRUE, TRUE); -#ifdef ALLEGRO_DOS - cpu_capabilities = old_capabilities; -#endif - } - - release_bitmap(_mouse_screen); - } - mouse_semaphore = FALSE; } @@ -408,24 +211,7 @@ END_OF_FUNCTION(_handle_mouse_input); */ static BITMAP *create_mouse_pointer(char *data) { - BITMAP *bmp; - int x, y; - int col; - - bmp = create_bitmap(DEFAULT_SPRITE_W, DEFAULT_SPRITE_H); - - for (y=0; yvtable->mask_color; break; - } - putpixel(bmp, x, y, col); - } - } - - return bmp; + return NULL; } @@ -436,51 +222,6 @@ static BITMAP *create_mouse_pointer(char *data) */ void set_mouse_sprite(struct BITMAP *sprite) { - BITMAP *old_mouse_screen = _mouse_screen; - int am_using_sys_cursor = use_system_cursor; - - if (!mouse_driver) - return; - - if (_mouse_screen && !am_using_sys_cursor) - show_mouse(NULL); - - if (sprite) - mouse_sprite = sprite; - else { - if (_mouse_pointer) - destroy_bitmap(_mouse_pointer); - _mouse_pointer = create_mouse_pointer(mouse_arrow_data); - mouse_sprite = _mouse_pointer; - } - - cursors[MOUSE_CURSOR_ALLEGRO] = mouse_sprite; - - lock_bitmap((struct BITMAP*)mouse_sprite); - - /* make sure the ms bitmap is big enough */ - if ((!ms) || (ms->w < mouse_sprite->w) || (ms->h < mouse_sprite->h) || - (bitmap_color_depth(mouse_sprite) != bitmap_color_depth(ms))) { - if (ms) { - destroy_bitmap(ms); - destroy_bitmap(mtemp); - } - - ms = create_bitmap(mouse_sprite->w, mouse_sprite->h); - lock_bitmap(ms); - - mtemp = create_bitmap(mouse_sprite->w*2, mouse_sprite->h*2); - lock_bitmap(mtemp); - } - - mouse_x_focus = 1; - mouse_y_focus = 1; - - if (!am_using_sys_cursor) - hw_cursor_dirty = TRUE; - - if (old_mouse_screen && !am_using_sys_cursor) - show_mouse(old_mouse_screen); } @@ -503,11 +244,6 @@ void select_mouse_cursor(int cursor) */ void set_mouse_cursor_bitmap(int cursor, struct BITMAP *bmp) { - ASSERT(cursor >= 0); - ASSERT(cursor != MOUSE_CURSOR_NONE); - ASSERT(cursor < AL_NUM_MOUSE_CURSORS); - - cursors[cursor] = bmp?bmp:default_cursors[cursor]; } @@ -544,45 +280,8 @@ int show_os_cursor(int cursor) remove_int(mouse_move); - gfx_capabilities &= ~(GFX_HW_CURSOR|GFX_SYSTEM_CURSOR); - if (cursor != MOUSE_CURSOR_NONE) { - - if (mouse_driver->enable_hardware_cursor) { - mouse_driver->enable_hardware_cursor(TRUE); - } - - /* default system cursor? */ - if (cursor != MOUSE_CURSOR_ALLEGRO) { - if (mouse_driver->select_system_cursor) { - if (mouse_driver->select_system_cursor(cursor) != 0) { - gfx_capabilities |= (GFX_HW_CURSOR|GFX_SYSTEM_CURSOR); - r = 0; - goto done; - } - } - goto done; - } - else { - /* set custom hardware cursor */ - if (gfx_driver) { - if (gfx_driver->set_mouse_sprite) { - if (gfx_driver->set_mouse_sprite(mouse_sprite, mouse_x_focus, mouse_y_focus)) - goto done; - } - if (gfx_driver->show_mouse) { - if (gfx_driver->show_mouse(screen, mouse_x, mouse_y)) - goto done; - } - gfx_capabilities |= GFX_HW_CURSOR; - r = 0; - goto done; - } - } - } - else { - if (gfx_driver && gfx_driver->hide_mouse) - gfx_driver->hide_mouse(); - } + if (gfx_driver && gfx_driver->hide_mouse) + gfx_driver->hide_mouse(); done: if (mouse_driver->timer_poll) @@ -603,76 +302,6 @@ done: */ void show_mouse(BITMAP *bmp) { - if (!mouse_driver) - return; - - remove_int(mouse_move); - - /* Remove the mouse cursor */ - if (_mouse_screen) { - acquire_bitmap(_mouse_screen); - - if (gfx_capabilities & GFX_HW_CURSOR) { - gfx_driver->hide_mouse(); - gfx_capabilities &= ~(GFX_HW_CURSOR|GFX_SYSTEM_CURSOR); - hw_cursor_dirty = TRUE; - } - else - draw_mouse(TRUE, FALSE); - - release_bitmap(_mouse_screen); - } - - _mouse_screen = bmp; - - if (bmp && (current_cursor != MOUSE_CURSOR_NONE)) { - acquire_bitmap(_mouse_screen); - - /* Default system cursor? */ - if ((current_cursor != MOUSE_CURSOR_ALLEGRO) && allow_system_cursor) { - if (mouse_driver && mouse_driver->select_system_cursor) { - use_system_cursor = mouse_driver->select_system_cursor(current_cursor); - if (use_system_cursor) { - gfx_capabilities |= GFX_HW_CURSOR|GFX_SYSTEM_CURSOR; - hw_cursor_dirty = FALSE; - got_hw_cursor = TRUE; - } - } - } - else { - use_system_cursor = FALSE; - } - - /* Custom hardware cursor? */ - if (hw_cursor_dirty) { - got_hw_cursor = FALSE; - - if ((gfx_driver) && (gfx_driver->set_mouse_sprite) && (!_dispsw_status)) - if (gfx_driver->set_mouse_sprite(mouse_sprite, mouse_x_focus, mouse_y_focus) == 0) - got_hw_cursor = TRUE; - - hw_cursor_dirty = FALSE; - } - - /* Try to display hardware (custom or system) cursor */ - if ((got_hw_cursor) && (is_same_bitmap(bmp, screen))) - if (gfx_driver->show_mouse(bmp, mx=mouse_x, my=mouse_y) == 0) - gfx_capabilities |= GFX_HW_CURSOR; - - /* Draw cursor manually if we can't do that */ - if (!(gfx_capabilities & GFX_HW_CURSOR)) { - draw_mouse(FALSE, TRUE); - use_system_cursor = FALSE; - } - - release_bitmap(_mouse_screen); - - install_int(mouse_move, 10); - } - else { - if (mouse_driver->timer_poll) - install_int(mouse_move, 10); - } } @@ -685,24 +314,6 @@ void show_mouse(BITMAP *bmp) */ void scare_mouse(void) { - if (!mouse_driver) - return; - - if ((is_same_bitmap(screen, _mouse_screen)) && (!(gfx_capabilities & GFX_HW_CURSOR))) { - if (scared_size < SCARED_SIZE) { - scared_screen[scared_size] = _mouse_screen; - scared_freeze[scared_size] = FALSE; - } - show_mouse(NULL); - } - else { - if (scared_size < SCARED_SIZE) { - scared_screen[scared_size] = NULL; - scared_freeze[scared_size] = FALSE; - } - } - - scared_size++; } @@ -716,49 +327,6 @@ void scare_mouse(void) */ void scare_mouse_area(int x, int y, int w, int h) { - int was_frozen; - - if (!mouse_driver) - return; - - if ((is_same_bitmap(screen, _mouse_screen)) && (!(gfx_capabilities & GFX_HW_CURSOR))) { - was_frozen = freeze_mouse_flag; - freeze_mouse_flag = TRUE; - - if ((mx - mouse_x_focus < x + w) && - (my - mouse_y_focus < y + h) && - (mx - mouse_x_focus + mouse_sprite->w >= x) && - (my - mouse_y_focus + mouse_sprite->h >= y)) { - - if (scared_size < SCARED_SIZE) { - scared_screen[scared_size] = _mouse_screen; - scared_freeze[scared_size] = FALSE; - } - - freeze_mouse_flag = was_frozen; - show_mouse(NULL); - } - else { - if (scared_size < SCARED_SIZE) { - scared_screen[scared_size] = NULL; - - if (was_frozen) { - scared_freeze[scared_size] = FALSE; - freeze_mouse_flag = was_frozen; - } - else - scared_freeze[scared_size] = TRUE; - } - } - } - else { - if (scared_size < SCARED_SIZE) { - scared_screen[scared_size] = NULL; - scared_freeze[scared_size] = FALSE; - } - } - - scared_size++; } @@ -769,22 +337,6 @@ void scare_mouse_area(int x, int y, int w, int h) */ void unscare_mouse(void) { - if (!mouse_driver) - return; - - if (scared_size > 0) - scared_size--; - - if (scared_size < SCARED_SIZE) { - if (scared_screen[scared_size]) - show_mouse(scared_screen[scared_size]); - - if (scared_freeze[scared_size]) - freeze_mouse_flag = FALSE; - - scared_screen[scared_size] = NULL; - scared_freeze[scared_size] = FALSE; - } } @@ -795,14 +347,9 @@ void unscare_mouse(void) */ void position_mouse(int x, int y) { - BITMAP *old_mouse_screen = _mouse_screen; - if (!mouse_driver) return; - if (_mouse_screen) - show_mouse(NULL); - if (mouse_driver->position) { mouse_driver->position(x, y); } @@ -812,9 +359,6 @@ void position_mouse(int x, int y) } update_mouse(); - - if (old_mouse_screen) - show_mouse(old_mouse_screen); } @@ -854,7 +398,6 @@ void position_mouse_w(int w) */ void set_mouse_range(int x1, int y1, int x2, int y2) { - BITMAP *old_mouse_screen = _mouse_screen; ASSERT(x1 >= 0); ASSERT(y1 >= 0); ASSERT(x2 >= x1); @@ -863,16 +406,10 @@ void set_mouse_range(int x1, int y1, int x2, int y2) if (!mouse_driver) return; - if (_mouse_screen) - show_mouse(NULL); - if (mouse_driver->set_range) mouse_driver->set_range(x1, y1, x2, y2); update_mouse(); - - if (old_mouse_screen) - show_mouse(old_mouse_screen); } @@ -915,11 +452,6 @@ void enable_hardware_cursor(void) if ((mouse_driver) && (mouse_driver->enable_hardware_cursor)) { mouse_driver->enable_hardware_cursor(TRUE); allow_system_cursor = TRUE; - if (is_same_bitmap(_mouse_screen, screen)) { - BITMAP *bmp = _mouse_screen; - show_mouse(NULL); - show_mouse(bmp); - } } } @@ -934,11 +466,6 @@ void disable_hardware_cursor(void) if ((mouse_driver) && (mouse_driver->enable_hardware_cursor)) { mouse_driver->enable_hardware_cursor(FALSE); allow_system_cursor = FALSE; - if (is_same_bitmap(_mouse_screen, screen)) { - BITMAP *bmp = _mouse_screen; - show_mouse(NULL); - show_mouse(bmp); - } } } @@ -994,13 +521,6 @@ static void set_mouse_etc(void) if ((!mouse_driver) || (!gfx_driver)) return; - if ((!_mouse_pointer) || - ((screen) && (_mouse_pointer) && - (bitmap_color_depth(_mouse_pointer) != bitmap_color_depth(screen)))) - set_mouse_sprite(NULL); - else - hw_cursor_dirty = TRUE; - set_mouse_range(0, 0, SCREEN_W-1, SCREEN_H-1); set_mouse_speed(2, 2); position_mouse(SCREEN_W/2, SCREEN_H/2); @@ -1045,38 +565,15 @@ int install_mouse(void) LOCK_VARIABLE(mouse_callback); LOCK_VARIABLE(mouse_x_focus); LOCK_VARIABLE(mouse_y_focus); - LOCK_VARIABLE(mouse_sprite); - LOCK_VARIABLE(_mouse_pointer); - LOCK_VARIABLE(_mouse_screen); LOCK_VARIABLE(mx); LOCK_VARIABLE(my); - LOCK_VARIABLE(ms); - LOCK_VARIABLE(mtemp); LOCK_VARIABLE(mouse_polled); LOCK_VARIABLE(mouse_semaphore); - LOCK_VARIABLE(cursors); - LOCK_FUNCTION(draw_mouse_doublebuffer); - LOCK_FUNCTION(draw_mouse); LOCK_FUNCTION(update_mouse); LOCK_FUNCTION(mouse_move); LOCK_FUNCTION(poll_mouse); LOCK_FUNCTION(mouse_needs_poll); LOCK_FUNCTION(_handle_mouse_input); - - /* Construct mouse pointers */ - if (!default_cursors[MOUSE_CURSOR_ARROW]) - default_cursors[MOUSE_CURSOR_ARROW] = create_mouse_pointer(mouse_arrow_data); - if (!default_cursors[MOUSE_CURSOR_BUSY]) - default_cursors[MOUSE_CURSOR_BUSY] = create_mouse_pointer(mouse_busy_data); - if (!default_cursors[MOUSE_CURSOR_QUESTION]) - default_cursors[MOUSE_CURSOR_QUESTION] = create_mouse_pointer(mouse_arrow_data); - if (!default_cursors[MOUSE_CURSOR_EDIT]) - default_cursors[MOUSE_CURSOR_EDIT] = create_mouse_pointer(mouse_arrow_data); - - cursors[MOUSE_CURSOR_ARROW] = default_cursors[MOUSE_CURSOR_ARROW]; - cursors[MOUSE_CURSOR_BUSY] = default_cursors[MOUSE_CURSOR_BUSY]; - cursors[MOUSE_CURSOR_QUESTION] = default_cursors[MOUSE_CURSOR_QUESTION]; - cursors[MOUSE_CURSOR_EDIT] = default_cursors[MOUSE_CURSOR_EDIT]; if (system_driver->mouse_drivers) driver_list = system_driver->mouse_drivers(); @@ -1174,29 +671,6 @@ void remove_mouse(void) mouse_polled = FALSE; - destroy_bitmap(default_cursors[MOUSE_CURSOR_ARROW]); - destroy_bitmap(default_cursors[MOUSE_CURSOR_BUSY]); - destroy_bitmap(default_cursors[MOUSE_CURSOR_QUESTION]); - destroy_bitmap(default_cursors[MOUSE_CURSOR_EDIT]); - - cursors[MOUSE_CURSOR_ARROW] = default_cursors[MOUSE_CURSOR_ARROW] = NULL; - cursors[MOUSE_CURSOR_BUSY] = default_cursors[MOUSE_CURSOR_BUSY] = NULL; - cursors[MOUSE_CURSOR_QUESTION] = default_cursors[MOUSE_CURSOR_QUESTION] = NULL; - cursors[MOUSE_CURSOR_EDIT] = default_cursors[MOUSE_CURSOR_EDIT] = NULL; - - if (_mouse_pointer) { - destroy_bitmap(_mouse_pointer); - _mouse_pointer = NULL; - } - - if (ms) { - destroy_bitmap(ms); - ms = NULL; - - destroy_bitmap(mtemp); - mtemp = NULL; - } - _remove_exit_func(remove_mouse); } -- 2.11.0 1oom-1.11.2/doc/ext/allegro-4.2.3.1-p3-disable-unused.patch000066400000000000000000000667311476061725400225360ustar00rootroot00000000000000From b29c14c864bcf7b01b5035aef6163bea56bca915 Mon Sep 17 00:00:00 2001 From: Kilgore Trout Mask Replicant Date: Mon, 28 May 2018 12:43:17 +0300 Subject: [PATCH] Disable/remove some code not used by 1oom --- include/allegro/internal/alconfig.h | 3 - makefile.all | 4 +- makefile.lst | 126 +----------- src/blit.c | 396 +----------------------------------- src/dos/dgfxdrv.c | 2 - src/dos/djoydrv.c | 13 -- src/gfx.c | 15 +- src/graphics.c | 8 +- src/misc/modex.c | 84 ++++---- src/vtable8.c | 82 ++++---- 10 files changed, 106 insertions(+), 627 deletions(-) diff --git a/include/allegro/internal/alconfig.h b/include/allegro/internal/alconfig.h index 7131175..214f038 100644 --- a/include/allegro/internal/alconfig.h +++ b/include/allegro/internal/alconfig.h @@ -18,9 +18,6 @@ /* which color depths to include? */ #define ALLEGRO_COLOR8 -#define ALLEGRO_COLOR16 -#define ALLEGRO_COLOR24 -#define ALLEGRO_COLOR32 /* for backward compatibility */ diff --git a/makefile.all b/makefile.all index cc6f172..65b085b 100644 --- a/makefile.all +++ b/makefile.all @@ -119,7 +119,7 @@ endif # -------- list what objects and programs we need to build -------- -VPATH += src demo docs examples setup tests tools tools/plugins docs/src/makedoc +VPATH += src OBJECTS = $(addprefix $(OBJ_DIR)/, $(addsuffix $(OBJ), $(OBJECT_LIST))) @@ -136,7 +136,7 @@ ifeq (,$(wildcard $(PLATFORM_DIR)/cpp-tested)) endif endif -PROGRAMS += $(CPP_PROGRAMS) demo examples makedoc +PROGRAMS += $(CPP_PROGRAMS) EXAMPLES = $(basename $(notdir $(ALLEGRO_EXAMPLE_FILES))) diff --git a/makefile.lst b/makefile.lst index 7663309..40d7a6e 100644 --- a/makefile.lst +++ b/makefile.lst @@ -3,126 +3,48 @@ ALLEGRO_SRC_FILES = \ src/allegro.c \ src/blit.c \ - src/bmp.c \ - src/clip3d.c \ - src/clip3df.c \ - src/colblend.c \ - src/color.c \ src/config.c \ - src/datafile.c \ src/dataregi.c \ src/digmid.c \ - src/dither.c \ src/dispsw.c \ src/drvlist.c \ src/file.c \ - src/fli.c \ - src/flood.c \ - src/font.c \ - src/fontbios.c \ - src/fontbmp.c \ - src/fontdat.c \ - src/fontgrx.c \ - src/fonttxt.c \ - src/fsel.c \ src/gfx.c \ src/glyph.c \ src/graphics.c \ - src/gsprite.c \ - src/gui.c \ - src/guiproc.c \ src/inline.c \ - src/joystick.c \ src/keyboard.c \ - src/lbm.c \ src/libc.c \ src/lzss.c \ src/math.c \ - src/math3d.c \ src/midi.c \ src/mixer.c \ src/modesel.c \ src/mouse.c \ - src/pcx.c \ - src/poly3d.c \ - src/polygon.c \ - src/quantize.c \ - src/quat.c \ - src/readbmp.c \ - src/readfont.c \ - src/readsmp.c \ - src/rle.c \ - src/rotate.c \ - src/scene3d.c \ src/sound.c \ - src/spline.c \ src/stream.c \ - src/text.c \ - src/tga.c \ src/timer.c \ src/unicode.c \ src/vtable.c \ - src/vtable15.c \ - src/vtable16.c \ - src/vtable24.c \ - src/vtable32.c \ src/vtable8.c ALLEGRO_SRC_C_FILES = \ - src/c/cblit16.c \ - src/c/cblit24.c \ - src/c/cblit32.c \ src/c/cblit8.c \ src/c/ccpu.c \ src/c/ccsprite.c \ - src/c/cgfx15.c \ - src/c/cgfx16.c \ - src/c/cgfx24.c \ - src/c/cgfx32.c \ src/c/cgfx8.c \ src/c/cmisc.c \ - src/c/cscan15.c \ - src/c/cscan16.c \ - src/c/cscan24.c \ - src/c/cscan32.c \ src/c/cscan8.c \ - src/c/cspr15.c \ - src/c/cspr16.c \ - src/c/cspr24.c \ - src/c/cspr32.c \ src/c/cspr8.c \ src/c/cstretch.c \ - src/c/czscan15.c \ - src/c/czscan16.c \ - src/c/czscan24.c \ - src/c/czscan32.c \ src/c/czscan8.c \ src/misc/ccolconv.c ALLEGRO_SRC_I386_FILES = \ - src/i386/iblit16.s \ - src/i386/iblit24.s \ - src/i386/iblit32.s \ src/i386/iblit8.s \ src/i386/icpu.c \ src/i386/icpus.s \ - src/i386/icsprite.c \ - src/i386/igfx15.s \ - src/i386/igfx16.s \ - src/i386/igfx24.s \ - src/i386/igfx32.s \ - src/i386/igfx8.s \ - src/i386/imisc.s \ - src/i386/iscan.s \ - src/i386/iscanmmx.s \ - src/i386/ispr15.s \ - src/i386/ispr16.s \ - src/i386/ispr24.s \ - src/i386/ispr32.s \ - src/i386/ispr8.s \ - src/i386/istretch.c \ - src/i386/izbuf.s \ - src/misc/icolconv.s + src/i386/imisc.s ALLEGRO_SRC_AMD64_FILES = \ src/c/cblit16.c \ @@ -172,36 +94,17 @@ ALLEGRO_SRC_DOS_FILES = \ src/dos/emu8k.c \ src/dos/emu8kmid.c \ src/dos/essaudio.c \ - src/dos/gpro.c \ - src/dos/grip.c \ - src/dos/gripjoy.c \ - src/dos/gripfnc.s \ - src/dos/ifsega.c \ - src/dos/ifsega2f.c \ - src/dos/ifsega2p.c \ - src/dos/joystd.c \ src/dos/mpu.c \ - src/dos/multijoy.c \ - src/dos/n64pad.c \ src/dos/pic.c \ - src/dos/psxpad.c \ src/dos/sb.c \ src/dos/sndscape.c \ - src/dos/snespad.c \ - src/dos/sw.c \ - src/dos/swpp.c \ - src/dos/swpps.s \ src/dos/vesa.c \ src/dos/vesas.s \ src/dos/wss.c \ - src/dos/ww.c \ src/misc/modex.c \ src/misc/modexgfx.s \ src/misc/modexsms.c \ src/misc/pckeys.c \ - src/misc/vbeaf.c \ - src/misc/vbeafs.s \ - src/misc/vbeafex.c \ src/misc/vga.c \ src/misc/vgaregs.c @@ -481,29 +384,8 @@ ALLEGRO_LIB_X_EXE_SOURCES = \ tools/x11/xf2pcx.c ALLEGRO_LIB_EXES = -# \ -# setup/setup \ -# tests/afinfo \ -# tests/akaitest \ -# tests/digitest \ -# tests/filetest \ -# tests/gfxinfo \ -# tests/mathtest \ -# tests/miditest \ -# tests/play \ -# tests/test -# tests/playfli \ -# tests/vesainfo \ -# tools/colormap \ -# tools/dat2c \ -# tools/exedat \ -# tools/pack \ -# tools/rgbmap \ -# tools/textconv ALLEGRO_LIB_CPP_EXES = -# \ -# tests/cpptest ALLEGRO_LIB_X_EXES = \ tools/x11/xkeymap \ @@ -515,11 +397,7 @@ ALLEGRO_DATAFILE_EXE_SOURCES = \ tools/grabber.c \ tools/pat2dat.c -ALLEGRO_DATAFILE_EXES = \ - tools/dat \ - tools/dat2s \ - tools/grabber \ - tools/pat2dat +ALLEGRO_DATAFILE_EXES = ALLEGRO_EXAMPLE_FILES = \ examples/ex12bit.c \ diff --git a/src/blit.c b/src/blit.c index dd4d29f..1bc4e75 100644 --- a/src/blit.c +++ b/src/blit.c @@ -41,6 +41,7 @@ static int get_replacement_mask_color(BITMAP *bmp) else return bestfit_color(_current_palette, 63, 1, 63); } +#if 0 else { do c = makecol_depth(depth, 255, ++g, 255); @@ -48,6 +49,7 @@ static int get_replacement_mask_color(BITMAP *bmp) return c; } +#endif } @@ -224,377 +226,6 @@ static void blit_from_256(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, makecol##dbits##_dither(r, g, b, x, y)) - -#if (defined ALLEGRO_COLOR8) || (defined ALLEGRO_GFX_HAS_VGA) - -/* dither_blit: - * Blits with Floyd-Steinberg error diffusion. - */ -static void dither_blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - int prev_drawmode = _drawing_mode; - int *errline[3]; - int *errnextline[3]; - int errpixel[3]; - int v[3], e[3], n[3]; - int x, y, i; - int c, nc, rc; - - /* allocate memory for the error buffers */ - for (i=0; i<3; i++) { - errline[i] = _AL_MALLOC_ATOMIC(sizeof(int) * w); - errnextline[i] = _AL_MALLOC_ATOMIC(sizeof(int) * w); - } - - /* free the buffers if there was an error allocating one */ - for (i=0; i<3; i++) { - if ((!errline[i]) || (!errnextline[i])) - goto getout; - } - - /* initialize the error buffers */ - for (i=0; i<3; i++) { - memset(errline[i], 0, sizeof(int) * w); - memset(errnextline[i], 0, sizeof(int) * w); - errpixel[i] = 0; - } - - /* get the replacement color */ - rc = get_replacement_mask_color(dest); - - _drawing_mode = DRAW_MODE_SOLID; - - /* dither!!! */ - for (y =0; y 255) - n[i] = 255; - - if (n[i] < 0) - n[i] = 0; - } - - /* find the nearest matching colour */ - nc = makecol8(n[0], n[1], n[2]); - if (_color_conv & COLORCONV_KEEP_TRANS) { - if (c == bitmap_mask_color(src)) - putpixel(dest, d_x+x, d_y+y, bitmap_mask_color(dest)); - else if (nc == bitmap_mask_color(dest)) - putpixel(dest, d_x+x, d_y+y, rc); - else - putpixel(dest, d_x+x, d_y+y, nc); - } - else { - putpixel(dest, d_x+x, d_y+y, nc); - } - v[0] = getr8(nc); - v[1] = getg8(nc); - v[2] = getb8(nc); - - /* calculate the error and store it */ - for (i=0; i<3; i++) { - e[i] = n[i] - v[i]; - errpixel[i] = (int)((e[i] * 3)/8); - errnextline[i][x] += errpixel[i]; - - if (x != w-1) - errnextline[i][x+1] = (int)(e[i]/4); - } - } - - /* update error buffers */ - for (i=0; i<3; i++) { - memcpy(errline[i], errnextline[i], sizeof(int) * w); - memset(errnextline[i], 0, sizeof(int) * w); - } - } - - _drawing_mode = prev_drawmode; - - getout: - - for (i=0; i<3; i++) { - if (errline[i]) - _AL_FREE(errline[i]); - - if (errnextline[i]) - _AL_FREE(errnextline[i]); - } -} - -#endif - - - -/* blit_from_15: - * Converts 15 bpp images onto some other destination format. - */ -static void blit_from_15(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - #ifdef ALLEGRO_COLOR16 - - int x, y, c, r, g, b; - uintptr_t s, d; - - switch (bitmap_color_depth(dest)) { - - #ifdef ALLEGRO_COLOR8 - case 8: - if (_color_conv & COLORCONV_DITHER_PAL) - dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h); - else - CONVERT_BLIT(15, sizeof(int16_t), 8, 1) - break; - #endif - - case 16: - CONVERT_BLIT(15, sizeof(int16_t), 16, sizeof(int16_t)) - break; - - #ifdef ALLEGRO_COLOR24 - case 24: - CONVERT_BLIT(15, sizeof(int16_t), 24, 3) - break; - #endif - - #ifdef ALLEGRO_COLOR32 - case 32: - CONVERT_BLIT(15, sizeof(int16_t), 32, sizeof(int32_t)) - break; - #endif - } - - #endif -} - - - -/* blit_from_16: - * Converts 16 bpp images onto some other destination format. - */ -static void blit_from_16(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - #ifdef ALLEGRO_COLOR16 - - int x, y, c, r, g, b; - uintptr_t s, d; - - switch (bitmap_color_depth(dest)) { - - #ifdef ALLEGRO_COLOR8 - case 8: - if (_color_conv & COLORCONV_DITHER_PAL) - dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h); - else - CONVERT_BLIT(16, sizeof(int16_t), 8, 1) - break; - #endif - - case 15: - CONVERT_BLIT(16, sizeof(int16_t), 15, sizeof(int16_t)) - break; - - #ifdef ALLEGRO_COLOR24 - case 24: - CONVERT_BLIT(16, sizeof(int16_t), 24, 3) - break; - #endif - - #ifdef ALLEGRO_COLOR32 - case 32: - CONVERT_BLIT(16, sizeof(int16_t), 32, sizeof(int32_t)) - break; - #endif - } - - #endif -} - - - -/* blit_from_24: - * Converts 24 bpp images onto some other destination format. - */ -static void blit_from_24(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - #ifdef ALLEGRO_COLOR24 - - int x, y, c, r, g, b; - uintptr_t s, d; - - switch (bitmap_color_depth(dest)) { - - #ifdef ALLEGRO_COLOR8 - case 8: - if (_color_conv & COLORCONV_DITHER_PAL) - dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h); - else - CONVERT_BLIT(24, 3, 8, 1); - break; - #endif - - #ifdef ALLEGRO_COLOR16 - case 15: - if (_color_conv & COLORCONV_DITHER_HI) - CONVERT_DITHER_BLIT(24, 3, 15, sizeof(int16_t)) - else - CONVERT_BLIT(24, 3, 15, sizeof(int16_t)) - break; - - case 16: - if (_color_conv & COLORCONV_DITHER_HI) - CONVERT_DITHER_BLIT(24, 3, 16, sizeof(int16_t)) - else - CONVERT_BLIT(24, 3, 16, sizeof(int16_t)) - break; - #endif - - #ifdef ALLEGRO_COLOR32 - case 32: - CONVERT_BLIT(24, 3, 32, sizeof(int32_t)) - break; - #endif - } - - #endif -} - - - -/* blit_from_32: - * Converts 32 bpp images onto some other destination format. - */ -static void blit_from_32(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - #ifdef ALLEGRO_COLOR32 - - int x, y, c, r, g, b; - uintptr_t s, d; - - switch (bitmap_color_depth(dest)) { - - #ifdef ALLEGRO_COLOR8 - case 8: - if (_color_conv & COLORCONV_DITHER_PAL) - dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h); - else - CONVERT_BLIT(32, sizeof(int32_t), 8, 1) - break; - #endif - - #ifdef ALLEGRO_COLOR16 - case 15: - if (_color_conv & COLORCONV_DITHER_HI) - CONVERT_DITHER_BLIT(32, sizeof(int32_t), 15, sizeof(int16_t)) - else - CONVERT_BLIT(32, sizeof(int32_t), 15, sizeof(int16_t)) - break; - - case 16: - if (_color_conv & COLORCONV_DITHER_HI) - CONVERT_DITHER_BLIT(32, sizeof(int32_t), 16, sizeof(int16_t)) - else - CONVERT_BLIT(32, sizeof(int32_t), 16, sizeof(int16_t)) - break; - #endif - - #ifdef ALLEGRO_COLOR24 - case 24: - CONVERT_BLIT(32, sizeof(int32_t), 24, 3) - break; - #endif - } - - #endif -} - - - -/* blit_to_or_from_modex: - * Converts between truecolor and planar mode-X bitmaps. This function is - * painfully slow, but I don't think it is something that people will need - * to do very often... - */ -static void blit_to_or_from_modex(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - #ifdef ALLEGRO_GFX_HAS_VGA - - int x, y, c, r, g, b; - int src_depth = bitmap_color_depth(src); - int dest_depth = bitmap_color_depth(dest); - - int prev_drawmode = _drawing_mode; - _drawing_mode = DRAW_MODE_SOLID; - - if ((src_depth != 8) && (_color_conv & COLORCONV_DITHER_PAL)) - dither_blit(src, dest, s_x, s_y, d_x, d_y, w, h); - else { - for (y=0; yvtable->color_depth != dest->vtable->color_depth) { - /* need to do a color conversion */ - dest->vtable->blit_between_formats(src, dest, s_x, s_y, d_x, d_y, w, h); - } - else if (is_same_bitmap(src, dest)) { + if (is_same_bitmap(src, dest)) { /* special handling for overlapping regions */ blit_to_self(src, dest, s_x, s_y, d_x, d_y, w, h); } @@ -741,20 +368,3 @@ void blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, } END_OF_FUNCTION(blit); - - - -/* masked_blit: - * Version of blit() that skips zero pixels. The source must be a memory - * bitmap, and the source and dest regions must not overlap. - */ -void masked_blit(BITMAP *src, BITMAP *dest, int s_x, int s_y, int d_x, int d_y, int w, int h) -{ - ASSERT(src); - ASSERT(dest); - ASSERT(src->vtable->color_depth == dest->vtable->color_depth); - - BLIT_CLIP(); - - dest->vtable->masked_blit(src, dest, s_x, s_y, d_x, d_y, w, h); -} diff --git a/src/dos/dgfxdrv.c b/src/dos/dgfxdrv.c index f7890de..e602236 100644 --- a/src/dos/dgfxdrv.c +++ b/src/dos/dgfxdrv.c @@ -24,9 +24,7 @@ #endif - BEGIN_GFX_DRIVER_LIST - GFX_DRIVER_VBEAF GFX_DRIVER_VGA GFX_DRIVER_MODEX GFX_DRIVER_VESA3 diff --git a/src/dos/djoydrv.c b/src/dos/djoydrv.c index 676d0ad..726fc14 100644 --- a/src/dos/djoydrv.c +++ b/src/dos/djoydrv.c @@ -26,17 +26,4 @@ BEGIN_JOYSTICK_DRIVER_LIST - JOYSTICK_DRIVER_WINGWARRIOR - JOYSTICK_DRIVER_SIDEWINDER - JOYSTICK_DRIVER_GAMEPAD_PRO - JOYSTICK_DRIVER_GRIP - JOYSTICK_DRIVER_STANDARD - JOYSTICK_DRIVER_SNESPAD - JOYSTICK_DRIVER_PSXPAD - JOYSTICK_DRIVER_N64PAD - JOYSTICK_DRIVER_DB9 - JOYSTICK_DRIVER_TURBOGRAFX - JOYSTICK_DRIVER_IFSEGA_ISA - JOYSTICK_DRIVER_IFSEGA_PCI - JOYSTICK_DRIVER_IFSEGA_PCI_FAST END_JOYSTICK_DRIVER_LIST diff --git a/src/gfx.c b/src/gfx.c index a6abfc6..6036170 100644 --- a/src/gfx.c +++ b/src/gfx.c @@ -71,7 +71,7 @@ void drawing_mode(int mode, BITMAP *pattern, int x_anchor, int y_anchor) } - +#if 0 /* set_blender_mode: * Specifies a custom set of blender functions for interpolating between * truecolor pixels. The 24 bit blender is shared between the 24 and 32 bit @@ -130,7 +130,7 @@ void set_blender_mode_ex(BLENDER_FUNC b15, BLENDER_FUNC b16, BLENDER_FUNC b24, B _blender_alpha = a; } - +#endif /* xor_mode: @@ -233,8 +233,10 @@ void set_palette_range(AL_CONST PALETTE p, int from, int to, int vsync) for (c=from; c<=to; c++) { _current_palette[c] = p[c]; +#if 0 if (_color_depth != 8) palette_color[c] = makecol(_rgb_scale_6[p[c].r], _rgb_scale_6[p[c].g], _rgb_scale_6[p[c].b]); +#endif } _current_palette_changed = 0xFFFFFFFF & ~(1<<(_color_depth-1)); @@ -271,12 +273,14 @@ void select_palette(AL_CONST PALETTE p) _current_palette[c] = p[c]; } +#if 0 if (_color_depth != 8) { for (c=0; ctruecolor. */ @@ -342,7 +346,7 @@ static int *palette_expansion_table(int bpp) /* this has to be called through a function pointer, so MSVC asm can use it */ int *(*_palette_expansion_table)(int) = palette_expansion_table; - +#endif /* generate_332_palette: @@ -408,7 +412,7 @@ void get_palette_range(PALETTE p, int from, int to) } - +#if 0 /* fade_interpolate: * Calculates a palette part way between source and dest, returning it * in output. The pos indicates how far between the two extremes it should @@ -1570,3 +1574,4 @@ void _soft_arc(BITMAP *bmp, int x, int y, fixed ang1, fixed ang2, int r, int col release_bitmap(bmp); } +#endif diff --git a/src/graphics.c b/src/graphics.c index 7608fb7..3fd85c5 100644 --- a/src/graphics.c +++ b/src/graphics.c @@ -57,10 +57,12 @@ int _color_conv = COLORCONV_TOTAL; /* which formats to auto convert? */ static int color_conv_set = FALSE; /* has the user set conversion mode? */ int _palette_color8[256]; /* palette -> pixel mapping */ +#if 0 int _palette_color15[256]; int _palette_color16[256]; int _palette_color24[256]; int _palette_color32[256]; +#endif int *palette_color = _palette_color8; @@ -305,10 +307,12 @@ void set_color_depth(int depth) switch (depth) { case 8: palette_color = _palette_color8; break; +#if 0 case 15: palette_color = _palette_color15; break; case 16: palette_color = _palette_color16; break; case 24: palette_color = _palette_color24; break; case 32: palette_color = _palette_color32; break; +#endif default: ASSERT(FALSE); } } @@ -430,7 +434,6 @@ GFX_VTABLE *_get_vtable(int color_depth) if (vt) { LOCK_DATA(vt, sizeof(GFX_VTABLE)); - LOCK_CODE(vt->draw_sprite, (long)vt->draw_sprite_end - (long)vt->draw_sprite); LOCK_CODE(vt->blit_from_memory, (long)vt->blit_end - (long)vt->blit_from_memory); return vt; } @@ -439,7 +442,6 @@ GFX_VTABLE *_get_vtable(int color_depth) for (i=0; _vtable_list[i].vtable; i++) { if (_vtable_list[i].color_depth == color_depth) { LOCK_DATA(_vtable_list[i].vtable, sizeof(GFX_VTABLE)); - LOCK_CODE(_vtable_list[i].vtable->draw_sprite, (long)_vtable_list[i].vtable->draw_sprite_end - (long)_vtable_list[i].vtable->draw_sprite); LOCK_CODE(_vtable_list[i].vtable->blit_from_memory, (long)_vtable_list[i].vtable->blit_end - (long)_vtable_list[i].vtable->blit_from_memory); return _vtable_list[i].vtable; } @@ -840,11 +842,13 @@ static int _set_gfx_mode(int card, int w, int h, int v_w, int v_h, int allow_con gui_mg_color = 8; gui_bg_color = 0; } +#if 0 else { gui_fg_color = makecol(0, 0, 0); gui_mg_color = makecol(128, 128, 128); gui_bg_color = makecol(255, 255, 255); } +#endif if (_al_linker_mouse) _al_linker_mouse->set_mouse_etc(); diff --git a/src/misc/modex.c b/src/misc/modex.c index db01fea..c900076 100644 --- a/src/misc/modex.c +++ b/src/misc/modex.c @@ -58,29 +58,29 @@ static GFX_VTABLE __modex_vtable = NULL, NULL, NULL, - _x_getpixel, - _x_putpixel, - _x_vline, - _x_hline, - _x_hline, - _normal_line, - _fast_line, - _normal_rectfill, - _soft_triangle, - _x_draw_sprite, - _x_draw_sprite, - _x_draw_sprite_v_flip, - _x_draw_sprite_h_flip, - _x_draw_sprite_vh_flip, - _x_draw_trans_sprite, + NULL, //_x_getpixel, + NULL, //_x_putpixel, + NULL, //_x_vline, + NULL, //_x_hline, + NULL, //_x_hline, + NULL, //_normal_line, + NULL, //_fast_line, + NULL, //_normal_rectfill, + NULL, //_soft_triangle, + NULL, //_x_draw_sprite, + NULL, //_x_draw_sprite, + NULL, //_x_draw_sprite_v_flip, + NULL, //_x_draw_sprite_h_flip, + NULL, //_x_draw_sprite_vh_flip, + NULL, //_x_draw_trans_sprite, NULL, - _x_draw_lit_sprite, - _x_draw_rle_sprite, - _x_draw_trans_rle_sprite, + NULL, //_x_draw_lit_sprite, + NULL, //_x_draw_rle_sprite, + NULL, //_x_draw_trans_rle_sprite, NULL, - _x_draw_lit_rle_sprite, - _x_draw_character, - _x_draw_glyph, + NULL, //_x_draw_lit_rle_sprite, + NULL, //_x_draw_character, + NULL, //_x_draw_glyph, _x_blit_from_memory, _x_blit_to_memory, _x_blit_from_memory, @@ -88,30 +88,30 @@ static GFX_VTABLE __modex_vtable = _x_blit, _x_blit_forward, _x_blit_backward, - _blit_between_formats, - _x_masked_blit, + NULL, //_blit_between_formats, + NULL, //_x_masked_blit, _x_clear_to_color, - _pivot_scaled_sprite_flip, + NULL, //_pivot_scaled_sprite_flip, NULL, /* AL_METHOD(void, do_stretch_blit, (struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int masked)); */ - _soft_draw_gouraud_sprite, - _x_draw_sprite_end, + NULL, //_soft_draw_gouraud_sprite, + NULL, //_x_draw_sprite_end, _x_blit_from_memory_end, - _soft_polygon, - _soft_rect, - _soft_circle, - _soft_circlefill, - _soft_ellipse, - _soft_ellipsefill, - _soft_arc, - _soft_spline, - _soft_floodfill, - - _soft_polygon3d, - _soft_polygon3d_f, - _soft_triangle3d, - _soft_triangle3d_f, - _soft_quad3d, - _soft_quad3d_f + NULL, //_soft_polygon, + NULL, //_soft_rect, + NULL, //_soft_circle, + NULL, //_soft_circlefill, + NULL, //_soft_ellipse, + NULL, //_soft_ellipsefill, + NULL, //_soft_arc, + NULL, //_soft_spline, + NULL, //_soft_floodfill, + + NULL, //_soft_polygon3d, + NULL, //_soft_polygon3d_f, + NULL, //_soft_triangle3d, + NULL, //_soft_triangle3d_f, + NULL, //_soft_quad3d, + NULL //_soft_quad3d_f }; diff --git a/src/vtable8.c b/src/vtable8.c index ff57e5d..4d7320a 100644 --- a/src/vtable8.c +++ b/src/vtable8.c @@ -38,29 +38,29 @@ GFX_VTABLE __linear_vtable8 = NULL, NULL, NULL, - _linear_getpixel8, - _linear_putpixel8, - _linear_vline8, - _linear_hline8, - _linear_hline8, - _normal_line, - _fast_line, - _normal_rectfill, - _soft_triangle, - _linear_draw_sprite8, - _linear_draw_sprite8, - _linear_draw_sprite_v_flip8, - _linear_draw_sprite_h_flip8, - _linear_draw_sprite_vh_flip8, - _linear_draw_trans_sprite8, + NULL, //_linear_getpixel8, + NULL, //_linear_putpixel8, + NULL, //_linear_vline8, + NULL, //_linear_hline8, + NULL, //_linear_hline8, + NULL, //_normal_line, + NULL, //_fast_line, + NULL, //_normal_rectfill, + NULL, //_soft_triangle, + NULL, //_linear_draw_sprite8, + NULL, //_linear_draw_sprite8, + NULL, //_linear_draw_sprite_v_flip8, + NULL, //_linear_draw_sprite_h_flip8, + NULL, //_linear_draw_sprite_vh_flip8, + NULL, //_linear_draw_trans_sprite8, NULL, - _linear_draw_lit_sprite8, - _linear_draw_rle_sprite8, - _linear_draw_trans_rle_sprite8, + NULL, //_linear_draw_lit_sprite8, + NULL, //_linear_draw_rle_sprite8, + NULL, //_linear_draw_trans_rle_sprite8, NULL, - _linear_draw_lit_rle_sprite8, - _linear_draw_character8, - _linear_draw_glyph8, + NULL, //_linear_draw_lit_rle_sprite8, + NULL, //_linear_draw_character8, + NULL, //_linear_draw_glyph8, _linear_blit8, _linear_blit8, _linear_blit8, @@ -68,30 +68,30 @@ GFX_VTABLE __linear_vtable8 = _linear_blit8, _linear_blit8, _linear_blit_backward8, - _blit_between_formats, - _linear_masked_blit8, + NULL, //_blit_between_formats, + NULL, //_linear_masked_blit8, _linear_clear_to_color8, - _pivot_scaled_sprite_flip, + NULL, //_pivot_scaled_sprite_flip, NULL, // AL_METHOD(void, do_stretch_blit, (struct BITMAP *source, struct BITMAP *dest, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int dest_width, int dest_height, int masked)) - _soft_draw_gouraud_sprite, - _linear_draw_sprite8_end, + NULL, //_soft_draw_gouraud_sprite, + NULL, //_linear_draw_sprite8_end, _linear_blit8_end, - _soft_polygon, - _soft_rect, - _soft_circle, - _soft_circlefill, - _soft_ellipse, - _soft_ellipsefill, - _soft_arc, - _soft_spline, - _soft_floodfill, + NULL, //_soft_polygon, + NULL, //_soft_rect, + NULL, //_soft_circle, + NULL, //_soft_circlefill, + NULL, //_soft_ellipse, + NULL, //_soft_ellipsefill, + NULL, //_soft_arc, + NULL, //_soft_spline, + NULL, //_soft_floodfill, - _soft_polygon3d, - _soft_polygon3d_f, - _soft_triangle3d, - _soft_triangle3d_f, - _soft_quad3d, - _soft_quad3d_f + NULL, //_soft_polygon3d, + NULL, //_soft_polygon3d_f, + NULL, //_soft_triangle3d, + NULL, //_soft_triangle3d_f, + NULL, //_soft_quad3d, + NULL, //_soft_quad3d_f }; -- 2.11.0 1oom-1.11.2/doc/ext/fontdump.asm000066400000000000000000000020011476061725400163570ustar00rootroot00000000000000; dumps VGA 8x8 font to "r.bin" ; written in nasm syntax ; nasm -o fontdump.com fontdump.asm org 100h ; code starts at offset 100h use16 ; use 16-bit code ; get pointer to ROM font mov ax,1130h mov bh,03h ; 8x8 font int 10h ; es:bp -> ROM font ; save ROM font to file push es mov dx,filename ; ds:dx -> filename xor cx,cx ; normal attributes mov ah,3ch ; create file int 21h jc fail ; cf = 1 = error mov bx,ax ; bx = output file handle mov cx,2048 ; cx = output size mov dx,bp pop ds ; ds:dx -> data mov ah,40h ; write to file int 21h jc fail ; cf = 1 = error cmp ax,cx ; ax = cx -> write ok jne fail mov ah,3eh ; close file, bx = outputfile handle int 21h mov al,0 jnc exit ; cf = 1 = error fail: mov al,1 exit: mov ah,4ch int 21h ; data filename db 'r.bin',0 1oom-1.11.2/doc/format_gam.txt000066400000000000000000000307201476061725400161070ustar00rootroot00000000000000MOO1 .gam file format All offsets are hex. All values are little endian unless otherwise noted. Some values are recalculated before they are used. save game file (0xe69c) offset sz description 0 0xb8*0x6c planet data 4da0 0x1c*0x104 fleets enroute to planets 6a10 0x12*0x64 transports enroute to planets 7118 0xdd4*6 empire/tech/orbitfleet data ( +0 0x332 empire data +332 0x60 tech data +392 0x10 empire data (cont) +3a2 0x18*0x6c fleet at orbit data +dc2 0x12 empire data (cont) ) c410 0x468*6 ship design and research de80 0x336 game events e1b6 2 num fleets enroute e1b8 2 num transports enroute e1ba 15*6 emperor names e232 2 year (0 -> 2299) e234 2 ? always 1, never used e236 2 selected planet e238 2 nebula_num : galaxy_size -> 0..1, 1..3, 2..3, 2..4 e23a 2*4 nebula_type : rnd_1_n(10)-1 e242 2*4 nebula x : rnd_1_n(galaxy maxx - 0x46)+4 e24a 2*4 nebula y : rnd_1_n(galaxy maxy - 0x46)+4 e252 2*4*4 nebula x0 tbl e272 2*4*4 nebula x1 tbl e292 2*4*4 nebula y0 tbl e2b2 2*4*4 nebula y1 tbl e2d2 2 players e2d4 2 difficulty (0..4) e2d6 2 galaxy stars e2d8 2 galaxy size (0..3) e2da 2 galaxy w (6 8 a c) e2dc 2 galaxy h (4 6 7 9) e2de 2 galaxy maxx : (w-1) * 0x1c + 0x14 e2e0 2 galaxy_maxy : (h-1) * 0x20 + 0x10 e2e2 2*0x6c seen owner e3ba 2*0x6c seen pop e492 2*0x6c seen bases e56a 2*0x6c seen factories e642 0x44 current ship design e686 2 end : 0=none, 1=exile, 2=won, 3=final war e688 2 winner (0..5) e68a 2 guardian killer (player id or 1000) e68c 2 election held : 0/1 e68e 0xe have new ships: bool vector with 1 bit per planet planet data (0xb8) offset sz description 0 12 name c 2 xpos e 2 ypos 10 2 star type (0..5) 12 2 look (0, 6) 14 2 frame (0..49) 16 2 ? unused (0..4?) 18 2 rocks: 0=0, 1=1..4, 2=5..7 1a 2 max pop1 (base size) 1c 2 max pop2 (base size modified by soil enrichment tech) 1e 2 max pop3 (actual population maximum) 20 2 type: 0=not habitable, 2=toxic, 3=inferno, 4=dead, 7=minimal, 8=desert, 9=steppe, 0xa=arid, 0xb=ocean, 0xd=terran 22 2 battle background (0..4): index to space.lbx (+0x1a), 0 implies planet is in nebula 24 2 infogfx: index to planets.lbx 26 2 growth: 0=hostile, 1=nothing, 2=fertile 28 2 special: 0=normal, 1=ultra poor, 2=poor, 3=artifacts, 4=rich, 5=ultra rich, 6=4xtech 2a 2 BC towards eco project 2c 2 BC towards next ship(s) 2e 2 BC towards next factory 30 4 reserve 34 2 waste 36 2 owner (0..5, 0xffff) 38 2 previous owner (0..5, 0xffff) 3a 2 population 3c 2 population on previous turn 3e 2 factories 40 2 production after maint 42 2 total production (n) 44 2*6 inbound troopers (0..300) 50 2*5 slider % (ship, def, ind, eco, tech) 5a 2 build ship (0..5, 6=star gate) 5c 2 relocation: planet index number, normally index of planet itself 5e 2 missile bases 60 2 BC towards next missile base or shield 62 2 BC to upgrade base 64 2 have stargate: 0/1 66 2 ? always 0, never used 68 2 shield (5, 10, 15, 20) 6a 2 BC towards shield 6c 2 transport number 6e 2 transport destination (planet index) 70 1 population tenths 72 2*5 slider lock 7c 2*6 explored: 0/1 88 2*6 within scanner range: 0/1 94 2*6 within fuel range: 0/1, 2=with reserve a0 2 claimed by player (0..5, 0xffff) a2 2*6 total inbound troopers ae 2 a colonist operates N factories b0 2 BC towards industy refit b2 2 rebels (0..actual pop) b4 2 unrest: 0=no, 1=unrest, 3=rebellion b6 2 unrest reported: 0/1 transports enroute entry (0x12) offset sz description 0 2 owner (0 - 5, -1) 2 2 x 4 2 y 6 2 destination as planetary index number 8 2 population a 1*6 visible flag ; player N can see the transport 10 1 speed 11 1 ? always 0, never used fleet enroute entry (0x1c) offset sz description 0 2 owner (0 - 5, -1) 2 2 x 4 2 y 6 2 destination as planetary index number 8 1 speed 9 1 ? always 0, never used a 2*6 ship counts for 6 ship types 16 1*6 visible flag ; player N can see the fleet fleet at orbit entry (0x18) offset sz description 0 2*6 visible flag ; player N can see the fleet c 2*6 ship counts for 6 ship types empire data (0xdd4) offset sz description 0 2 race (0=human, 1=mrrshan, 2=silicoid, 3=sakkra, 4=psilon, 5=alkari, 6=klackon, 7=bulrathi, 8=meklar, 9=darlok) 2 2 banner (0=blue, 1=green, 2=purple, 3=red, 4=white, 5=yellow) 4 2 trait1 (0..5) 6 2 trait2 (0..5) 8 2 AI turn p3 countdown (0..6) a 2 AI turn p2 countdown (0..20) c 2*6 empire within contact range: 0/1 18 2*6 relation1 (init from relation2) 24 2*6 relation2 (init from exe table * c) 30 2*6 diplo type: ... 3c 2*6 diplo value 48 2*6 diplo param 1 (depends on type ; planet index or 0) 54 2*6 diplo param 2 (depends on type) 6c 2*6 trust 78 2*6 broken treaty 84 2*6 diplomatic blunder (0 = none, diplomat.lbx message type) 90 2*6 tribute tech field 9c 2*6 tribute tech a8 2*6 mood for treaty (non-aggression or alliance) b4 2*6 mood for trade c0 2*6 mood for tech trade cc 2*6 mood for peace treaty d8 2*6 treaty: 0=no, 1=non-aggression, 2=alliance, 3=war, 4=final war e4 2*6 trade (bc/year) f0 2*6 trade percent ( ..100) fc 2*6 AI next spy mode: 0=hide, 1=espionage, 2=sabotage 108 2*6 ? 114 2*6 ? 120 2*6 ? 138 2*6 audience; tech trade num 144 2*6*6 audience; tech trade field 18c 2*6*6 audience; tech trade tech 1d4 2*6 incentive offer tech field 1e0 2*6 incentive offer tech 1ec 2*6 incentive offer BC 1f8 2*6 audience; attacker of ally 204 2*6 audience; ask break treaty with 210 2*6 ? 21c 2*6 attack bounty on player 228 2*6 bounty collect for player (0/1) 234 2*6 attack gift tech field 240 2*6 attack gift tech 24c 2*6 attack gift BC 258 2*6 ? 264 2*6 ? 270 2*6 hatred 27c 2*6 have met (0=no, 1=just, 2=introduced) 288 2*6 established trade BC 294 2*6 ? 2a0 2 have planetary shield tech (0, 5, 10, 15, 20) 2a4 2*6 spying percent in tenths 2b0 2*6 spy fund left over after creating new spies 2bc 2*6 ? 2c8 2*6 spy mode: 0=hide, 1=espionage, 2=sabotage 2d4 2 Security percentage in tenths 2d6 2*6 spies 2e2 2 Trade BC 2e4 2 Ship maint BC 2e6 2 Bases maint BC 2ec 2 Spying maint BC 2ee 2 Percentage to convert total production to actual 2f0 4 Total maint BC (can be negative) 2f8 4 Total empire production BC 2f4 4 total reseach BC 2fc 4 Reserve BC 300 2 tax in tenths (0..200) 302 2 best base shield 304 2 best base computer 306 2 best base weapon 308 2 have sub space interdictor 30a 2 antidote (0, 1, 2) 30c 2 have colony tech for planet type N 310 2 have eco restoration N (2, 3, 5, 10, 20) 310 2 have terraform +N 312 2 terraform cost per increase of 1 314 2 have adv soil enrich 316 2 have atmos terraforming 318 2 have soil enrich 31a 2 cost to increase pop by 1 31e 2 have improved or advanced scanner 320 2 have advanced scanner 322 2 have hyperspace comm 324 2 have stargates 326 2 a colonist operates N factories 32c 2 industrial waste scale (0, 2, 4, .. 10) 32e 2 fuel range (3..10, 30) 330 2 have combat transporter (332 0x6c tech data) 39e 2 have engine 3a0 2 number of ship designs (3a2 0x1c*0x6c fleet at orbit data) dc2 2*6 spy report for each field dce 2 spy report year dd0 2 AI: colony ship index (or -1) dd2 2 AI: bomber ship index (or -1) tech data (0x6c) offset sz description 0 2*6 Tech level %; Comp/Const/FF/Plan/Prop/Weap c 2*6 Tech slider percentage for 6 fields 18 4*6 Current research investment in project in 6 fields 30 2*6 Tech level of current research project in 6 fields 3c 4*6 Full tech cost of current project in 6 fields 54 2*6 Number of completed projects (including level 1) in 6 fields 60 2*6 Tech slider lock for 6 fields ships and research data (0x468) offset sz description 0 0x44*6 ship design 0..5 198 12*12 ship name list 228 3*10*6 Limited Research List; 3 bytes per tier, 10 tiers per field, 6 fields 2dc 60*6 completed research; 60 bytes per field (see tech data offs 54 above for number active) 444 2*6 have reserve fuel 450 2*6 year of the design (AI only) 45c 2*6 total ship count ship design (0x44) offset sz description 0 12 name c 8 ? unused 14 2 ship cost 16 2 space 18 2 hull size (0..3) 1a 2 look (0..152?) 1c 2*4 weapon type (0..63) 24 2*4 weapon num 2c 2 engine (0..8) 2e 4 number of engines 32 2*3 special type (0..31) 38 2 shield (0..11) 3a 2 jammer (0..10) 3c 2 computer (0..11) 3e 2 armor (0..13) 40 2 speed (0..8?) 42 2 hit points ship name list (0x90) offset sz description 0 12*12 names game events (0x336 at 0xde80) offset sz description 0 2 year of last event 2 2 ? always 30, never used 4 2*20 event has happened (0/1) 2c 2 have plague (0..3) 2e 2 plague player 30 2 plague planet 32 2 plague value 34 2 have quake event (0/1) 36 2 quake player 38 2 quake planet 3a 2 have nova (0..3) 3c 2 nova player 3e 2 nova planet 40 2 nova years 42 2 nova value 44 2 have accident (0..2) 46 2 accident player 48 2 accident planet 4a 2 have assassination attempt (0/1) 4c 2 assassination player2 4e 2 assassination player 50 2 have virus (0/1) 52 2 virus player 54 2 virus tech field 56 2 have comet (0..3) 58 2 comet player 5a 2 comet planet 5c 2 comet years 5e 2 comet HP 60 2 comet damage 62 2 have pirates (0..3) 64 2 ? 66 2 pirates planet 68 2 pirates HP 6a 2 have derelict event (0/1) 6c 2 derelict player 6e 2 crystal exists (0..3) 70 2 crystal x 72 2 crystal y 74 2 crystal counter 76 2 crystal killer (0 or killer_player_id+1) 78 2 crystal dest 7a 2 crystal number of destroyed planets 7c 2 amoeba exists (0..3) 7e 2 amoeba x 80 2 amoeba y 82 2 amoeba counter 84 2 amoeba killer (0 or killer_player_id+1) 86 2 amoeba dest 88 2 amoeba number of destroyed planets 8a 2 have environment event (0/1) 8c 2 environment planet 8e 2 have rich event (0/1) 90 2 rich planet 92 2 have support BC event (0/1) 94 2 support player 96 2 have poor event (0/1) 98 2 poor planet 9a 2 have orion conqueror (0 or player_id+1) 9c 2 orion planet index 9e 2 have guardian a0 2*6 home planet index (-1, 0..107 ; -1 means player is dead) ac 2 report star colonization status (0..4) ae ? ? ec 2 coup player (-1, 0..5) ee 2 new tech num f0 2*15 new tech field 10e 2*15 new tech tech index 12c 2*15 new tech source (0=research, 1=spy, 2=found, 3=choose/AI spy, 4=trade) 14a 2*15 new tech val1 : giver race or source planet ruins (>0) or artifact planet (<0) or -1000 for Orion 168 2*15 new tech val2 : race stolen from 186 2*15 new tech can frame (0/1) 1a4 2*6 new ships 1f2 2*6 spies caught (my) 1fe 2*6 spies caught (their) 28e 2*6 ceasefire (years) 2e2 20 help show (0/1 * 20) 2f6 2 build finished number (0..20) 2f8 20 build finished planet index 30c 20 build finished type: 0=?, 1=eco1, 2=eco2, 3=? 320 2*6 voted for (-1, 0..5) 32c 2 best eco restore 32e 2 best waste reduce 332 2 best robotic control 334 2 best terraform 1oom-1.11.2/doc/format_lbx.txt000066400000000000000000000174411476061725400161350ustar00rootroot00000000000000MOO1 .lbx file format All offsets are hex. All values are little endian unless otherwise noted. offset sz description 0 2 number of entries 2 2 ID: 0xad 0xfe 4 2 0x00 0x00 6 2 type - 0: gfx - 1: sound (introsnd.lbx, music.lbx, snddrv.lbx) - 2: fonts, palette (fonts.lbx) - 3: data table (help.lbx) - 5: data table (firing.lbx, research.lbx, ...) 8+4*I 4 offset to item I data start (data ends at next I start) 200+20*I 32 name/description of item I gfx format offset sz description 0 2 width 2 2 height 4 2 frame (current: 0 in file) 6 2 frames 8 2 set current frame to this when frame == frames (0, frames-1...) a 1 0x00 (runtime: emm handle) b 1 0x00 (runtime: emm page) c 2 0x0000 (runtime: ?) e 2 offset to palette (or 0 if none) 10 1 independent frames : 0x00/0x01 (if 0 then need to draw frames 0..n-1 before n) 11 1 gfx format ; 0x00 except council.lbx i1 == 0x01 12+4*I 4 offset to frame I data start (data ends at next I start) frame data offset sz description 0 1 (unused) if 0: overlay on previous frame ; 1: clear buffer 1.. ? columnwise pixel data - 0xff: skip this column - 0x00: uncompressed: - total_len - part_len, skip_pixels, pixel*part_len - v=geti(); puto(v, 1); - 0x80: compressed: - total_len - part_len, skip_pixels, compressed_data*part_len - v=geti(); if (v>223) { len=v-223; v=geti(); } else { len=1; } ; puto(v, len); - puto(v, len) - format 0 - while (len--) { put_pixel(x, y, v); ++y } - format 1 - if (v>=0xe8) { tbl = lut[v-0xe8]; while (len--) { v = tbl[get_pixel(x, y)]; put_pixel(x, y, v); ++y; } } else { while (len--) { put_pixel(x, y, v); ++y } } palette metadata offset sz description 0 2 offset to palette data (from gfx data start) 2 2 first changed color 4 2 number of changed colors 6 2 ? 0x00 0x00 (offset points to 8...) palette data offset sz description 3*N 3 RGB palette values (6bpp per item) fonts.lbx entry 0 : the fonts (max 8, only 6 exist) offset sz description 0 16 palette indices (copied runtime from active palette) 10 2 font height (copied runtime from selected font from offset 0x16a + active_font * 2) 12 1 ? 0 (set runtime from selected font) 13 1 active font colors 14 16 font colors 0 (palette indices, copied runtime from active palette), same as offset 0 24 16 font colors 1 (copied runtime from active palette) 34 16 font colors 2 (copied runtime from active palette) 44 2 line height (copied runtime from selected font, offset 0x10 + offset 0x46) 46 2 gap height (copied runtime from selected font from offset 0x18a + active_font * 2) 48 2 gap width (copied runtime from selected font from offset 0x17a + active_font * 2) 4a 0x60 character c-0x20 width (copied runtime from selected font from offset 0x19a + active_font * 0x60) aa 0xc0 character c-0x20 data offset (copied runtime from selected font from offset 0x49a + active_font * 0xc0) a9d.. ? columnwise pixel data - 0b0hhhiiii: h pixels with color from offset i - 0b1sssssss: skip s lines - 0b10000000: next column fonts.lbx entries 2..12: the palettes (size 0x1560) offset sz description 0 256*3 RGB palette values (6bpp per item) 300 16*16 palette indices for fonts 400 256 ? (unused) 500 0x1000 cursor data: 16*16 pix * 16 cursors, columnwise 1500 4*0x18 color table generation parameters : r g b percent data table: (research.lbx, firing.lbx, ...) offset sz description 0 2 item num N 2 2 item size S 4 N*S data research.lbx entry 0: (0x70c) offset sz description 0 2 item num 0x12c == 6*50 2 2 item size 6 4 6*50*6 tech data tech data: (size 6) offset sz description 0 1 tech group (0xff for tech does not exist) 1 1 index to tech table (tbl_shiptech_weap etc) 2 2 index to techno.lbx 4 2 name: offset to research.lbx entry 1 data research.lbx entry 1: offset sz description 0 2 item num 1 2 2 item size 0xf3c 4 .. "Tech 1 name\0Tech 2 name\0" ... firing.lbx: (0x1018) offset sz description 0 2 item num N = 0x93 = ship looks 2 2 item size S = 0x1c 4 N*S u16 tbl[ship_look][0xe] firing.lbx table entry: (0x1c) offset sz description 0 2 x0 forward 2 2 y0 forward 4 2 x1 forward 6 2 y1 forward 8 2 x2 forward a 2 y2 forward c 2 x0 behind e 2 y0 behind 10 2 x1 behind 12 2 y1 behind 14 2 x2 behind 16 2 y2 behind 18 2 target x 1a 2 target y diplomat.lbx entry 0: amount of audience messages per type offset sz description 0 2 item num N = 81 2 2 item size S = 2 4 N*S number of message variations in lbx entry 1 (0..15) diplomat.lbx entry 1: audience messages offset sz description 0 2 item num N = 1215 2 2 item size S = 0xc8 4 N*S char str[S - 2 * 2], u16 gfx_index, u16 mus_index 15 variations per message type characters with MSb set are tokens for race name, BC amount etc eventmsg.lbx entry 0: news messages offset sz description 0 2 item num N = 154 2 2 item size S = 0xc8 4 N*S char str[S] 7 variations per message type characters with MSb set are tokens for race name, BC amount etc names.lbx entry 0: () offset sz description 0 2 num entries (60) 2 2 entry size (20) 4 6*10*20 the names help.lbx entry 0: help offset sz description 0 2 item num N = 0x28 2 2 item size S = 0x5f8 4 N*S help item help.lbx entry 0: help item (size 0x5f8) offset sz description 0 16 filename ("MAINMOVE.FLI") ; unused 10 2 ? if < 3 uses string table 12 26 description ; unused 2c 12*2 x 44 12*2 y 5c 12*2 width 74 12*2 line x 8c 12*2 line y a4 12*2 line type : 0=none,1=?,2=? bc 40 text string 0 e4 314 text string 1 21e 40 text string 2 ; used if offs 0x10 >= 3 246 314 text string 3 ; used if offs 0x10 >= 3 380 9*70 text string table ; used if offs 0x10 < 3 5f6 2 next help item to display (or 0 for none) sound data offset sz description 0 16 0xaf 0xde 0x02 0x00 .. ("deaf 2"?) 0x10 ? VOC music data (XMI) http://www.shikadi.net/wiki/modding/index.php?title=XMI_Format&oldid=6874 offset sz description 0 16 0xaf 0xde 0x01 0x00 .. ("deaf 1"?) 10 4 "FORM" 14 4BE length 0xe 18 4 "XDIR" 1c 4 "INFO" 20 4BE length 0x2 24 2 number of songs (1) 26 4 "CAT " 2a 4BE length rest_of_data 2e 4 "XMID" 32 4 "FORM" 36 4BE length rest_of_data 3a 4 "XMID" 3e 4 "TIMB" 42 4BE length of timbre data = T 46 T timbre data: - u16 entry count - patch number, bank number 46+T 4 "EVNT" 4a+T 4BE length of event data = E 4e+T E event data: MIDI-ish, but - delta times are mostly missing - delta times are series of 0x7f bytes, with the time as sum of them - note off events are missing! - note on events have 3rd parameter byte that indicates duration - can be multibyte; duration is concatenation of "byte & 0x7f"s 1oom-1.11.2/doc/format_moo.txt000066400000000000000000000011751476061725400161370ustar00rootroot00000000000000MOO1 config.moo file format All offsets are hex. All values are little endian unless otherwise noted. config.moo file (0x9a) offset sz description 0 2 music card 2 2 music port 4 2 music IRQ 6 2 music ? 8 2 SFX card a 2 SFX port c 2 SFX IRQ e 2 SFX DMA 10 2 0=silent, 1=fx only, 2=music+fx 12 2 0=keyboard only, 1=mouse 14 2 game options : galaxy_size*10 + difficulty + opponents*100 16 2*6 have save : 0/1 22 0x14*6 save name 1oom-1.11.2/doc/format_pbx.txt000066400000000000000000000024761476061725400161430ustar00rootroot000000000000001oom PBX file format All offsets and sizes are hex. All values are little endian unless otherwise noted. PBX header offset sz description 0 8 magic header "1oomPBX " 8 4 version (== 1) c 4 number of items 10+I*4 4 PBX item I offset PBX item offset sz description 0 4 length of item 4 2 type of item - 0: PBX name - 1: PBX description - 2: LBX patch - 3: string patch - 4: number patch - 5: LBX partial overwrite 6 2 item index - 2, 5: LBX item number to patch - 3: string table index - 4: number table index 8 14 item ID - 0: "PBX NAME" - 1: "PBX DESC" - 2, 5: LBX file to patch, lowercase (f.ex "ships.lbx") - 3: string ID - 4: number ID 20 length data - 0: ASCII - 1: ASCII - 2: data - 3: ASCII / MOO1 - 4: 32 bit number, little endian - 5: 32 bit offset + data (length - 4 bytes) 1oom-1.11.2/doc/format_save.txt000066400000000000000000000211231476061725400162760ustar00rootroot000000000000001oom save file format version 0 All offsets and sizes are hex. All values are little endian unless otherwise noted. Save header (0x40 bytes) offset sz description 0 8 magic header "1oomSAVE" 8 4 version (== 0) c 4 (0, unused) 10 14 save name 24 1c (0, unused) Save payload (? bytes) offset sz description 40 1 number of players: @PLAYERS (2..6) 41 1 player is AI (bitmask) 42 1 player refused council ruling (bitmask) 43 1 AI type ID 44 3 (0, unused) 47 1 active player when save was made 48 1 difficulty (0..4) 49 1 galaxy size (0..3) 4a 1 galaxy width 4b 1 galaxy height 4c 1 galaxy stars; @STARS (width * height; 24, 48, 70, 108) 4d 2 galaxy max x 4f 2 galaxy max y 51 4 galaxy seed 55 4 current RNG seed 59 2 year (add 2299 for shown year) 5b 2 number of fleets enroute: @FLEETS 5d 2 number of transports enroute: @TRANSPORTS 5f 1 end state: 0=none, 3=final war 60 1 election winner (0..5, 6) 61 1 election held (0/1) 62 1 nebula num: @NEBULAS (0..4) (The rest of payload uses variable length tables and thus have no constant offsets. The description is thus a bit different from the other format_*.) Nebula data (N = @NEBULAS) sz description N*2 nebula x N*2 nebula y N*4*2 nebula x0 N*4*2 nebula x1 N*4*2 nebula y0 N*4*2 nebula y1 @PLAYERS * Emperor name sz description 15 emperor name (ASCIIz) @PLAYERS * Planet focused on sz description 1 selected planet index @STARS * Star data sz description c name (ASCIIz) 2 x 2 y 1 star type (0..5) 1 look (0, 6) 1 frame (0..49) 1 rocks: 0=0. 1=1..4, 2=5..7 2 max pop1 (base size) 2 max pop2 (base size modified by soil enrichment tech) 2 max pop3 (actual population maximum) 1 planet type: 0=not habitable, 1=radiated, 2=toxic, 3=inferno, 4=dead, 5=tundra, 6=barren, 7=minimal, 8=desert, 9=steppe, a=arid, b=ocean, c=jungle, d=terran, e=gaia 1 battle background (0..4): index to space.lbx (+0x1a), 0 implies planet is in nebula 1 infogfx: index to planets.lbx 1 growth: 0=hostile, 1=nothing, 2=fertile 1 special: 0=normal, 1=ultra poor, 2=poor, 3=artifacts, 4=rich, 5=ultra rich, 6=4xtech 2 BC towards eco project 2 BC towards next ship(s) 2 BC towards next factory 4 reserve 2 waste 1 owner (0..5, 6) 1 previous owner (0..5, 6) 1 claimed by player (0..5, 6) 2 population 2 population on previous turn 2 factories 5*2 slider % (ship, def, ind, eco, tech) 5*1 slider lock (0/1) 1 build ship (0..5, 6=star gate) 1 relocation: planet index number, normally index of planet itself 2 missile bases 2 BC towards next missile base or shield 2 BC to upgrade base 1 have stargate (0/1) 1 shield (5, 10, 15, 20) 2 BC towards shield 2 transport number ; population to transport 1 transport destination (planet index) 1 population tenths 1 explored by player (bitmask) 1 player fleet unrefueled (bitmask) 4 (0, unused) 1 a colonist operates N factories 2 BC towards industy refit 2 rebels (0..actual pop) 1 unrest: 1=unrest, 3=rebellion 1 unrest reported (0/1) 1 build finished (bitmask; bits: 0=factories, 1=eco1, 2=eco2, 3=stargate, 4=shield, 5=ship) 5 (0, unused) @PLAYERS * @STARS * Seen data sz description 1 owner (0..5, 6) 2 population 2 missile bases 2 factories @FLEETS * Fleet enroute data sz description 1 owner (0..5, 6) 2 x 2 y 1 destination as planetary index number 1 bits 6..0: speed, bit 7: retreat 6*2 number of ships @TRANSPORTS * Transport data sz description 1 owner (0..5, 6) 2 x 2 y 1 destination as planetary index number 1 speed 2 population @PLAYERS * Empire/tech/orbit data (N = @PLAYERS) sz description 1 race (0=human, 1=mrrshan, 2=silicoid, 3=sakkra, 4=psilon, 5=alkari, 6=klackon, 7=bulrathi, 8=meklar, 9=darlok) 1 banner (0=blue, 1=green, 2=purple, 3=red, 4=white, 5=yellow) 1 trait1 (0..5) 1 trait2 (0..5) 1 AI turn p3 countdown (0..6) 1 AI turn p2 countdown (0..20) 1 in contact with empire (bitmask) 1 contact broken with empire (bitmask) 4 (0, unused) N*2 relation1 N*2 relation2 N*1 diplo type: ... N*2 diplo value N*2 diplo param 1 (depends on type) N*2 diplo param 2 (depends on type) N*2 trust N*1 broken treaty N*2 diplomatic blunder N*1 tribute tech field N*1 tribute tech N*2 mood for treaty (non-aggression or alliance) N*2 mood for trade N*2 mood for tech trade N*2 mood for peace treaty N*1 treaty; 0=no, 1=non-aggression, 2=alliance, 3=war, 4=final war N*2 trade BC N*2 trade percent (..100) N*1 AI next spy mode: 0=hide, 1=espionage, 2=sabotage N*1 incentive offer tech field N*1 incentive offer tech N*2 incentive offer BC N*2 if bit 0 is 0: attack gift BC ; if bit 0 is 1: bits: 15..8=tech, 4..1=field N*2 bits 11..8: attack bounty on player (0..5, 6) ; bits 3..0: bounty collect (0..5, 6) N*2 hatred N*2 have met (0=no, 1=just, 2=introduced) N*2 established trade BC N*2 spying percent in tenths N*2 spy fund left over after creating new spies N*1 spy mode: 0=hide, 1=espionage, 2=sabotage 2 security percentage in tenths N*2 spies 4 reserve BC 2 tax in tenths (0..200) 1 best base shield 1 best base computer 1 best base weapon 1 a colonist operates N factories 6*1 tech field percent ; tech level % 6*2 tech field slider % 6*1 tech field slider lock (0/1) 6*4 tech field investment 6*1 tech field project 6*4 tech field project cost 6*2 tech field number of completed projects: @TECHCOMPL 1 number of ship designs: @SHIPDNUM ? Fleet orbit list: (S = @SHIPDNUM) sz description 1 planet index I or ff=list end S*2 number of ships at planet I orbit (omitted for list end) N*6*1 spy report for each field N*2 spy report year 1 AI: colony ship index (or -1) 1 AI: bomber ship index (or -1) @PLAYERS * Ship/research data (S = @SHIPDNUM) sz description S*29 number of ship designs * Ship design: $SHIPDESIGN sz description c name 2 cost 2 space 1 hull (0..3) 1 look (0..146) 4*1 weapon type (0..63) 4*1 weapon num 1 engine (0..8) 4 number of engines 3*1 special type (0..31) 1 shield (0..11) 1 jammer (0..10) 1 computer (0..11) 1 armor (0..13) 1 speed (0..8?) 2 hit points 6*a*3 limited research list (data is tech ID) 6*3c completed research (data is tech ID; table length is @TECHCOMPL) 6*1 (0, unused) 6*2 year of ship design 6*4 (0, unused) @PLAYERS * Current ship design sz description 29 Ship design (see $SHIPDESIGN above) Event data (N = @PLAYERS) sz description 2 year of last event 3 event has happened (bitmask of 20 bits) 1 diplo message subtype (-1..13) 16 (0, unused) 1 have plague (0..3) 1 plague player 1 plague planet 4 plague value 1 have nova (0..3) 1 nova player 1 nova planet 1 nova years 4 nova value 1 have accident 1 accident planet 1 have comet (0..3) 1 comet player 1 comet planet 1 comet years 2 comet HP 2 comet damage 1 have pirates (0..3) 1 pirates planet 2 pirates HP 9 Crytal: $MONSTER sz description 1 exists (0..3) 2 x 2 y 1 killer (0..5, 6) 1 destination 1 counter 1 number of destroyed planets 9 Amoeba (see $MONSTER above) 1 Orion planet index 1 have guardian (0/1) N*1 home planet (0..107, 255 means player is dead) 1 reported stars N*6*4 number of new ships N*N*2 number of caught spies N*N*2 ceasefire (years) N*10 help shown (bitmask of 16 bits) + 14 unused bytes N*2 build finished num N*1 voted for (0..5, 6) N*1 best eco restore N*1 best waste reduce N*1 best robotic control N*1 best terraform Save footer sz description 4 magic footer "\nEnd" 1oom-1.11.2/doc/lbxmd5.txt000066400000000000000000000027321476061725400151700ustar00rootroot00000000000000a46e6ad9e8cc23893da78467d8a29e28 backgrnd.lbx fd8612f703c57d680385abdca17105d1 colonies.lbx ad4603e8a311e347a65e4d361573046a council.lbx 64984d5a57c7cf0f977233c06e5047ee design.lbx e5fc3f6f1c54765df64635922d3c136a diplomat.lbx 95d07952c2e00f5b54e195e213fd10ab embassy.lbx 1acbba8b9b9fdd613332007e8243d341 eventmsg.lbx aa75c8712b36826b12456fe677c08b54 firing.lbx 90185afbfee99bd0880975607e540906 fonts.lbx 7b6bdb4d3473bf4c92728c322cf6d990 help.lbx 9d2939f54fd0afd598540ee6cff38702 intro2.lbx bb67559b324a39c08b8499f6b644c72c intro.lbx 231249611c30549de45832c3ea3b7950 introsnd.lbx da2821237a1a6fc5e1c815165b4798ab landing.lbx 4783bf2a2a80d2271a8b765860c6d42d missile.lbx 895a69c82771681d7f03a464387503f5 music.lbx c5a389047b06046edeb3b88a52cf0ccf names.lbx cf760ca4317576017b2e639f90723966 nebula.lbx 24c92d46fa767d44ce547e7b04bfc1c2 newscast.lbx 468dece5e73d06e1b6b548f86fcde51d planets.lbx 690ab296de5d0bce8436fa5174bb7048 research.lbx 0756b968b1f10179571360aac2f6b302 screens.lbx 6eba05956be3ed6f5139bd6638920a26 ships2.lbx 7af514d3126245a4dc8a15712eed7fa5 ships.lbx 7bb71fb62fba0fef557d37ee054bbcc9 soundfx.lbx db4deda97ad23b8107762cb169f7eae0 space.lbx d2e2fa83b239ca1218f205bbe965ebea spies.lbx 59200e5ea204447bf680e681ad405b9a starmap.lbx 6f41a8fd1f736a2eba6a1ee4c1536378 starview.lbx ee9ab3ed71a6d70d614fa3a8cb857da6 techno.lbx d2bb2f627bde3ca9b7260f9961d98c6e v11.lbx 581424657fc5427ad654405c6a1d03e7 vortex.lbx c0399f0c67473874d944aebf1a5dfc88 winlose.lbx 1oom-1.11.2/doc/list_diplo_msg_types.txt000066400000000000000000000107271476061725400202340ustar00rootroot00000000000000Because of the large number of message types in diplomat.lbx, they are documented here instead of in format_lbx.txt. The different message types and numbers of variations are, in order: 0) EMPTY: 0 variations (all-0 block) 1) Accept tribute: 10 variations 2) Praise - ongoing trade: 9 variations 3) Praise - enemy-of-my-enemy: 5 variations # Warnings before declaring war 4) Warning - spying: 6 variations 5) EMPTY: 0 variations 6) Warning - sabotage: 8 variations 7) EMPTY: 0 variations 8) Warning - military buildup: 9 variations 9) Warning - destroyed ships: 12 variations 10) Warning - attacked colony: 12 variations 11) Warning - bioweapons: 7 variations 12) Warning - stop expanding: 6 variations 13) War - warning ignored: 14 variations # First contact messages for different leader personalities. # Not sure if the order is completely right. 14) First contact - Xenophobic: 4 variations 15) First contact - Ruthless: 4 variations 16) First contact - Aggressive: 4 variations 17) First contact - Erratic: 4 variations 18) First contact - Pacifist: 4 variations 19) First contact - Honrable: 5 variations 20) Ambassador unavailable (war): 4 variations 21) Ambassador unavailable (peace): 5 variations 22) Friendly greeting: 4 variations 23) Unfriendly greeting: 5 variations 24) Propose NAP: 4 variations 25) Propose alliance: 5 variations 26) Propose trade: 3 variations 27) Break alliance with other: 4 variations 28) Offer bounty: 5 variations 29) Offer tech trade: 4 variations 30) Offer peace: 6 variations 31) Reject deal: 9 variations 32) Break treaty (war of expansion): 5 variations # The diplomat rejects a deal due to bad behavior by the player 33) Reject deal - past treaties broken: 5 variations 34) Reject deal - spying: 5 variations 35) EMPTY: 0 variations 36) Reject deal - sabotage: 5 variations 37) EMPTY: 0 variations 38) Reject deal - military buildup: 5 variations 39) Reject deal - destroyed ships: 5 variations 40) Reject deal - attacked colony: 5 variations 41) Reject deal - bioweapons: 5 variations # Threatening to break treaties because of ... 42) Threat - sppying: 6 variations 43) EMPTY: 0 variations 44) Threat - sabotaging: 5 variations 45) EMPTY: 0 variations 46) Threat - military buildup: 5 variations 47) Threat - destroyed ships: 5 variations 48) Threat - attacked colony: 5 variations 49) Threat - bioweapons: 4 variations # Actually breaking treaties because of ... 50) Break - sppying: 4 variations 51) EMPTY: 0 variations 52) Break - sabotaging: 5 variations 53) EMPTY: 0 variations 54) Break - military buildup: 5 variations 55) Break - destroyed ships: 5 variations 56) Break - attacked colony: 5 variations 57) Break - bioweapons: 6 variations 58) Give bounty: 5 variations # More war declarations 59) War - final war: 9 variations 60) War - other: 6 variations 61) War - erratic: 7 variations # Accepting deals 62) Accept - NAP: 5 variations 63) Accept - alliance: 5 variations 64) Accept - trade: 5 variations 65) Accept - peace: 5 variations 66) Accept - because of tribute: 4 variations 67) Accept - declare war on other: 6 variations 68) Accept - break alliance with other: 5 variations 69) Ignore threat: 7 variations 70) Cave to threat - stop frontier war/spying: 5 variations 71) Cave to threat - give tribute: 5 variations 72) Cave to threat - give tech tribute: 5 variations 73) Player broke treaty: 6 variations 74) Ambassador recalled: 9 variations 75) No tech wanted: 6 variations 76) Request to honor alliance: 2 variations 77) Player refused request to honor alliance: 4 variations 78) Player accepted request to honor alliance: 6 variations 79) Warning - council vote: 11 variations 80) Praise - council vote: 8 variations 1oom-1.11.2/doc/list_gamediff.txt000066400000000000000000000073321476061725400165730ustar00rootroot00000000000000This is an incomplete list of game differences in comparision to v1.3. See doc/list_pbxnum.txt for optional game differences. See doc/usage_classic.txt for UI differences. Much of this file is based on the readme from the unofficial v1.40m patch. - the game makes an undo save (slot 8) on every next turn click, run with -noundo if you do not want this - the game makes yearly saves on (1oom_save_YYYY.bin) every next turn click, if allowed to with -yearsave - fleets can not be sent to the planet they are orbiting (redirecting departing fleets back to orbit is still possible) - multiple fleets sent to same destination on the same turn are combined if they have the same speed - fixed "bug" where on a given year only one scouted artifact planets gave new tech - the number of build finished messages per turn is no longer limited to 10 per category - fixed weird behaviour when space monsters attack colonized Orion - fixed AI-AI tech trades where the tech was not owned by either party - all Advanced Technology are available for research - espionage messages can show the framed or unknown race instead of always leaking the actual spy - ETA calculations take nebulas into account correctly - the discovery percentages on tech screen are no more only 1/2 of the true probability of a tech hit - Psilon leader "Zygot " name correction (extra whitespace trimmed from all names) - the AI now uses the right race and the right objective when it takes decision about where to allocate the research points - the spies you educate on the same turn against different races are no more overpriced - 8th stargate bug corrected (no ship maintenance overflow) - changes in Classic+ AI: - breaking a NAP / alliance no more positively contributes to your relations with the AIs - entering the general "threaten / break treaty" dialogue no more equals to a large temporary diplomatic penalty - cash tributes work as described in OSG instead of not at all - AI checks the correct mood variable when asked for a peace treaty - AI-AI stop war check uses the same relation value as the make treaty/trade checks instead of the last diplo message subtype - AI huge, armored ships now cannot cause a negative overflow - ignore journey length for closest in-range colony ship - do not try to send one colony ship to multiple destinations - AIs now actually take their treaties in consideration when asked to declare war on their allies - AI clears his spies' missions when succesfully threatened - AI does not blame both parties for breaking a treaty - a war sparked by capturing or destroying a colony is considered to be started by the attacker - Bulrathi orbital bombardment decisions corrected to reflect their race bonus - Alkari and Mrrshan bonus for AI-AI combat corrected to reflect their race bonus - battle AI miss chance accumulation fixed; AI is less/more optimistic about missile/beam weapon damage - battle AI checks shield halving properly, does not check for target's Oracle or any Oracle for missiles - battle AI will not retreat due to doom stack damage estimate overflow - AI does not go into panic ship building mode on planets with incoming allied fleets - AI-AI battles destroy missile bases - AI always uses one of their best engines - AI does not transfer populations from rebel systems - the game has multiplayer (only local/hotseat for now); multiplayer differences to single player: - player diplomat is always up for audience except during the final war - when asked by other player to join a treaty, a player can ask for tech to sweeten the deal from those the spies have reported to exist - each player can accept/refuse the council ruling; the final war alliances are based on refusals 1oom-1.11.2/doc/list_pbxnum.txt000066400000000000000000000260221476061725400163370ustar00rootroot00000000000000This is an incomplete list of PBX number replacements. Run with -dumpnum for the full list without explanations. (name : range, default) deterministic : 0..1, 1 - Game is deterministic. Given the same input, the outcome remains the same. Reloading a save and clicking Next turn will not get rid of a nasty event. Setting this number to 0 makes sitting idle churn the random number generator for producing different results. ai_trans_range_fix : 0..1, 0 - In MOO1 AI never checks range when sending transport. ai_4_colony_curse_fix : - In MOO1 4th colony ship disables sending colony ships. ai_first_tech_cost_fix : 0..1, 0 - First tech costs are calculated using the same formula as the rest. This fix significantly reduces the cost compared to MOO1. bt_turn_max : 1..65535, 50 - The number of battle turns before a forced retreat. bt_wait_no_reload : 0..1, 0 - Do not reload ship specials on Wait. MOO1 reloads ship specials when Wait is pressed and the ship's turn resumes. This means it is possible to fire the Pulsars, Black Hole Generator etc an unlimited number of times. Automated repair also kicks in on every resume from wait. bt_precap_tohit : 0..1, 0 - Add To Hit bonus before capping defense to 95%. MOO1 adds To Hit bonuses after capping defense. This results in high defense being less effective against high tech missiles. bt_no_tohit_acc : 0..1, 0 - Do not accumulate To Hit bonuses. MOO1 accumulates weapon To Hit bonuses while firing the four weapons slots. This results in Hyper-X or better missiles or Megabolt Cannon in slots 1..3 affecting the accuracy of a beam weapon in slot 4. bt_oracle_fix : 0..1, 0 - Fix the Oracle Interface. In MOO1 the Oracle Interface does nothing to the target's shields. The AI does take the target's (!) Oracle shield into account in damage esimates, including those related to missiles. weapon_list_max : 0..64, 30 - Max. number of weapons shown in the ship design weapon list. news_orion : 0..1, 0 - Show news when Orion is first colonized. MOO1 has a news item for conquering Orion but never shows it. aud_ask_break_nap : 0..1, 0 - Include Non-Aggression Pact in Break Alliance With Another Race. The OSG claims that the audience dialog option is enabled if a NAP exists between any of the opponents. This is a filthy lie. aud_bounty_give : 0..1, 0 - Give promised bounty. The AI sometimes promises to give rewards for attacking an another player. In MOO1 the AI says something along the lines of "thnx, take this FOO tech" but never actually gives anything. aud_update_tech : 0..1, 0 - Update tech, range and visibility after audience. MOO1 does this on save/load. update_on_load : 0..1, 1 - Readjust eco and update visibility on load. In MOO1 saving and reloading affect game state. newtech_adjust_fix : 0..1, 1 - Do not reset the eco slider in the 25/50/75% dialog. monster_rest_att : 0..1, 0 - Allow attacking resting space monsters. In MOO1 it is impossible to attack a space crystal or amoeba after the turn it has reached a planet. orbital_bio_fix : 0..1, 0 - Remove passive bio damage In MOO1, bio weapons reduce maximum population without orders orbital_weap_any : 0..1, 0 - Allow orbital bombardment with any weapon type. In MOO1 neither Death Ray, Crystal Ray nor Amoeba Stream can be used for orbital bombardment. The last two are only available via save game editing, but the omission of Death Ray is puzzling. orbital_weap_4 : 0..1, 0 - Allow orbital bombardment with weapon in slot 4. In MOO1 the weapon in slot 4 is not used in orbital bombardment. orbital_torpedo : 0..1, 0 - Fix orbital bombardment missile/torpedo damage halving. In MOO1 the missile damage is halved but torpedo damage is untouched. orbital_comp_fix : 0..1, 0 - Fix orbital bombardment undeserved battle computer bonus. In MOO1 the bonus is given for the best battle computer in any ship design regardless of if any such ships are present in the fleet in orbit. combat_trans_fix : 0..1, 0 - Make Combat Transporters work as intended. In MOO1 Combat Transporters only work if the planet owner has Sub-Space Interdictor, and using 25% roll followed by 50% roll if the first one failed. Enabling the fix makes it behave as OSG describes; chance is 50%/25% depending on Interdictor. stargate_redir_fix : 0..1, 0 - Fix Star Gate fleet redirection bug/cheat. In MOO1 a fleet sent via Star Gate can be redirected to any other planet and the flight will take only 1 turn regardless of destination. The other way was also bugged; redirecting a fleet to a valid Star Gate use situation did not end up in the fleet using the Star Gates. trans_redir_fix : 0..1, 0 - Fix transport redirection bug/cheat. In MOO1 transports can be redirected (given Hyperspace Communications) to unexplored. reserve-fuel-needing and no-colony-for destinations. retreat_redir_fix : 0..1, 0 - Fix retreating fleet redirection back to battle bug/cheat. In MOO1 fleets retreating from battle can be redirected to fight again the next turn. This fix disables redirecting back to the planet the fleet just retreated from unless Hyperspace Communications is available. first_tech_rp_fix : 0..1, 0 - Fix RP stagnation before starting first tech project. Investing 1 RP to start the first project in a field is not enough due to the 10% stagnation rounding it down to 0. waste_calc_fix : 0..1, 0 - Fix waste calculation. MOO1 adds waste twice: first using a perfectly sensible formula and then a baffling one. The waste elimination cost is calculated in between. The second amount added is often negative due to the waste amount not being limited. This is why Silicoid planets end up with 0 waste. Other races only see the effect when setting the Eco slider below Clean. waste_adjust_fix : 0..1, 0 - Partially fix waste elimination slider autoadjustment. In MOO1 the sum of sliders can exceed 100 due to weird math in the waste elimination slider adjustment code. This fix does not address the effects of integer division. slider_respects_locks : 0..1, 0 - Waste elimination slider autoadjustment does not change locked sliders. pop_tenths_fix: 0..1, 0 - Do not add population tenths twice. MOO1 adds population tenths twice when calculating population growth. This results in higher and nonlinear changes of growth value. factory_cost_fix: 0..1, 0 - Fix factory cost and refit cost after researching the Computers->IRC tech. This also removes refit cost for Meklars eco_slider_slack : 0..255, 7 - Eco slider automatic adjustment slack. Reducing the value to 0 eliminates extraneous eco spending after population maximum has been reached. reset_tform_to_max : 0..1, 1 - Reset terraforming to the player's maximum when finishing soil enrichment. If this value is 1 (the default), when the soil enrichment project is completed on a planet that has been terraformed to a higher level than the player has available, the terraforming is reset to the players maximum. If the value is 0, the alien terraforming is kept. soil_rounding_fix : 0..1, 0 - Fix incorrect rounding up with soil enrichment In older versions of 1oom and probably in MOO1 instead of rounding up to the next multiple of 5, the game adds an additional +5 unless the base size is in the range 50-59 or 100-109. leaving_trans_fix : 0..1, 0 - Population scheduled for transport no longer contributes to production. hidden_child_labor_fix : 0..1, 0 - Do not update production for SHIP, DEF and IND spending after ECO spending and pop growth. TECH spending is not affected and uses pre-growth values. A value of 1 means the same production for all sliders. extended_reloc_range : 0..1, 0 - Allow new fleets to relocate to any planet within range. MOO1 allows you to assign only controlled planets as reloc points. colonized_factories_fix : 0..1, 0 - Fix robotic controls factor for colonized factories There are scenarios that after destroying colony, the planet factories survive and new colony created by another player didn't reset robotic control factor of this colony. This fix resets the factor to 2 if no factories or to 1 if there are factories on the planet. This also sets bc_to_refit to 0. cond_switch_to_ind_fix: 0..1, 0 - Always switch production from eco to building factories rather than technology, regardless of current population. slider_eco_done_fix: 0..1, 0 - Do not stop terraforming when finishing eco project. ship_scanner_fix : 0..1, 0 - Fix broken ship scanners In MOO1, ship scanners are broken (obviously) doom_stack_fix : 0..1, 0 - Fix negative/32000 ship doom stack bug. In MOO1 overflows in AI-AI battles can result in 32000 ship doom stacks. ai_fleet_cheating_fix : 0..1, 0 - Fix unlimited exponential growth of ship slider value when too many MBases on a planet. In MOO1, ship slider can reach 1000% (maybe more) tech_costmuld : 0..255, ? - Research discovery base cost difficulty multiplier for human players. tech_costmula : 0..255, ? - Research discovery base cost difficulty multiplier for AI players. tcostm_* : 0..255, ? - Research discovery base cost racial modifier. event_roll : 0..2147483647, 512 - Special event probability. Bigger number means events are less likely. Zero means events are disabled. accident_chk_factories : 0..1, 0 - Only apply the industrial accident events to colonies with some industry. If this is set to 1, the industrial accident event happens only to colonies with at least 30 factories, as described in the OSG. If it is set to 0, it can happen to any colony, as is actually the case in MOO 1.3. council_years : 0..32767, 25 - Number of years between Galactic Council meetings. Zero means the Council never gathers. trait1_* : 0..5, ? - Starting personality type table for each race. The type is chosen randomly from the table when stating a new game. The values are: 0 = Xenophobix, 1 = Ruthless, 2 = Aggressive, 3 = Erratic, 4 = Honorable, 5 = Pacifistic. trait2_* : 0..5, ? - Starting racial objective table for each race. The objective is chosen randomly from the table when stating a new game. The values are: 0 = Diplomat, 1 = Militarist, 2 = Expansionist, 3 = Technologist, 4 = Industrialist, 5 = Ecologist. crystal_* : ?, ? amoeba_* : ?, ? guardian_* : ?, ? - The index of these space monster tables is the difficulty level. ngt_*_* : 0..255, ? - New game research list limitations for each field and race. Table index corresponds to tech level, for example ngt_we_meklar item 32 controls Gauss Autocannon research availability for Meklars. The value 1 means the tech is never added, f.ex Silicoids & colony tech. The value 2 means the tech is always added. (Unused by default.) The bits 2..7 (values 4, 8, ...) are used for groups of essential techs; the research list must contain at least one of the techs with a given bit set. (Bit 2 / value 4 is the only one used by default.) 1oom-1.11.2/doc/pbxin_example.txt000066400000000000000000000067201476061725400166310ustar00rootroot00000000000000# This is an example PBXIN file. # Lines starting with # are comments. Empty lines are ignored. # PBXIN files are used by 1oom_pbxmake to make PBX files. # PBX files are patch files that replace LBX data or not-really-constants. # Think of a MOO1 version of Doom WAD files (no scripts, though). # The format of the non-comment lines is: # 0,"pbx name" # 1,pbx_description.txt # 2,filename.lbx,itemnumber,replacementfile.bin # 5,filename.lbx,itemnumber,offset,partialdata.bin # 3,string_id,itemnumber,"new text" # 4,number_id,itemnumber,value[,value]* # Type 0 item is the PBX name. One per PBX, one line only. Keep it 7-bit ASCII. 0,"Example PBX file" # Type 1 item is the PBX description. One per PBX. Can be long. Keep it 7-bit ASCII. 1,long_description.txt # Tip: any included file could also be entered as a C-like string, f.ex #1,"This is just a PBX example.\nGet the latest version from www.example.org/pbx\nHave fun!" # Type 2 is a LBX patch. # The item "itemnumber" in the LBX file is replaced with the given file whenever the # game (or UI) asks for it. The LBX file itself is untouched. # Replace the main menu logo with newlogo.bin. 2,v11.lbx,0,newlogo.bin # Replace ship #4 graphics with newshipgfx.bin. 2,ships.lbx,4,newshipgfx.bin # Only the native MOO1 LBX GFX format is supported. # Use 1oom_gfxconv to convert pictures to the native format. # Replace the battle music with something fitting. 2,music.lbx,8,D_RUNNIN.mid # Replace the "click" sound. 2,soundfx.lbx,0x24,ping.wav # Tip: hex numbers are supported. Unfortunately, so are octal; 012 == 10 == 0xa. # Currently supported music formats: MIDI, XMID (used in MOO1 and MOM), FLAC, Ogg Vorbis # Currently supported sound formats: WAV, VOC # Type 5 is LBX partial overwrite. # Whenever the game (or UI) asks for the item "itemnumber" in the LBX file, # the data from the LBX file (or LBX patch) will have the bytes at "offset" # overwritten with the given data. The LBX file itself is untouched. # Replace "Lasitus" with "Lazarus" 5,names.lbx,0,0x56,"zar" # Replace "Prrsha" with "Mrrsha" 5,names.lbx,0,0x7c,"M" # Note that the offsets are from the beginning of the item, not the file. # Type 3 is a string replacement. # Run "1oom_classic_sdl1 -dumpstr" to get all the strings in copy/paste-friendly format. # The "itemnumber" is 0 for non-table items. Indices start at 0. # Let's change the main menu quit item: 3,mm_quit,0,"GTFO" # Let's honor an another early 90's classic: 3,tbl_race,0,"Hunam" # Example of changing an other item in the same table: 3,tbl_race,9,"Google" # Let's not forget the other table: 3,tbl_races,0,"Hunams" 3,tbl_races,9,"Googles" # New strings may be longer than the original, but excessive length may break the UI. # Type 4 is a number replacement. # Run "1oom_classic_sdl1 -dumpnum" to get all the numbers in copy/paste-friendly format. # The "itemnumber" is 0 for non-table items. Indices start at 0. # Multiple items of a table can be changed in one line. # Change the star gate cost: 4,stargate_cost,0,6000 # Tweak the large (2) and huge (3) hull space: 4,st_hull_space,2,1275,4850 # Tip: hex numbers are supported. Unfortunately, so are octal; 012 == 10 == 0xa. # See doc/list_pbxnum.txt for more information. # Use "1oom_pbxmake pbxin_example.txt example.pbx" to make the PBX file. # (...although first you need to provide the missing files or comment the lines out.) # Then "1oom_classic_sdl1 -file example.pbx" to try it out. # "1oom_lbxview_sdl1 -file example.pbx" also works for viewing the LBX replacements. 1oom-1.11.2/doc/pbxin_fixbugs.txt000066400000000000000000000047121476061725400166440ustar00rootroot00000000000000# This is a PBXIN file. # It enables most of the optional MOO1 bug fixes. # Use "1oom_pbxmake pbxin_fixbugs.txt fixbugs.pbx" to make the PBX file. # Then "1oom_classic_sdl1 -file fixbugs.pbx" to use it. 0,"Fix MOO1 bugs" 1,"Enables most of the optional MOO1 bug fixes.\nAlso tweaks some clearly bug-like things such as Guardian ADC and starting ship costs." # Give Guardian Advance Damage Control on impossible. # MOO1 has Automated Repair (but shows ADC) on hard and nothing on impossible. # The MOO1 code is along the lines of: # if (difficulty == hard) { special2 = ADC; } else if (difficulty == hard) { special2 = AR; } # if (difficulty == hard) { repair = 15; } else if (difficulty == hard) { repair = 30; } # This is clearly a bug. 4,guardian_special2,3,16,26 4,guardian_repair,4,30 # The amount of engines and thus costs of the starting ship designs are wrong. 4,startship_engines,0,2,27,110,85,100 4,startship_cost,0,8,14,74,65,570 # The 2500 factories limit is too low for Meklars. 4,max_factories,0,2700 # Silicoids have most of the tech useless to them not appear in their research tree. # However, Advanced Eco Restoration and Advanced Soil Enrichment can still appear. # This must be an oversight. 4,ngt_pl_silicoid,24,1 4,ngt_pl_silicoid,30,1 # Apply the industrial accident event only to colonies that have some industry. 4,accident_chk_factories,0,1 # See doc/list_pbxnum.txt for description of the rest of the fixes. 4,ai_trans_range_fix,0,0 4,ai_4_colony_curse_fix,0,1 4,ai_first_tech_cost_fix,0,1 4,doom_stack_fix,0,1 4,bt_wait_no_reload,0,1 4,bt_precap_tohit,0,1 4,bt_no_tohit_acc,0,1 4,bt_oracle_fix,0,1 4,news_orion,0,1 4,weapon_list_max,0,64 4,aud_bounty_give,0,1 4,aud_update_tech,0,1 4,update_on_load,0,0 4,newtech_adjust_fix,0,1 4,orbital_bio_fix,0,1 4,orbital_weap_any,0,1 4,orbital_weap_4,0,1 4,orbital_torpedo,0,1 4,orbital_comp_fix,0,1 4,combat_trans_fix,0,1 4,stargate_redir_fix,0,1 4,trans_redir_fix,0,1 4,first_tech_rp_fix,0,1 4,waste_calc_fix,0,1 4,waste_adjust_fix,0,1 4,slider_respects_locks,0,1 4,pop_tenths_fix,0,0 4,factory_cost_fix,0,0 4,eco_slider_slack,0,0 4,reset_tform_to_max,0,0 4,soil_rounding_fix,0,1 4,leaving_trans_fix,0,1 4,hidden_child_labor_fix,0,1 4,extended_reloc_range,0,1 4,colonized_factories_fix,0,1 4,cond_switch_to_ind_fix,0,1 4,slider_eco_done_fix,0,1 4,ship_scanner_fix,0,1 4,ai_fleet_cheating_fix,0,1 # Disabled fixes. Remove the # in front of 4 to enable. #4,aud_ask_break_nap,0,1 #4,retreat_redir_fix,0,1 #4,monster_rest_att,0,1 1oom-1.11.2/doc/usage_classic.txt000066400000000000000000000164041476061725400166030ustar00rootroot00000000000000################ # 1oom_classic # ################ 1oom_classic_* replicate the 1993 UI. See doc/usage_common.txt for the data/user file locations and command-line arguments. The UI controls like the original. Consult the game manual and the readme.txt from v1.3. This document describes only the differences. New hotkeys: - Middle click or Ctrl-F10 to grab/ungrab input - Ctrl-Esc to quit (without saving) - Ctrl-[] to adjust sfx volume - Ctrl-Shift-[] to adjust music volume - Alt-[] to adjust window size - Alt-Enter to toggle full screen mode Unlike the original, 1oom does not autosave the "continue game" (save slot 7) when starting a new game or every N turns. It only saves it when quitting the game via Game -> Quit or when F10 is pressed while in the "control screen" / "galaxy movement screen". 1oom does autosave the "new game" (save slot 9) when starting a new game. An incorrect answer in the copy protection dialog does not delete save slot 7. The config file item "ui.uiscale" (set via the -uiscale command-line option) is an int scaling factor for the whole UI except galaxy movement screen map. The default value is 1 for that classic 320x200 feeling. Larger values allow more of the galaxy to be viewed without scrolling. Mouse wheel can be used to adjust the scaling of the galaxy movement screen map. The following new UI features are always enabled/available: - The main menu now allows you to change game settings - Random race / banner - Custom Game screen allows setting opponent race/banner/names and AI/human flag - Custom Game screen allows local multiplayer - Lowercase allowed in save names - Load Game screen uses numbers as hotkeys for slots - Objects with hotkeys can be navigated to using cursor keys - Mouse wheel can be used to scroll lists and adjust many things - Mouse wheel on planet name in the galaxy movement screen changes planet - Space bar works as a generic dismiss message key (Continue, ...) - Ctrl and Alt works as a step modifier for the counters and sliders: - on the Design screen - on the fleet sending screen - on the galaxy movement screen - on the transport sending screen - on the Tech screen - on the Races screen - Sending ships does not deselect the orbit fleet when holding Shift - F4/F5 can iterate over fleets of the same owner - In Tech screen +/- adjusts the current field slider - In Tech screen the L key locks the current slider - Clicking the portraits in Races screen brings Report page - In Races screen the keys 1-5 correspond to clicking the portraits - In Specs screen the keys 1-6 correspond to clicking the scrap button - In Tech screen the keys 1-6 correspond to clicking the tech fields - Ind slider no longer shows 0.N/y when at max factories - Eco slider shows Clean/+N Pop past T-Form on a full planet - Bases can be scrapped by clicking on the Bases text - Clicking cycles selection of overlapping fleets - The following hotkeys are available for the star map whenever it makes sense: Alt+m, Alt+c, Alt+r - Ctrl+r sets or unsets all reloc points similar to Alt+r - Planets can be searched for by pressing the / key - Planets and ship designs can be renamed by clicking on their name - The = key can be substituted by the # key - The + key can be substituted by the = key (if not conflicting) The config file item "ui.uiextra" (set via the -uiextra command-line option) or selecting the 1oom UI preset enables the following extra UI features: - Report screen shows name of AI leaders, Map screen shows current year - Pressing + or - will show the slider when sending transport - Fleet deployment shows the amount of available ships - Alt+f shows friendly fleet routes - Alt+o (experimental) toggles text under stars - Buttons and slider are always visible when sending transport - Clicking a selected destination star again works as Accept for fleet send etc - The position of the build finished message is slightly improved. - Clicking on the picture of the planet in the upper right corner works for all explored planets - The + sign is placed in the population text if it is possible to do atmospheric terraforming or soil enrichment - Eco slider shows fractional population growth if growth is less than 10 - Eco slider can show "MAX" - Nebula planets show "NEB" in their shields field and have a purple instead of a red frame around their picture - After running through the Next turn phase and messages the game recenters on your last planet of choice - Clicking on #, Name, etc on Planets screen sorts the list - Clicking on Station or ship names on Fleet screen sorts the list - The color of ship names on Planets screen is black - Added max population column on Planets screen - Pressing = in the galaxy movement screen also transfers reserve back and the behavior is more predictable - Weapons can be filtered by type when modeling a ship Click on Weapons to change the filter - Pressing the I key on the planet overview screen shows additional info for inhabited planets - The entire map on the Map screen is now clickable (focus on the mouse cursor) - Pressing g on the battlefield screen shows the grid - Holding the Alt or Ctrl key while locking a colony slider allows you to lock sliders for all colonies at once (or for all colonies of the same type) - Holding the Alt or Ctrl key while clicking on the frame with the slider value text allows you to adjust sliders for all colonies at once The following features can be enabled in the configuration file or by selecting the 1oom UI preset: - The config file item "ui.fixbugs" fixes the following: - Pressing = on the Tech screen adjusts only the unlocked sliders - When using cursor keys, the mouse position is calculated taking into account the mouse icon offset - Fixed graphics bug with brighter stars drawn further away than dimmer ones - Continue, Undo and Initial saves can be chosen in the Load Game screen ("ui.load_opts_extra") - Summary of forces shown before ship combat. New Auto and Retreat buttons for space combat autoresolve ("ui.space_combat_autoresolve") - Galaxy movement screen scrolling range is expanded ("ui.sm_expanded_scroll") - The cursor key behavior is more intuitive (ui.kbd_cursor_keys_fix) - Improved behavior of the left mouse button ("ui.mouse_lmb_fix") - Pressing a hotkey does not trigger mouse warp ("ui.mouse_warp_disabled") - "ui.illogical_hotkey_fix" changes some illogical hotkeys: - Starmap -> Fleet -> Specs ('v' -> 's') - Starmap -> Fleet -> Scrap ('s' -> 'c') - Starmap -> Reloc ('l' -> 'r') - Starmap -> Races ('r' -> 'a') - "game.skipintro" skips intro video - The question mark cursor is disabled on the galaxy movement screen ("ui.sm_no_question_mark_cursor") - Pressing the "Ships" button in the galaxy movement screen opens the ship design selection screen ("ui.ui_sm_ships_enabled") - Holding Alt toggles the cursor icon and the ability to select a fleet ("ui.sm_explicit_cursor_context") Also: - "ui.sm_mouseover_focus" changes the target when hovering over a star - The keys UHJK scroll the galaxy movement screen map ("ui.sm_uhjk_scroll") - Mouse scrolls the galaxy movement screen map if touches edge ("ui.sm_mouse_scroll") - "ui.sm_smoother_scrolling": - Smoother galaxy movement screen scrolling - Galaxy movement screen scrolling speed is adjustable ("ui.sm_scroll_speed") See doc/list_gamediff.txt for a list of differences in the game itself. 1oom-1.11.2/doc/usage_cmdline.txt000066400000000000000000000060761476061725400166010ustar00rootroot00000000000000################ # 1oom_cmdline # ################ 1oom_cmdline is a proof of concept textual UI. See doc/usage_common.txt for the data/user file locations and command-line arguments. Type '?' for help. Example game beginning: Lizard King | 2300 | L.A. > # This is a comment. > # Let's take a peek at our home planet. > l [38] (213,187) L.A.: TERRAN, POP 100 MAX, pop 50, bases 0, factories 30, prod 43 (56), waste 0 - Build 0 SCOUT - Slider SHIP 0 NONE - Slider DEF 0 NONE - Slider IND 65 2.7/Y - Slider ECO 35 CLEAN - Slider TECH 0 0 RP - Sakkra fleet at orbit: 2 0 0 0 1 0 > # Let's view the surrounding 6 parsecs. > v 6 [...] Dist 4: [46] (186,213) #R46: UNEXPLORED. Range 4 Parsecs. Dist 3: [47] (236,178) #B47: UNEXPLORED. Range 3 Parsecs. Dist 3: [45] (189,178) #R45: UNEXPLORED. Range 3 Parsecs. Dist 2: [39] (213,166) #R39: UNEXPLORED. Range 2 Parsecs. > # Send scouts to the range 3 planets. > fs 45 1 > fs #B47 1 > # Send the remaining fleet to the range 2 planet. > fs 39 > # Check that we actually did something. > fleet - SCOUT, FIGHTER, DESTROYER, BOMBER, COLONY SHIP #F0 (213,187) MOVING TO [45] #R45 1 0 0 0 0 0 ETA 3 TURNS #F1 (213,187) MOVING TO [47] #B47 1 0 0 0 0 0 ETA 3 TURNS #F2 (213,187) MOVING TO [39] #R39 0 0 0 0 1 0 ETA 2 TURNS > # Next turn (twice) > n > n [39] (213,166) Paranar: JUNGLE, POP 85 MAX. No colony. Range 2 Parsecs - Sakkra fleet at orbit: 0 0 0 0 1 0 Build a new colony? Y) Yes N) No > y In the year 2301 the Sakkras form a new colony: (Paranar) > Lizard King | 2302 | L.A. > # Transfer some pop to the new planet. > trans Paranar 10 ETA 2 TURNS > # Let's visit the planet. > g Paranar Lizard King | 2302 | Paranar > l [39] (213,166) Paranar: JUNGLE, POP 85 MAX, pop 2, bases 0, factories 0, prod 1 (1), waste 0 - Build 0 SCOUT - Slider SHIP 0 NONE - Slider DEF 0 NONE - Slider IND 100 0.1/Y - Slider ECO 0 NONE - Slider TECH 0 0 RP > # Let's view our planets. > v py Dist 2: [38] (213,187) L.A.: TERRAN, POP 100 MAX, pop 59, bases 0, factories 36, prod 67 (67), waste 0 Dist 0: [39] (213,166) Paranar: JUNGLE, POP 85 MAX, pop 2, bases 0, factories 0, prod 1 (1), waste 0 > # Go back to the home planet and start researching. > g 38 Lizard King | 2302 | L.A. > sl e > s t +10 > l [38] (213,187) L.A.: TERRAN, POP 100 MAX, pop 59, bases 0, factories 36, prod 67 (67), waste 0 - Build 0 SCOUT - Slider SHIP 0 NONE - Slider DEF 0 NONE - Slider IND 55 3.6/Y - Slider * ECO 35 +0.6 POP - Slider TECH 10 6 RP > n Scout ships explore a new star system [45] (189,178) Paladia: JUNGLE, POP 80 MAX. No colony. Range 3 Parsecs - Sakkra fleet at orbit: 1 0 0 0 0 0 Scout ships explore a new star system [47] (236,178) Phantos: DEAD, POP 60 MAX, ULTRA POOR, HOSTILE. No colony. Range 3 Parsecs - Sakkra fleet at orbit: 1 0 0 0 0 0 > # Let's quit and never touch this silly UI again. > quit 1oom-1.11.2/doc/usage_common.txt000066400000000000000000000236411476061725400164530ustar00rootroot00000000000000This document describes things common for all the programs. This file is based on the OpenXcom 1.0 README, except s/folder/directory/g like a civilized person. 1. LBX files ============= 1oom requires a copy of the Master of Orion (v1.3) LBX files. See doc/lbxmd5.txt for the expected MD5 sums. The LBX file can be in a different directory as the executable. You can also specify your own path by passing the command-line argument "-data " when running 1oom. The given path is saved to the configuration file. The LBX files are first looked for in the directory specified with "-data ". If not found there, the following subsections apply. 1.1. Windows, MSDOS -------------------- 1oom will check the directory of the executable. 1.2 Unix (Linux) ----------------- According to the XDG standard, 1oom will also check the following directories: - $XDG_DATA_HOME/1oom - $XDG_DATA_DIRS/1oom Or if those variables aren't available: - ~/.local/share/1oom - /usr/share/1oom - . Choose whichever you prefer. 2. Configuration ================= 1oom is configured via command-line arguments or editing the configuration file. Each program has a separate configuration file (if any). 2.1. User Directory -------------------- 1oom creates a User directory with all the user savegames and options in one of the following paths: - (win32, msdos) - $XDG_CONFIG_HOME/1oom (Unix) - ~/.config/1oom (Unix) You can also specify your own path by passing the command-line argument "-user " when running 1oom. Note that unlike "-data" the setting is not saved in the configuration file. 2.2. What is not saved ----------------------- Most options set via command-line arguments are saved to the configuration file (if any). The notable exceptions are: -c Config filename in the config file? Too meta -cro Can not write "do not write config" to config -user Config file is in user directory -(no)log Log is opened before reading config -file 3. Command-line arguments ========================== The following are for the game UIs and lbxview. See doc/usage_*.txt for the other tools. For all: -? Show command line options -c FILE.TXT Set config filename -cro Do not write a config file -user PATH Set user directory -data PATH Set data directory -log FILE.TXT Set log filename -nolog Do not create a log file -file FILE.PBX Add PBX file For UIs with audio support: -audio Enable audio -noaudio Disable audio -music Enable music -nomusic Disable music -sfx Enable SFX -nosfx Disable SFX -sfxinitpar Init SFX in parallel (if possible) -nosfxinitpar Do not init SFX in parallel -musicvol VOLUME Set music volume (0..128) -sfxvol VOLUME Set SFX volume (0..128) -audiohz HZ Set audio sample rate (Hz) -audioms MS Set max audio slice size (ms) For UIs with audio support if libsamplerate is available: -libsr Use libsamplerate -nolibsr Do not use libsamplerate -libsrscale PERCENT libsamplerate scaling % -libsrmode MODE libsamplerate mode (0 = best, 4 = worst) For graphical UIs: -fs Enable fullscreen -window Use windowed mode -winw WIDTH Set window width -winh HEIGHT Set window height if w & h are 0 then use game resolution -fsw WIDTH Set fullscreen width -fsh HEIGHT Set fullscreen height if w & h are 0 then use desktop resolution For some graphical UIs: -aspect ASPECT Set aspect ratio (*1000000, 0 = off) default = 833333, or (1000000 * 5)/6 For SDL HWs: -mousespd SPEED Set mouse speed (default = 100) -sdlmixersf FILE.SF2 Set SDL_mixer soundfont For SDL1 HW: -gl Enable OpenGL -nogl Disable OpenGL -bpp BPP Set bits/pixel (0 = autodetect) -filt FILTER Set OpenGL filter (0 = nearest, 1 = linear) For SDL2 HW: -forcesw Force software rendering -noforcesw Do not force software rendering -intscaling Force integer scaling -nointscaling Do not force integer scaling -relmouse Use relative mouse mode -norelmouse Do not use relative mouse mode For all game UIs: -dumpstr Dump strings in PBXIN format -dumpnum Dump numbers in PBXIN format -new GAMESEED Start new game using given game seed GAMESEED is OPT[:RACES[:BANNERS[:GSEED[:HUMANS]]]] OPT is PLAYERS*100+GALAXYSIZE*10+DIFFICULTY 2..6, 0..3 = small..huge, 0..4 = simple..impossible default same as last new game RACES is PLAYERnRACE*(0x10^n), n=0..5 0 = random, 1..0xA = human..darlok default 0 (all random) BANNERS is PLAYERnBANNER*(10^n), n=0..5 0 = random, 1..6 = blue..yellow default 0 (all random) GSEED is a 32 bit galaxy seed or 0 for random default 0 HUMANS is PLAYERnISHUMAN*(10^n), n=0..5 default 1 (player 1 is human, others AI) -ngn PLAYER NAME Set new game emperor name for player 1..6 -ngh PLAYER NAME Set new game home world name for player 1..6 -nga AITYPE Set new game AI type (0..1) -load SAVE Load game (1..8 or filename) 1..6 are regular save slots 7 is continue game 8 is undo 2300 and over are yearly saves -continue Continue game -undo Enable undo saves -noundo Disable undo saves -yearsave Enable yearly saves -noyearsave Disable yearly saves -skipintro Skip intro -noskipintro Do not skip intro -nextturn Go directly to next turn (for reproducing bugs) YOMAMA Skip intro this time s Continue game For classic game UI: -uiscale SCALE UI scaling factor -uiextra Enable UI extras -nouiextra Disable UI extras -mwislider Invert mouse wheel for sliders -nomwislider Do not invert mouse wheel for sliders -mwicounter Invert mouse wheel for counters -nomwicounter Do not invert mouse wheel for counters -uismscroll SPEED Starmap scroll speed (1..10, 0 = instant) 3.1. -new ---------- Whenever a new game is started, the log displays a line such as: Game: new game -new 621:0x5:4:0x3f5e5b32:1 -nga 0 The alphanumeric jumble is a game seed. It can be given to -new to start a new game with the same galaxy and opponents. The game seed format is OPT:RACES:BANNERS:GSEED:HUMANS where OPT is PLAYERS*100+GALAXYSIZE*10+DIFFICULTY PLAYERS is 2..6 GALAXYSIZE is 0..3 = small..huge DIFFICULTY is 0..4 = simple..impossible default same as last new game RACES is PLAYERnRACE*(0x10^n), n=0..5 0 = random 1 = human 2 = mrrshan 3 = silicoid 4 = sakkra 5 = psilon 6 = alkari 7 = klackon 8 = bulrathi 9 = meklar a = darlok default 0 (all random) BANNERS is PLAYERnBANNER*(10^n), n=0..5 0 = random 1 = blue 2 = green 3 = purple 4 = red 5 = white 6 = yellow default 0 (all random) GSEED is a 32 bit galaxy seed or 0 for random default 0 HUMANS is PLAYERnISHUMAN*(10^n), n=0..5 default 1 (player 1 is human, others AI) Omitting a value sets it to the default one. Some examples: -new 634 * 6 player / huge / impossible game as a random race -new :0x7 * player / size / difficulty same as last new game * as klackon -new : * player / size / difficulty same as last new game * as random race -new 634:0x162 * 6 player / huge / impossible game as a random race * (2) as mrrshan, against (6) alkari and (1) human, others random -new 621:0x5:4:0x3f5e5b32:1 * 6 player game in (2) large galaxy with (1) easy difficulty * player 1 race is (5) psilon, others random * player 1 banner is (4) red, others random * galaxy and random races/banners based on seed 0x3f5e5b32 * player 1 is human, others AI -new 634:0x15533a * 6 player / huge / impossible game * as (a) darlok, against (1) human, (5) psilon, psilon, (3) silicoid and silicoid -new 304:0x48:25::11 * 3 player / small / impossible game * player 1 is (5) white (8) bulrathi, player 2 is (2) green (8) sakkra, player 3 is random * players 1 and 2 are human 3.2. -nga ---------- The -nga command line parameters selects the AI type to use when starting a new game via -new. The values 0 and 1 correspond to Classic and Classic+, respectively. 3.3. -file ----------- Unlike Doom, the "-file" part needs to added for each PBX file. Like Doom, the given PBX filenames are not stored anywhere and must be given with -file whenever the PBX files are to be used. 4. New features ================ 4.1. Space combat autoresolve ------------------------------ The space combat autoresolve is provided as an option for skipping battles. Pressing the Auto button results in the battle beings fought as if the player(s) pressed Auto right after starting combat. The Retreat button works as if the (human) player(s) pressed Retreat at the earliest and every opportunity. 1oom-1.11.2/doc/usage_gfxconv.txt000066400000000000000000000035621476061725400166350ustar00rootroot00000000000000################ # 1oom_gfxconv # ################ 1oom_gfxconv is a tool for converting GFX for use in PBX files. Usage: 1oom_gfxconv [OPTIONS] OUT.BIN IN.PCX|=WxHcC [INn.PCX]* 1oom_gfxconv -d IN.BIN Options: -f Make format 1 binary (only council.lbx item 1) -i All independent frames (winlose.lbx items 1-...) -e N Extra independent frame (embassy.lbx items 2-...) -n N Set number of frames (default N = number of input files) -l N Set loop frame -p F N Include palette ; First, Number of colors -d Dump converted file for debugging The filenames "=WxHcC" are interpreted to be images of size W x H consisting of the color C. If the number of frames set with -n N is greater than the amount of input files, the missing files are assumed to be the same as the last given file. Examples: 1oom_gfxconv title.bin title_screen.pcx - convert title_screen.pcx to title.bin 1oom_gfxconv shipfoo.bin z_ships2_49_00*.pcx - convert the animation in z_ships2_49_00*.pcx to shipfoo.bin (hopefully your CLI will sort the files properly) 1oom_gfxconv -p 0 256 foo.bin foo.pcx - convert foo.pcx to foo.bin - include the full palette 1oom_gfxconv -e 2 out.bin z_embassy_04_*.pcx - convert the animation in z_embassy_04_*.pcx to out.bin (hopefully your CLI will sort the files properly) - declare frame 2 as independent (as in embassy.lbx items 2-...) 1oom_gfxconv -n 48 emptyvortex.bin =320x200c13 - create 48 frames of 320x200 color 13 to emptyvortex.bin 1oom_gfxconv -d out.bin - dump out.bin for debugging You may be interested in using 1oom_lbxview to save the original items as template PCX files. FAQ: Q: ...wait. PCX? A: Yes. Suitably 1993. If your graphics program does not support it, go get GraphicsMagick or something. 1oom-1.11.2/doc/usage_lbxedit.txt000066400000000000000000000031351476061725400166120ustar00rootroot00000000000000################ # 1oom_lbxedit # ################ 1oom_lbxedit is a tool for editing LBX files. There is very little reason to use this as PBX files are a nondestructive way to replace LBX contents. Usage: 1oom_lbxedit [OPTIONS] d IN.LBX [OUTPREFIX] 1oom_lbxedit [OPTIONS] m LBXIN.TXT OUT.LBX 1oom_lbxedit [OPTIONS] e IN.LBX OUT.BIN ITEMNUM 1oom_lbxedit [OPTIONS] r FILE.LBX IN.BIN|0 ITEMNUM Commands: d Dump LBX file to LBXIN + bin files m Make LBX file from LBXIN + bin files e Extract item from LBX file r Replace item in LBX file Options: -w (d, r) Write files -o OUT.LBX (r) Set output LBX filename In d and r modes: If the -w option is not given then no files are written. In d mode: The input filename without the .LBX extension (if any) is used for the output prefix if none is given. The input bin filename "0" is interpreted as a zero length file. Examples: 1oom_lbxedit d ships.lbx - show ships.pbx contents in LBXIN format 1oom_lbxedit -w d ships.lbx - write ships.lbx contents to ships.lbxin and ships_*.bin 1oom_lbxedit -w d ships.lbx d/foo - write ships.lbx contents to d/foo.lbxin and d/foo_*.bin 1oom_lbxedit m foo.lbxin bar.lbx - build bar.lbx from foo.lbxin the files it refers to 1oom_lbxedit e ships.lbx ship4.bin 4 - extract item 4 in ships.lbx to ship4.bin 1oom_lbxedit -o new.lbx -w r ships.lbx ship4.bin 4 - create new.lbx from ships.lbx with ship4.bin as item 4 1oom_lbxedit -w r ships.lbx ship4.bin 4 - replace item 4 in ships.lbx with ship4.bin 1oom-1.11.2/doc/usage_lbxview.txt000066400000000000000000000033461476061725400166430ustar00rootroot00000000000000################ # 1oom_lbxview # ################ 1oom_lbxview_* is a tool for viewing LBX files. See doc/usage_common.txt for the data/user file locations and most of the command-line arguments. Rest of the command-line arguments: -font FONT.BIN Set 8x8 font filename Start in LBX file number at item 0 Start in LBX file number at item number 1oom_lbxview needs an external font file. From the error output: !! You need a 8x8 1bpp font (2048 bytes) file to use this program. !! If you have one ready elsewhere, use -font to use it. !! If you have DOSBox and base64; !! 1) Generate a font dumper: (source in doc/ext/fontdump.asm) !! echo uDARtwPNEAa6MwExybQ8zSFyGonDuQAIieoftEDNIXIMOch1CLQ+zSGwAHMCsAG0TM0hci5iaW4A | base64 -d > fontdump.com !! 2) Run fontdump.com in DOSBox to generate the font file r.bin. !! 3) Run lbxview again with -font r.bin Hoykeys: - Middle click or Ctrl-F10 to grab/ungrab input (no reason, mouse is unused) - Ctrl-Esc to quit - Ctrl-Plus/Minus to adjust sfx volume - Ctrl-Shift-Plus/Minus to adjust music volume - Alt-Enter to toggle full screen mode General keys: - Up/Down/Pageup/Pagedn: move the cursor - Esc: back out - 0..9: set palette N - w/a/s/d: change x/y offset, rotation angle, ... - f: fade out music Keys while outside of LBX: - Enter: select LBX file Keys while in LBX: - e: extract item as z_$LBXNAME_$ITEMNUM.bin Keys while in audio LBX: - Enter: play sfx/music - Shift-Enter: save item as z1.wav/z1.mid Keys while in gfx LBX: - Shift-Enter: save current image as z0.pcx - Ctrl-Enter: save all frames as z_$LBXNAME_$ITEMNUM_$FRAME.pcx - c: toggle clear before draw - q: cycle rotation test modes - z: cycle UI scaling test modes 1oom-1.11.2/doc/usage_pbxdump.txt000066400000000000000000000012531476061725400166350ustar00rootroot00000000000000################ # 1oom_pbxdump # ################ 1oom_pbxdump is a tool for dumping PBX files. See doc/usage_pbxmake.txt for information on PBX files. Usage: 1oom_pbxdump [OPTIONS] IN.PBX [OUTPREFIX] Options: -w Write files If the -w option is not given then no files are written. The input filename without the .PBX extension (if any) is used for the output prefix if none is given. Examples: 1oom_pbxdump file.pbx - show file.pbx contents in PBXIN format 1oom_pbxdump -w file.pbx - write file.pbx contents to file.pbxin and file_*.bin 1oom_pbxdump -w file.pbx d/foo - write file.pbx contents to d/foo.pbxin and d/foo_*.bin 1oom-1.11.2/doc/usage_pbxmake.txt000066400000000000000000000007621476061725400166110ustar00rootroot00000000000000################ # 1oom_pbxmake # ################ 1oom_pbxmake is a tool for creating PBX files. PBX files are patch files that replace LBX data or not-really-constants. Think of a MOO1 version of Doom WAD files (no scripts, though). Usage: 1oom_pbxmake PBXIN.TXT OUT.PBX See doc/pbxin_example.txt for the PBXIN.TXT format and example use. See doc/list_pbxnum.txt for description of some of the number replacements. See doc/format_pbx.txt for the OUT.PBX format. (For devs. Users can ignore.) 1oom-1.11.2/doc/usage_saveconv.txt000066400000000000000000000043411476061725400170030ustar00rootroot00000000000000################# # 1oom_saveconv # ################# 1oom_saveconv is a tool for converting save game files. Usage: 1oom_saveconv [OPTIONS] INPUT [OUTPUT] Options: -? Show command line options -i INTYPE Input type: s - smart: autodetect (default) m - MOO1 v1.3 1 - 1oom save version 0 t - text -o OUTTYPE Output type: s - smart: in old/new -> out new/old (default) m - MOO1 v1.3 1 - 1oom save version 0 t - text d - dummy (no output) -cmoo Enable CONFIG.MOO use -n NAME Set save name If a filename is a number from 1 to 8, it is interpreted as 1oom save number N. If it is number from 2300 to 9999, it is interpreted as 1oom yearly save YYYY. 1oom save format 0 is described in doc/format_save.txt. MOO1 v1.3 save format is described in doc/format_gam.txt. Text save format is intentionally left undefined. It is for debugging. Examples: 1oom_saveconv SAVE2.GAM oldsave2.bin - convert SAVE2.GAM to oldsave2.bin 1oom_saveconv -n "foo bar" SAVE2.GAM 2 - convert SAVE2.GAM to 1oom save 2 - set save name to "foo bar" 1oom_saveconv -cmoo SAVE2.GAM 2 - convert SAVE2.GAM to 1oom save 2 - take save name from CONFIG.MOO (if found) 1oom_saveconv 1oom_save5.bin SAVE6.GAM - convert 1oom_save5.bin to SAVE6.GAM 1oom_saveconv -cmoo 5 SAVE6.GAM - convert 1oom save 5 to SAVE6.GAM - update save name and availability in CONFIG.MOO (if found) 1oom_saveconv -o 1 7 6 - copy 1oom save 7 to 6 1oom_saveconv -o 1 2325 2 - copy 1oom yearly save 2325 to slot 2 1oom_saveconv -cmoo -n "foo bar" -o m SAVE1.GAM SAVE2.GAM - copy SAVE1.GAM SAVE2.GAM - set save name to "foo bar" - update save name and availability in CONFIG.MOO (if found) 1oom_saveconv -o t 7 foo.txt - save 1oom save 7 as text (for debugging) 1oom_saveconv foo.txt 7 - convert foo.txt to 1oom save 7 1oom_saveconv -o d 7 - load 1oom save 7 and do nothing (for debugging) 1oom-1.11.2/make-bindist_install.sh000066400000000000000000000001471476061725400171160ustar00rootroot00000000000000#!/bin/sh echo "No bindist for this platform. Copy src/1oom_* somewhere or use make install." exit 1 1oom-1.11.2/make-bindist_msdos.sh000066400000000000000000000034731476061725400166020ustar00rootroot00000000000000#!/bin/sh # based on make-bindist_win32.sh from VICE 3.1 # Written by # Marco van den Heuvel STRIP=$1 TOPSRCDIR=$2 ZIPKIND=$3 EXECUTABLES="1oom_classic_alleg4 1oom_cmdline 1oom_gfxconv 1oom_lbxedit 1oom_lbxview_alleg4 1oom_pbxdump 1oom_pbxmake 1oom_saveconv" for i in $EXECUTABLES do if [ ! -e src/$i.exe ] then echo Error: file $i not found, do a \"make\" first exit 1 fi done if [ -e $TOPSRCDIR/.git ] then VERSIONSTR=`git -C $TOPSRCDIR describe --tags` else VERSIONSTR=vUnknown fi PACKAGESTR=1oom-$VERSIONSTR-msdos BINDISTDIR=$PACKAGESTR ZIPNAME=$PACKAGESTR.zip mkdir $BINDISTDIR mkdir $BINDISTDIR/doc echo $PACKAGESTR > $BINDISTDIR/1version.txt for i in $EXECUTABLES do $STRIP src/$i.exe done cp src/1oom_classic_alleg4.exe $BINDISTDIR/1classic.exe cp src/1oom_cmdline.exe $BINDISTDIR/1cmdline.exe cp src/1oom_gfxconv.exe $BINDISTDIR/1gfxconv.exe cp src/1oom_lbxview_alleg4.exe $BINDISTDIR/1lbxview.exe cp src/1oom_lbxedit.exe $BINDISTDIR/1lbxedit.exe cp src/1oom_pbxmake.exe $BINDISTDIR/1pbxmake.exe cp src/1oom_pbxdump.exe $BINDISTDIR/1pbxdump.exe cp src/1oom_saveconv.exe $BINDISTDIR/1savconv.exe for p in pbxin format list usage do for i in $TOPSRCDIR/doc/$p*.txt do FNAME=${i#$TOPSRCDIR/doc/} cp $i $BINDISTDIR/doc/${FNAME/$p\_/} done done cp $TOPSRCDIR/README.md $BINDISTDIR/1README.txt cp $TOPSRCDIR/COPYING $BINDISTDIR/1COPYING.txt unix2dos -q $BINDISTDIR/*.txt $BINDISTDIR/doc/*.txt if [ -e extrabindist_common ] then cp extrabindist_common/* $BINDISTDIR fi if [ -e extrabindist_msdos ]; then cp extrabindist_msdos/* $BINDISTDIR fi if test x"$ZIPKIND" = "xzip"; then zip -r -9 -q $ZIPNAME $BINDISTDIR || die echo zip $ZIPNAME created rm -f -r $BINDISTDIR else echo dir $BINDISTDIR created fi 1oom-1.11.2/make-bindist_win32.sh000066400000000000000000000025331476061725400164130ustar00rootroot00000000000000#!/bin/sh # based on make-bindist_win32.sh from VICE 3.1 # Written by # Marco van den Heuvel STRIP=$1 TOPSRCDIR=$2 ZIPKIND=$3 EXECUTABLES="1oom_classic_sdl1 1oom_classic_sdl2 1oom_cmdline 1oom_gfxconv 1oom_lbxedit 1oom_lbxview_sdl1 1oom_lbxview_sdl2 1oom_pbxdump 1oom_pbxmake 1oom_saveconv" for i in $EXECUTABLES do if [ ! -e src/$i.exe ] then echo Error: file $i not found, do a \"make\" first exit 1 fi done if [ -e $TOPSRCDIR/.git ] then VERSIONSTR=`git -C $TOPSRCDIR describe --tags` else VERSIONSTR=vUnknown fi PACKAGESTR=1oom-$VERSIONSTR-win32 BINDISTDIR=$PACKAGESTR ZIPNAME=$PACKAGESTR.zip mkdir $BINDISTDIR mkdir $BINDISTDIR/doc echo $PACKAGESTR > $BINDISTDIR/1version.txt for i in $EXECUTABLES do $STRIP src/$i.exe cp src/$i.exe $BINDISTDIR done cp $TOPSRCDIR/doc/*.txt $BINDISTDIR/doc cp $TOPSRCDIR/README.md $BINDISTDIR/1README.txt cp $TOPSRCDIR/COPYING $BINDISTDIR/1COPYING.txt unix2dos -q $BINDISTDIR/*.txt $BINDISTDIR/doc/*.txt if [ -e extrabindist_common ] then cp extrabindist_common/* $BINDISTDIR fi if [ -e extrabindist_win32 ]; then cp extrabindist_win32/* $BINDISTDIR fi if test x"$ZIPKIND" = "xzip"; then zip -r -9 -q $ZIPNAME $BINDISTDIR || die echo zip $ZIPNAME created rm -f -r $BINDISTDIR else echo dir $BINDISTDIR created fi 1oom-1.11.2/src/000077500000000000000000000000001476061725400132525ustar00rootroot000000000000001oom-1.11.2/src/Makefile.am000066400000000000000000000137471476061725400153220ustar00rootroot00000000000000bin_PROGRAMS = if COMPILE_UICMDLINE bin_PROGRAMS += 1oom_cmdline endif if COMPILE_UICLASSIC if COMPILE_UICLASSIC_SDL1 bin_PROGRAMS += 1oom_classic_sdl1 endif if COMPILE_UICLASSIC_SDL2 bin_PROGRAMS += 1oom_classic_sdl2 endif if COMPILE_UICLASSIC_ALLEG4 bin_PROGRAMS += 1oom_classic_alleg4 endif endif if COMPILE_TOOLS bin_PROGRAMS += 1oom_pbxdump 1oom_pbxmake 1oom_gfxconv 1oom_saveconv 1oom_lbxedit if COMPILE_TOOLS_SDL1 bin_PROGRAMS += 1oom_lbxview_sdl1 endif if COMPILE_TOOLS_SDL2 bin_PROGRAMS += 1oom_lbxview_sdl2 endif if COMPILE_TOOLS_ALLEG4 bin_PROGRAMS += 1oom_lbxview_alleg4 endif endif SUBDIRS = hw os ui game DIST_SUBDIRS = hw os ui game util_sources = \ bits.h \ boolvec.h \ cfg.c \ cfg.h \ comp.h \ gameapi.h \ gfxaux.c \ gfxaux.h \ gfxscale.h \ hw.h \ lbx.c \ lbx.h \ lbxfont.c \ lbxfont.h \ lbxgfx.c \ lbxgfx.h \ lbxpal.c \ lbxpal.h \ lib.c \ lib.h \ log.c \ log.h \ main.c \ main.h \ menu.c \ menu.h \ options.c \ options.h \ os.h \ pbx.c \ pbx.h \ rnd.c \ rnd.h \ types.h \ ui.h \ util.c \ util.h \ util_cstr.c \ util_cstr.h \ util_math.c \ util_math.h \ version.h audio_sources = \ fmt_id.h \ fmt_mus.c \ fmt_mus.h \ fmt_sfx.c \ fmt_sfx.h ui_sources = \ font8x8.c \ font8x8.h \ font8x8_draw.c \ font8x8_draw.h \ kbd.c \ kbd.h \ mouse.c \ mouse.h \ palette.c \ palette.h pic_sources = \ fmt_pic.c \ fmt_pic.h BUILT_SOURCES = version.inc .PHONY: version.inc.indirect version.inc: version.inc.indirect version.inc.indirect: $(SHELL) $(srcdir)/version.sh $(top_srcdir) $(srcdir)/version.inc @USE_GIT@ @VERSION_1OOM@ EXTRA_DIST = version.sh AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src common_libs = @OS_LIBS@ game_lib = $(top_builddir)/src/game/libgame.a gamemain_lib = $(top_builddir)/src/game/libgamemain.a gamesaveconv_lib = $(top_builddir)/src/game/libgamesaveconv.a uicmdline_lib = $(top_builddir)/src/ui/cmdline/libuicmdline.a hwnop_lib = $(top_builddir)/src/hw/nop/libhwnop.a 1oom_cmdline_libs = $(gamemain_lib) $(game_lib) $(uicmdline_lib) $(game_lib) $(hwnop_lib) $(common_libs) 1oom_cmdline_SOURCES = $(util_sources) 1oom_cmdline_LDADD = $(1oom_cmdline_libs) @READLINE_LIBS@ 1oom_cmdline_DEPENDENCIES = $(1oom_cmdline_libs) uiclassic_lib = $(top_builddir)/src/ui/classic/libuiclassic.a hwsdl1_lib = $(top_builddir)/src/hw/sdl/1/libhwsdl1.a 1oom_classic_sdl1_libs = $(gamemain_lib) $(game_lib) $(uiclassic_lib) $(game_lib) $(uiclassic_lib) $(hwsdl1_lib) $(common_libs) 1oom_classic_sdl1_SOURCES = $(audio_sources) $(util_sources) $(ui_sources) 1oom_classic_sdl1_LDADD = $(1oom_classic_sdl1_libs) @HW_SDL1_LIBS@ @EXTRA_SDL1_LIBS@ @SAMPLERATE_LIBS@ 1oom_classic_sdl1_DEPENDENCIES = $(1oom_classic_sdl1_libs) uinop_lib = $(top_builddir)/src/ui/nop/libuinop.a 1oom_lbxview_sdl1_libs = $(hwsdl1_lib) $(uinop_lib) $(common_libs) 1oom_lbxview_sdl1_SOURCES = lbxview.c $(audio_sources) $(util_sources) $(ui_sources) $(pic_sources) 1oom_lbxview_sdl1_LDADD = $(1oom_lbxview_sdl1_libs) @HW_SDL1_LIBS@ @EXTRA_SDL1_LIBS@ @SAMPLERATE_LIBS@ 1oom_lbxview_sdl1_DEPENDENCIES = $(1oom_lbxview_sdl1_libs) hwsdl2_lib = $(top_builddir)/src/hw/sdl/2/libhwsdl2.a 1oom_classic_sdl2_libs = $(gamemain_lib) $(game_lib) $(uiclassic_lib) $(game_lib) $(uiclassic_lib) $(hwsdl2_lib) $(common_libs) 1oom_classic_sdl2_SOURCES = $(audio_sources) $(util_sources) $(ui_sources) 1oom_classic_sdl2_LDADD = $(1oom_classic_sdl2_libs) @HW_SDL2_LIBS@ @EXTRA_SDL2_LIBS@ @SAMPLERATE_LIBS@ 1oom_classic_sdl2_DEPENDENCIES = $(1oom_classic_sdl2_libs) 1oom_lbxview_sdl2_libs = $(hwsdl2_lib) $(uinop_lib) $(common_libs) 1oom_lbxview_sdl2_SOURCES = lbxview.c $(audio_sources) $(util_sources) $(ui_sources) $(pic_sources) 1oom_lbxview_sdl2_LDADD = $(1oom_lbxview_sdl2_libs) @HW_SDL2_LIBS@ @EXTRA_SDL2_LIBS@ @SAMPLERATE_LIBS@ 1oom_lbxview_sdl2_DEPENDENCIES = $(1oom_lbxview_sdl2_libs) hwalleg4_lib = $(top_builddir)/src/hw/alleg/4/libhwalleg4.a 1oom_classic_alleg4_libs = $(gamemain_lib) $(game_lib) $(uiclassic_lib) $(game_lib) $(uiclassic_lib) $(hwalleg4_lib) $(common_libs) 1oom_classic_alleg4_SOURCES = $(audio_sources) $(util_sources) $(ui_sources) 1oom_classic_alleg4_LDADD = $(1oom_classic_alleg4_libs) @HW_ALLEG4_LIBS@ @EXTRA_ALLEG4_LIBS@ @SAMPLERATE_LIBS@ 1oom_classic_alleg4_DEPENDENCIES = $(1oom_classic_alleg4_libs) 1oom_lbxview_alleg4_libs = $(hwalleg4_lib) $(uinop_lib) $(common_libs) 1oom_lbxview_alleg4_SOURCES = lbxview.c $(audio_sources) $(util_sources) $(ui_sources) $(pic_sources) 1oom_lbxview_alleg4_LDADD = $(1oom_lbxview_alleg4_libs) @HW_ALLEG4_LIBS@ @EXTRA_ALLEG4_LIBS@ @SAMPLERATE_LIBS@ 1oom_lbxview_alleg4_DEPENDENCIES = $(1oom_lbxview_alleg4_libs) 1oom_lbxedit_libs = $(hwnop_lib) $(common_libs) 1oom_lbxedit_SOURCES = lbxedit.c util.c util_cstr.c lib.c log.c 1oom_lbxedit_LDADD = $(1oom_lbxedit_libs) 1oom_lbxedit_DEPENDENCIES = $(1oom_lbxedit_libs) 1oom_pbxdump_libs = $(hwnop_lib) $(common_libs) 1oom_pbxdump_SOURCES = pbxdump.c pbx.c util.c lib.c log.c 1oom_pbxdump_LDADD = $(1oom_pbxdump_libs) 1oom_pbxdump_DEPENDENCIES = $(1oom_pbxdump_libs) 1oom_pbxmake_libs = $(hwnop_lib) 1oom_pbxmake_SOURCES = pbxmake.c util.c util_cstr.c lib.c log.c 1oom_pbxmake_LDADD = $(1oom_pbxmake_libs) 1oom_pbxmake_DEPENDENCIES = $(1oom_pbxmake_libs) 1oom_gfxconv_libs = $(hwnop_lib) 1oom_gfxconv_SOURCES = gfxconv.c util.c lib.c log.c $(pic_sources) 1oom_gfxconv_LDADD = $(1oom_gfxconv_libs) 1oom_gfxconv_DEPENDENCIES = $(1oom_gfxconv_libs) 1oom_saveconv_libs = $(gamesaveconv_lib) $(hwnop_lib) $(uinop_lib) $(common_libs) 1oom_saveconv_SOURCES = saveconv.c lib.c log.c options.c util.c 1oom_saveconv_LDADD = $(1oom_saveconv_libs) 1oom_saveconv_DEPENDENCIES = $(1oom_saveconv_libs) .PHONY: libui libhw libos libgame libgamemain libos: (cd os && $(MAKE)) libhw: (cd hw && $(MAKE)) libui: (cd ui && $(MAKE)) libgame: (cd game && $(MAKE) libgame.a) libgamemain: (cd game && $(MAKE) libgamemain.a) libgamesaveconv: (cd game && $(MAKE) libgamesaveconv.a) 1oom-1.11.2/src/bits.h000066400000000000000000000050741476061725400143720ustar00rootroot00000000000000#ifndef INC_1OOM_BITS_H #define INC_1OOM_BITS_H #include "config.h" #include "types.h" /* Allow unaligned access for various platforms */ #if defined(__i386__) || defined(__x86_64__) || defined(__amd64__) #define ALLOW_UNALIGNED_ACCESS #endif #if defined(__m68020__) || defined(__m68030__) || defined(__m68040__) || defined(__m68060__) #define ALLOW_UNALIGNED_ACCESS #endif #if defined(__powerpc__) || defined(__ppc__) #define ALLOW_UNALIGNED_ACCESS #endif #define BSWAP_16(_v_) ((uint16_t)((((_v_) >> 8) & 0xff) | ((_v_) << 8))) #if !defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS #define SET_LE_16(_p_,_v_) ((*((uint16_t *)(_p_))) = (_v_)) #define GET_LE_16(_p_) (*((uint16_t const *)(_p_))) #define SET_LE_32(_p_,_v_) ((*((uint32_t *)(_p_))) = (_v_)) #define GET_LE_32(_p_) (*((uint32_t const *)(_p_))) #else #define SET_LE_16(_p_,_v_) (((uint8_t *)(_p_))[0] = ((_v_) & 0xffu), ((uint8_t *)(_p_))[1] = (((_v_) >> 8) & 0xffu)) #define GET_LE_16(_p_) (((uint16_t)(((uint8_t const *)(_p_))[0])) | (((uint16_t)(((uint8_t const *)(_p_))[1])) << 8)) #define SET_LE_32(_p_,_v_) (((uint8_t *)(_p_))[0] = ((_v_) & 0xffu), ((uint8_t *)(_p_))[1] = (((_v_) >> 8) & 0xffu), ((uint8_t *)(_p_))[2] = (((_v_) >> 16) & 0xffu), ((uint8_t *)(_p_))[3] = (((_v_) >> 24) & 0xffu)) #define GET_LE_32(_p_) (((uint32_t)GET_LE_16((_p_))) | (((uint32_t)GET_LE_16((_p_) + 2)) << 16)) #endif #define GET_LE_24(_p_) (((uint32_t)GET_LE_16((_p_))) | (((uint32_t)*(((uint8_t const *)(_p_)) + 2)) << 16)) #if defined WORDS_BIGENDIAN && defined ALLOW_UNALIGNED_ACCESS #define SET_BE_16(_p_,_v_) ((*((uint16_t *)(_p_))) = (_v_)) #define GET_BE_16(_p_) (*((uint16_t const *)(_p_))) #define SET_BE_32(_p_,_v_) ((*((uint32_t *)(_p_))) = (_v_)) #define GET_BE_32(_p_) (*((uint16_t const *)(_p_))) #else #define SET_BE_16(_p_,_v_) (((uint8_t *)(_p_))[1] = ((_v_) & 0xffu), ((uint8_t *)(_p_))[0] = (((_v_) >> 8) & 0xffu)) #define GET_BE_16(_p_) (((uint16_t)(((uint8_t const *)(_p_))[1])) | (((uint16_t)(((uint8_t const *)(_p_))[0])) << 8)) #define SET_BE_32(_p_,_v_) (((uint8_t *)(_p_))[3] = ((_v_) & 0xffu), ((uint8_t *)(_p_))[2] = (((_v_) >> 8) & 0xffu), ((uint8_t *)(_p_))[1] = (((_v_) >> 16) & 0xffu), ((uint8_t *)(_p_))[0] = (((_v_) >> 24) & 0xffu)) #define GET_BE_32(_p_) (((uint32_t)GET_BE_16((_p_) + 2)) | (((uint32_t)GET_BE_16((_p_))) << 16)) #endif #define SET_BE_24(_p_, _v_) (((uint8_t *)(_p_))[2] = ((_v_) & 0xffu), ((uint8_t *)(_p_))[1] = (((_v_) >> 8) & 0xffu), ((uint8_t *)(_p_))[0] = (((_v_) >> 16) & 0xffu)) #define GET_BE_24(_p_) ((((uint32_t)GET_BE_16((_p_))) << 8) | ((uint32_t)*(((uint8_t const *)(_p_)) + 2))) #endif 1oom-1.11.2/src/boolvec.h000066400000000000000000000042721476061725400150610ustar00rootroot00000000000000#ifndef INC_1OOM_BOOLVEC_H #define INC_1OOM_BOOLVEC_H #include #include "types.h" #define BOOLVEC_DECLARE(_name_, _fnum_) uint8_t _name_[((_fnum_) + 7) / 8] #define BOOLVEC_CLEAR(_name_, _fnum_) do { if ((_fnum_) <= 8) { (_name_)[0] = 0; } else { memset(&(_name_), 0, sizeof(_name_)); } } while (0) #define BOOLVEC_COPY(_named_, _names_, _fnum_) do { if ((_fnum_) <= 8) { (_named_)[0] = (_names_)[0]; } else { memcpy(&(_named_), &(_names_), sizeof(_named_)); } } while (0) #define BOOLVEC_COMP(_name1_, _name2_, _fnum_) (((_fnum_) <= 8) ? ((_name1_)[0] == (_name2_)[0]) : (memcmp((_name1_), (_name2_), ((_fnum_) + 7) / 8) == 0)) #define BOOLVEC_PTRPARAMI(_name_) uint8_t *_name_ #define BOOLVEC_SET0(_name_, _i_) do { int ti = (_i_); _name_[ti / 8] &= ~(1 << (ti & 7)); } while (0) #define BOOLVEC_SET1(_name_, _i_) do { int ti = (_i_); _name_[ti / 8] |= (1 << (ti & 7)); } while (0) #define BOOLVEC_SET(_name_, _i_, _v_) do { int ti = (_i_); uint8_t *tp = &(_name_[ti / 8]); if ((_v_)) { *tp |= (1 << (ti & 7)); } else { *tp &= ~(1 << (ti & 7)); } } while (0) #define BOOLVEC_IS0(_name_, _i_) ((_name_[(_i_) / 8] & (1 << ((_i_) & 7))) == 0) #define BOOLVEC_IS1(_name_, _i_) ((_name_[(_i_) / 8] & (1 << ((_i_) & 7))) != 0) #define BOOLVEC_IS_CLEAR(_name_, _fnum_) (((_fnum_) <= 8) ? ((_name_)[0] == 0) : (/*FIXME*/0)) #define BOOLVEC_ONLY1(_name_, _fnum_) (((_fnum_) <= 8) ? (((_name_)[0] != 0) && (((_name_)[0] & ((_name_)[0] - 1)) == 0)) : (/*FIXME*/0)) #define BOOLVEC_TBL_DECLARE(_name_, _tnum_, _fnum_) uint8_t _name_[(_tnum_)][((_fnum_) + 7) / 8] #define BOOLVEC_TBL_PTRPARAMM(_name_, _tnum_) &(_name_[(_tnum_)][0]) #define BOOLVEC_TBL_CLEAR(_name_, _tnum_, _fnum_) memset(&(_name_), 0, sizeof(_name_)) #define BOOLVEC_TBL_COPY1(_named_, _names_, _tnum_, _fnum_) BOOLVEC_COPY(_named_[_tnum_], _names_, _fnum_) #define BOOLVEC_TBL_SET0(_name_, _tnum_, _i_) BOOLVEC_SET0(_name_[_tnum_], _i_) #define BOOLVEC_TBL_SET1(_name_, _tnum_, _i_) BOOLVEC_SET1(_name_[_tnum_], _i_) #define BOOLVEC_TBL_SET(_name_, _tnum_, _i_) BOOLVEC_SET(_name_[_tnum_], _i_) #define BOOLVEC_TBL_IS0(_name_, _tnum_, _i_) BOOLVEC_IS0(_name_[_tnum_], _i_) #define BOOLVEC_TBL_IS1(_name_, _tnum_, _i_) BOOLVEC_IS1(_name_[_tnum_], _i_) #endif 1oom-1.11.2/src/cfg.c000066400000000000000000000205521476061725400141610ustar00rootroot00000000000000#include "config.h" #include #include #include #include "cfg.h" #include "gameapi.h" #include "hw.h" #include "lib.h" #include "log.h" #include "main.h" #include "options.h" #include "os.h" #include "types.h" #include "ui.h" #include "util.h" #include "util_cstr.h" /* -------------------------------------------------------------------------- */ static const struct cfg_module_s { const char *str; const struct cfg_items_s *items; bool const * const cond; } cfg_items_tbl[] = { { "opt", opt_cfg_items, 0 }, { "opta", opt_cfg_items_audio, &ui_use_audio }, { "game", game_cfg_items, 0 }, { "hw", hw_cfg_items, 0 }, { "hwx", hw_cfg_items_extra, 0 }, { "ui", ui_cfg_items, 0 }, { 0, 0, 0 } }; struct cfg_parse_s { const struct cfg_module_s *module; const struct cfg_items_s *item; }; /* -------------------------------------------------------------------------- */ static void cfg_parse_init(struct cfg_parse_s *ctx) { ctx->module = 0; ctx->item = 0; } static int cfg_parse_line(char *line, int lnum, struct cfg_parse_s *ctx) { const struct cfg_module_s *module; const struct cfg_items_s *item; char *p, *iname, *ival; p = strchr(line, '.'); if (!p) { log_error("Cfg: . missing on line %i\n", lnum); return -1; } *p = '\0'; iname = ++p; p = strstr(iname, " ="); if (!p) { log_error("Cfg: = missing on line %i\n", lnum); return -1; } if (p < (iname + 2)) { log_error("Cfg: item name missing on line %i\n", lnum); return -1; } *p = '\0'; p += 2; ival = *p ? (p + 1) : p; if (1 && ctx->module && ctx->module->str && ctx->item && ctx->item->name && (strcmp(ctx->module->str, line) == 0) && (strcmp(ctx->item->name, iname) == 0) ) { module = ctx->module; item = ctx->item; } else { module = 0; for (const struct cfg_module_s *m = cfg_items_tbl; m->str; ++m) { if ((strcmp(m->str, line) == 0) && ((!m->cond) || *m->cond)) { module = m; break; } } if (!module) { log_error("Cfg: unknown module on line %i\n", lnum); return -1; } again: item = 0; for (const struct cfg_items_s *i = module->items; i->name; ++i) { if (strcmp(i->name, iname) == 0) { item = i; break; } } if (!item) { if (module->items == opt_cfg_items) { /* HACK handle audio option opt -> opta move */ ++module; goto again; } log_warning("Cfg: ignoring unknown item '%s.%s' on line %i\n", line, iname, lnum); return 0; } } ctx->module = module; { const struct cfg_items_s *i; for (i = item + 1; i->name && (i->type == CFG_TYPE_COMMENT); ++i); if (!i->name) { ++ctx->module; i = ctx->module->items; } ctx->item = i; } switch (item->type) { case CFG_TYPE_INT: { uint32_t v; if (!util_parse_number(ival, &v)) { log_error("Cfg: invalid value on line %i\n", lnum); return -1; } if (item->check && (!item->check((void *)(intptr_t)(int)v))) { log_warning("Cfg: item failed check on line %i\n", lnum); return -1; } *((int *)item->var) = (int)v; } break; case CFG_TYPE_STR: if (ival[0] == '\0') { lib_free(*((char **)item->var)); *((char **)item->var) = 0; } else if (ival[0] == '"') { ++ival; if (util_cstr_parse_in_place(ival) < 0) { log_warning("Cfg: invalid value on line %i\n", lnum); return -1; } if (item->check && (!item->check(ival))) { log_warning("Cfg: item failed check on line %i\n", lnum); return -1; } lib_free(*((char **)item->var)); *((char **)item->var) = lib_stralloc(ival); } else { log_error("Cfg: invalid value on line %i\n", lnum); return -1; } break; case CFG_TYPE_BOOL: if (strcmp(ival, "true") == 0) { *((bool *)item->var) = true; } else if (strcmp(ival, "false") == 0) { *((bool *)item->var) = false; } else { log_error("Cfg: invalid value on line %i\n", lnum); return -1; } break; case CFG_TYPE_COMMENT: /* should never happen */ break; } return 0; } /* -------------------------------------------------------------------------- */ char *cfg_cfgname(void) { const char *path = os_get_path_user(); char namebuf[128]; char *s; if (!os_get_fname_cfg(namebuf, sizeof(namebuf), idstr_main, idstr_ui, idstr_hw)) { lib_sprintf(namebuf, sizeof(namebuf), "1oom_config_%s_%s_%s.txt", idstr_main, idstr_ui, idstr_hw); } s = util_concat(path, FSDEV_DIR_SEP_STR, namebuf, NULL); return s; } int cfg_load(const char *filename) { #define BUFSIZE (FSDEV_PATH_MAX + 64) FILE *fd; char buf[BUFSIZE]; int len, lnum = 0; struct cfg_parse_s ctx[1]; log_message("Cfg: loading configuration from '%s'\n", filename); fd = fopen(filename, "r"); if (!fd) { log_error("Cfg: failed to open file '%s'\n", filename); return -1; } cfg_parse_init(ctx); while ((len = util_get_line(buf, BUFSIZE, fd)) >= 0) { ++lnum; if ((len == 0) || (buf[0] == '#')) { continue; } if (cfg_parse_line(buf, lnum, ctx) < 0) { fclose(fd); return -1; } } fclose(fd); return 0; #undef BUFSIZE } int cfg_save(const char *filename) { FILE *fd; log_message("Cfg: saving configuration to '%s'\n", filename); if (os_make_path_for(filename)) { log_error("Cfg: failed to create path for '%s'\n", filename); return -1; } fd = fopen(filename, "w+"); if (!fd) { log_error("Cfg: failed to create file '%s'\n", filename); return -1; } if (fprintf(fd, "# 1oom configuration file\n") < 1) { goto fail; } for (const struct cfg_module_s *module = cfg_items_tbl; module->str; ++module) { if (module->cond && !(*module->cond)) { continue; } for (const struct cfg_items_s *item = module->items; item->name; ++item) { switch (item->type) { case CFG_TYPE_INT: if (fprintf(fd, "%s.%s = %i\n", module->str, item->name, *((const int *)item->var)) < 1) { goto fail; } break; case CFG_TYPE_STR: if (fprintf(fd, "%s.%s = ", module->str, item->name) < 1) { goto fail; } if (*((const char **)item->var) != 0) { if (fprintf(fd, "\"") < 1) { goto fail; } if (util_cstr_out(fd, *((const char **)item->var)) < 0) { goto fail; } if (fprintf(fd, "\"") < 1) { goto fail; } } if (fprintf(fd, "\n") < 1) { goto fail; } break; case CFG_TYPE_BOOL: if (fprintf(fd, "%s.%s = %s\n", module->str, item->name, (*((const bool *)item->var)) ? "true" : "false") < 1) { goto fail; } break; case CFG_TYPE_COMMENT: if (fprintf(fd, "# %s\n", item->name) < 1) { goto fail; } break; } } } if (fd) { fclose(fd); } return 0; fail: log_error("Cfg: writing to '%s' failed\n", filename); if (fd) { fclose(fd); } return -1; } 1oom-1.11.2/src/cfg.h000066400000000000000000000013161476061725400141630ustar00rootroot00000000000000#ifndef INC_1OOM_CFG_H #define INC_1OOM_CFG_H #include "types.h" struct cfg_items_s { const char *name; void *var; bool (*check)(void *var); enum { CFG_TYPE_INT, CFG_TYPE_STR, CFG_TYPE_BOOL, CFG_TYPE_COMMENT } type; }; #define CFG_ITEM_STR(_n_, _v_, _c_) { _n_, _v_, _c_, CFG_TYPE_STR } #define CFG_ITEM_INT(_n_, _v_, _c_) { _n_, _v_, _c_, CFG_TYPE_INT } #define CFG_ITEM_BOOL(_n_, _v_) { _n_, _v_, 0, CFG_TYPE_BOOL } #define CFG_ITEM_COMMENT(_s_) { _s_, 0, 0, CFG_TYPE_COMMENT } #define CFG_ITEM_END { 0, 0, 0, CFG_TYPE_INT } extern char *cfg_cfgname(void); extern int cfg_load(const char *filename); extern int cfg_save(const char *filename); #endif 1oom-1.11.2/src/comp.h000066400000000000000000000015151476061725400143630ustar00rootroot00000000000000#ifndef INC_1OOM_COMP_H #define INC_1OOM_COMP_H #ifndef MIN #define MIN(a, b) (((a) <= (b)) ? (a) : (b)) #endif #ifndef MAX #define MAX(a, b) (((a) >= (b)) ? (a) : (b)) #endif #ifndef SETMIN #define SETMIN(a, b) do { if ((b) < (a)) { (a) = (b); }} while (0) #endif #ifndef SETMAX #define SETMAX(a, b) do { if ((b) > (a)) { (a) = (b); }} while (0) #endif #ifndef SETRANGE #define SETRANGE(a, b, c) do { if (((c) <= (b)) || ((b) > (a))) { (a) = (b); } else if ((c) < (a)) { (a) = (c); } } while (0) #endif #define ADDSATT(_v_, _n_, _top_) do { int _t_; _t_ = (_v_) + (_n_); SETMIN(_t_, (_top_)); (_v_) = _t_; } while (0) #define SUBSATT(_v_, _n_, _bot_) do { int _t_; _t_ = (_v_) - (_n_); SETMAX(_t_, (_bot_)); (_v_) = _t_; } while (0) #define SUBSAT0(_v_, _n_) SUBSATT(_v_, _n_, 0) #define TBLLEN(_t_) (sizeof((_t_)) / sizeof((_t_)[0])) #endif 1oom-1.11.2/src/fmt_id.h000066400000000000000000000011041476061725400146610ustar00rootroot00000000000000#ifndef INC_1OOM_FMT_ID_H #define INC_1OOM_FMT_ID_H #define HDRID_LBXXMID 0xafde0100/*0xdeaf 1*/ #define HDRID_LBXVOC 0xafde0200/*0xdeaf 2*/ #define HDRID_MIDI 0x4d546864/*MThd*/ #define HDRID_VOC 0x43726561/*Crea*/ #define HDRID_WAV 0x52494646/*RIFF*/ #define HDRID_OGG 0x4f676753/*OggS*/ #define HDRID_FLAC 0x664c6143/*fLaC*/ #define HDR_LBXXMID_LEN 0x10 #define HDR_LBXVOC_LEN 0x10 #define HDR_VOC ((const uint8_t *)"Creative Voice File\x1a\x1a\x00\x0a\x01\x29\x11") #define HDR_VOC_LEN 0x1a #define HDR_WAV_LEN 0x2c #endif 1oom-1.11.2/src/fmt_mus.c000066400000000000000000000333521476061725400150760ustar00rootroot00000000000000#include "config.h" #include #include #include "fmt_mus.h" #include "bits.h" #include "fmt_id.h" #include "lib.h" #include "log.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define DEBUGLEVEL_FMTMUS 4 #define HDR_MIDI_LEN 0x16 typedef struct noteoff_s { uint32_t t; /* time of event */ int16_t next; /* next event, sorted by time */ uint8_t ch; /* 0 if unused, otherwise 0x8Z whe Z is channel */ uint8_t note; } noteoff_t; /* MOO1 has max. 15 pending noteoffs */ #define NOTEOFFBUFSIZE 32 struct noteoffs_s { noteoff_t tbl[NOTEOFFBUFSIZE]; /* noteoff events */ int16_t top; /* noteoff with nearest time */ int16_t pos; /* position of (likely) free tbl entry */ int8_t num; /* number of pending events */ int8_t max; /* max. number of pending events */ }; #define XMID_TICKSPERQ 60 /*#define XMID_USE_BANKS*/ /* -------------------------------------------------------------------------- */ static int8_t xmid_find_free_noteoff(struct noteoffs_s *s) { int i = s->pos; int num = NOTEOFFBUFSIZE; while (num) { if (++i == NOTEOFFBUFSIZE) { i = 0; } if (s->tbl[i].ch == 0) { s->pos = i; return i; } --num; } return -1; } static bool xmid_add_pending_noteoff(struct noteoffs_s *s, const uint8_t *data, uint32_t t_now, uint32_t duration) { uint32_t t = t_now + duration; int8_t i = xmid_find_free_noteoff(s); noteoff_t *n; if (i < 0) { log_error("XMID: BUG noteoff tbl full!\n"); return false; } n = &(s->tbl[i]); n->next = -1; n->t = t; n->ch = data[0] & 0x8f; /* 9x -> 8x */ n->note = data[1]; if (s->top < 0) { s->top = i; } else { int j, k; j = s->top; k = -1; while ((j >= 0) && (t >= s->tbl[j].t)) { k = j; j = s->tbl[j].next; } if (k < 0) { n->next = s->top; s->top = i; } else { s->tbl[k].next = i; s->tbl[i].next = j; } } if (++s->num > s->max) { s->max = s->num; } return true; } static uint32_t xmid_encode_delta_time(uint8_t *buf, uint32_t delta_time) { uint32_t len_event = 0, v = delta_time & 0x7f; while ((delta_time >>= 7) != 0) { v <<= 8; v |= (delta_time & 0x7f) | 0x80; } while (1) { buf[len_event++] = (uint8_t)(v & 0xff); if (v & 0x80) { v >>= 8; } else { return len_event; } } } static int xmid_convert_evnt(const uint8_t *data_in, uint32_t len_in, const uint8_t *timbre_tbl, uint16_t timbre_num, uint8_t *p, bool *tune_loops) { struct noteoffs_s s[1]; int rc = -1, noteons = 0, looppoint = -1; uint32_t len_out = 0, t_now = 0, delta_time = 0; bool end_found = false; *tune_loops = false; memset(s, 0, sizeof(s[0])); s->top = -1; while ((len_in > 0) && (!end_found)) { uint32_t len_event, add_extra_bytes, skip_extra_bytes; uint8_t buf_extra[4]; bool add_event; add_event = true; add_extra_bytes = 0; skip_extra_bytes = 0; switch (*data_in & 0xf0) { case 0x90: { uint32_t dt_off; uint8_t b; dt_off = 0; skip_extra_bytes = 1; while (((b = data_in[2 + skip_extra_bytes]) & 0x80) != 0) { dt_off |= b & 0x7f; dt_off <<= 7; ++skip_extra_bytes; } dt_off |= b; if (!xmid_add_pending_noteoff(s, data_in, t_now + delta_time, dt_off)) { goto fail; } } ++noteons; len_event = 3; break; case 0xb0: len_event = 3; { uint8_t c; c = data_in[1]; if (0 || ((c >= 0x20) && (c <= 0x2e)) || ((c >= 0x3a) && (c <= 0x3f)) || ((c >= 0x6e) && (c <= 0x78)) ) { LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: dropping unhandled AIL CC event %02x %02x %02x, notes %i\n", *data_in, c, data_in[2], noteons)); add_event = false; len_event = 0; skip_extra_bytes = 3; } switch (c) { case 0x74: /* AIL loop: FOR loop = 1 to n */ if (looppoint >= 0) { log_warning("XMID: nth FOR loop unimpl\n"); } else { looppoint = noteons; if (looppoint > 0) { log_warning("XMID: FOR loop after %i notes unimpl\n", looppoint); } } break; case 0x75: /* AIL loop: NEXT/BREAK */ LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: NEXT/BREAK at %i after %i notes, forcing end\n", looppoint, noteons)); if (looppoint >= 0) { *tune_loops = true; } else { log_warning("XMID: NEXT/BREAK without FOR\n"); } len_event = 0; end_found = true; add_event = true; buf_extra[0] = 0xff; buf_extra[1] = 0x2f; buf_extra[2] = 0x00; add_extra_bytes = 3; break; default: break; } } break; case 0xa0: case 0xe0: len_event = 3; break; case 0x80: log_error("XMID: unexpected noteoff\n"); goto fail; case 0xc0: len_event = 2; #ifdef XMID_USE_BANKS { int ti; uint8_t patch; uint8_t bank = 0; patch = data_in[1]; for (ti = 0; ti < timbre_num; ++ti) { if (timbre_tbl[ti * 2] == patch) { bank = timbre_tbl[ti * 2 + 1]; break; } } if (ti < timbre_num) { LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: TIMB found bank 0x%02x for patch 0x%02x\n", bank, patch)); buf_extra[0] = 0xb0 | (data_in[1] & 0xf); buf_extra[1] = 0; buf_extra[2] = bank; buf_extra[3] = 0; add_extra_bytes = 4; } else { LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: TIMB no bank for patch 0x%02x\n", patch)); } } #endif /*XMID_USE_BANKS*/ break; case 0xd0: len_event = 2; break; case 0xf0: switch (*data_in & 0xf) { case 0x08: case 0x0a: case 0x0b: case 0x0c: len_event = 1; break; case 0x0f: len_event = 3 + data_in[2]; if (data_in[1] == 0x2f) { end_found = true; } else if (data_in[1] == 0x51) { /* MOO1 seems to ignore the set tempo events as not dropping them results in wrong tempo in f.ex tune 0xA */ LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: dropping tempo %u event after %i notes\n", GET_BE_24(&data_in[3]), noteons)); add_event = false; skip_extra_bytes = len_event; } break; default: log_error("XMID: unhandled event 0x%02x\n", *data_in); goto fail; } break; default: /* 0x00..0x7f */ add_event = false; while (!(*data_in & 0x80)) { delta_time += *data_in++; --len_in; } break; } if (add_event) { uint32_t len_delta_time; uint8_t buf_delta_time[4]; while ((s->top >= 0) && ((t_now + delta_time) >= s->tbl[s->top].t)) { noteoff_t *n = &(s->tbl[s->top]); uint32_t delay_noff = n->t - t_now; len_delta_time = xmid_encode_delta_time(buf_delta_time, delay_noff); for (int i = 0; i < len_delta_time; ++i) { *p++ = buf_delta_time[i]; } len_out += len_delta_time; *p++ = n->ch; *p++ = n->note; *p++ = 0x00; len_out += 3; delta_time -= delay_noff; t_now += delay_noff; n->ch = 0; s->top = n->next; --s->num; } t_now += delta_time; len_delta_time = xmid_encode_delta_time(buf_delta_time, delta_time); delta_time = 0; for (int i = 0; i < len_delta_time; ++i) { *p++ = buf_delta_time[i]; } if (end_found) { /* last event, add remaining noteoffs */ LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: %i noteoffs at end, max %i noteoffs, total %i noteons\n", s->num, s->max, noteons)); while (s->top >= 0) { noteoff_t *n = &(s->tbl[s->top]); *p++ = n->ch; *p++ = n->note; *p++ = 0x00; *p++ = 0; len_out += 4; n->ch = 0; s->top = n->next; } s->num = 0; } for (int i = 0; i < add_extra_bytes; ++i) { *p++ = buf_extra[i]; } for (int i = 0; i < len_event; ++i) { uint8_t c; c = *data_in++; --len_in; *p++ = c; } len_out += len_event + len_delta_time + add_extra_bytes; } if (skip_extra_bytes) { data_in += skip_extra_bytes; len_in -= skip_extra_bytes; } } rc = len_out; fail: return rc; } /* -------------------------------------------------------------------------- */ mus_type_t fmt_mus_detect(const uint8_t *data, uint32_t len) { uint32_t hdrid; if (len < 32) { return MUS_TYPE_UNKNOWN; } hdrid = GET_BE_32(data); if (hdrid == HDRID_LBXXMID) { return MUS_TYPE_LBXXMID; } else if (hdrid == HDRID_MIDI) { return MUS_TYPE_MIDI; } else if (hdrid == HDRID_WAV) { return MUS_TYPE_WAV; } else if (hdrid == HDRID_OGG) { return MUS_TYPE_OGG; } else if (hdrid == HDRID_FLAC) { return MUS_TYPE_FLAC; } return MUS_TYPE_UNKNOWN; } bool fmt_mus_convert_xmid(const uint8_t *data_in, uint32_t len_in, uint8_t **data_out_ptr, uint32_t *len_out_ptr, bool *tune_loops) { uint8_t *data = NULL; const uint8_t *timbre_tbl; uint32_t len_timbre, len_evnt; uint16_t timbre_num; int len = 0; if (0 || (fmt_mus_detect(data_in, len_in) != MUS_TYPE_LBXXMID) || (len_in < 0x4e) || (memcmp(&data_in[0x10], (const uint8_t *)"FORM", 4) != 0) || (memcmp(&data_in[0x3e], (const uint8_t *)"TIMB", 4) != 0) || ((len_timbre = GET_BE_32(&data_in[0x42])), (len_in < (0x4e + len_timbre))) || (memcmp(&data_in[0x46 + len_timbre], (const uint8_t *)"EVNT", 4) != 0) || ((len_evnt = GET_BE_32(&data_in[0x4a + len_timbre])), (len_in < (0x4e + len_timbre + len_evnt))) ) { log_error("XMID: invalid header\n"); goto fail; } LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: lent %i lene %i\n", len_timbre, len_evnt)); timbre_num = GET_LE_16(&data_in[0x46]); timbre_tbl = &data_in[0x48]; data_in += 0x4e + len_timbre; /* max. len_out/len_in ratio for MOO1 data is about 1.8 */ data = lib_malloc(HDR_MIDI_LEN + len_evnt * 2); { uint8_t hdr[] = { /*00*/ 'M', 'T', 'h', 'd', /*04*/ 0, 0, 0, 6, /*08*/ 0, 0, 0, 1, /*0c*/ (XMID_TICKSPERQ >> 8) & 0xff, XMID_TICKSPERQ & 0xff, /*0e*/ 'M', 'T', 'r', 'k' /*12*/ /* length, big endian */ }; memcpy(data, hdr, sizeof(hdr)); } len = xmid_convert_evnt(data_in, len_evnt, timbre_tbl, timbre_num, &data[HDR_MIDI_LEN], tune_loops); LOG_DEBUG((DEBUGLEVEL_FMTMUS, "XMID: lene %i len %i (%f) %s\n", len_evnt, len, (double)len / (double)len_evnt, *tune_loops ? "loop" : "once")); if (len < 0) { goto fail; } SET_BE_32(&data[0x12], len); len += HDR_MIDI_LEN; data = lib_realloc(data, len); if (data_out_ptr) { *data_out_ptr = data; } if (len_out_ptr) { *len_out_ptr = len; } return true; fail: lib_free(data); if (data_out_ptr) { *data_out_ptr = NULL; } if (len_out_ptr) { *len_out_ptr = 0; } return false; } 1oom-1.11.2/src/fmt_mus.h000066400000000000000000000006731476061725400151030ustar00rootroot00000000000000#ifndef INC_1OOM_FMT_MUS_H #define INC_1OOM_FMT_MUS_H #include "types.h" typedef enum { MUS_TYPE_UNKNOWN = 0, MUS_TYPE_LBXXMID, MUS_TYPE_MIDI, MUS_TYPE_WAV, MUS_TYPE_OGG, MUS_TYPE_FLAC } mus_type_t; extern mus_type_t fmt_mus_detect(const uint8_t *data, uint32_t len); extern bool fmt_mus_convert_xmid(const uint8_t *data_in, uint32_t len_in, uint8_t **data_out_ptr, uint32_t *len_out_ptr, bool *tune_loops); #endif 1oom-1.11.2/src/fmt_pic.c000066400000000000000000000166721476061725400150530ustar00rootroot00000000000000#include "config.h" #include #include #include "fmt_pic.h" #include "bits.h" #include "lib.h" #include "log.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define DEBUGLEVEL_FMTPIC 4 /* -------------------------------------------------------------------------- */ static bool fmt_pic_pcx_detect(const uint8_t *data, uint32_t len) { int xmin, xmax, ymin, ymax; if (0 || (len < 128) || (data[0] != 10) || (data[1] > 5) || (data[2] != 1) || (data[3] != 8) || (data[65] != 1) ) { return false; } xmin = GET_LE_16(&data[4]); ymin = GET_LE_16(&data[6]); xmax = GET_LE_16(&data[8]); ymax = GET_LE_16(&data[10]); if ((xmin > xmax) || (ymin > ymax)) { return false; } return true; } static bool fmt_pic_pcx_decode(struct pic_s *pic) { int bpl, w, h, len_in = pic->len; const uint8_t *data = pic->coded; bpl = GET_LE_16(&data[66]); { int xmin, xmax, ymin, ymax; xmin = GET_LE_16(&data[4]); ymin = GET_LE_16(&data[6]); xmax = GET_LE_16(&data[8]); ymax = GET_LE_16(&data[10]); pic->w = w = xmax - xmin + 1; pic->pitch = w; pic->h = h = ymax - ymin + 1; LOG_DEBUG((DEBUGLEVEL_FMTPIC, "%s: [%i,%i]-[%i,%i] w:%i bpl:%i\n", __func__, xmin, ymin, xmax, ymax, w, bpl)); } data += 128; len_in -= 128; pic->pix = lib_malloc(w * h + 1/*bpl padding*/); for (int y = 0; y < h; ++y) { uint8_t *p; p = &(pic->pix[y * w]); for (int x = 0; x < bpl;) { uint8_t c, n; if (len_in-- == 0) { return false; } c = *data++; if (c & 0xc0) { n = c & 0x3f; if (len_in-- == 0) { return false; } c = *data++; } else { n = 1; } x += n; while (n--) { *p++ = c; } } } if ((len_in > 0) && (*data++ == 12) && (--len_in >= (256 * 3))) { uint8_t *p; pic->pal = p = lib_malloc(256 * 3); for (int i = 0; i < (256 * 3); ++i) { *p++ = *data++ / 4; } len_in -= 256 * 3; } else { pic->pal = NULL; } return true; } static bool fmt_pic_pcx_encode(struct pic_s *pic) { int len = 0, w = pic->w, h = pic->h; uint8_t *p; pic->coded = p = lib_malloc(128 + w * h * 2 + (pic->pal ? (3 * 256 + 1) : 0)); SET_BE_32(p, 0x0a050108); SET_LE_16(&p[8], w - 1); SET_LE_16(&p[10], h - 1); SET_LE_16(&p[12], 320); SET_LE_16(&p[14], 200); p[65] = 1; SET_LE_16(&p[66], w); SET_LE_16(&p[68], 1); SET_LE_16(&p[70], 320); SET_LE_16(&p[72], 200); len += 128; p += 128; for (int y = 0; y < h; ++y) { const uint8_t *q = &(pic->pix[y * pic->pitch]); int x; x = 0; while (x < w) { uint8_t n, c; n = 1; c = *q; while ((n < 0x3f) && ((x + n) < w) && (c == q[n])) { ++n; } if ((n > 1) || (c & 0xc0)) { *p++ = n | 0xc0; ++len; } *p++ = c; x += n; q += n; ++len; } } if (pic->pal) { const uint8_t *q = pic->pal; *p++ = 12; for (int i = 0; i < (256 * 3); ++i) { *p++ = *q++ * 4; } len += 256 * 3 + 1; } pic->coded = lib_realloc(pic->coded, len); pic->len = len; return true; } static bool fmt_pic_equaldef_decode(struct pic_s *pic) { const char *p = (const char *)pic->coded + 1; char c; int v, w, h; v = 0; while ((c = *p++) != 'x') { if ((c >= '0') && (c <= '9')) { v *= 10; v += c - '0'; } else { break; } } if (c != 'x') { return false; } pic->w = w = v; v = 0; while ((c = *p++) != 'c') { if ((c >= '0') && (c <= '9')) { v *= 10; v += c - '0'; } else { break; } } if (c != 'c') { return false; } pic->h = h = v; v = 0; while ((c = *p++) != '\0') { if ((c >= '0') && (c <= '9')) { v *= 10; v += c - '0'; } else { break; } } if (c != '\0') { return false; } pic->pix = lib_malloc(w * h); memset(pic->pix, v, w * h); pic->pal = NULL; return true; } static pic_type_t fmt_pic_detect(const uint8_t *data, uint32_t len) { if ((len == 0) && (data[0] == '=')) { return PIC_TYPE_EQUALDEF; } if (len < 32) { return PIC_TYPE_UNKNOWN; } if (fmt_pic_pcx_detect(data, len)) { return PIC_TYPE_PCX; } return PIC_TYPE_UNKNOWN; } static bool fmt_pic_decode(struct pic_s *pic) { pic_type_t type; pic->type = PIC_TYPE_UNKNOWN; type = fmt_pic_detect(pic->coded, pic->len); if ((type == PIC_TYPE_PCX) && fmt_pic_pcx_decode(pic)) { pic->type = PIC_TYPE_PCX; return true; } else if ((type == PIC_TYPE_EQUALDEF) && fmt_pic_equaldef_decode(pic)) { pic->type = PIC_TYPE_EQUALDEF; return true; } return false; } /* -------------------------------------------------------------------------- */ bool fmt_pic_load(const char *filename, struct pic_s *pic) { #define BUFSIZE (128 + 320 * 200 * 2 + 3 * 256 + 200) FILE *fd = 0; uint8_t *buf; bool res = false; int len, l; if (filename[0] == '=') { len = 0; buf = (uint8_t *)lib_stralloc(filename); goto ready; } buf = lib_malloc(128); if (0 || ((fd = fopen(filename, "rb")) == 0) || ((len = fread(buf, 1, 128, fd)) < 32) ) { log_error("loading '%s'\n", filename); goto fail; } if (!fmt_pic_detect(buf, len)) { log_error("unsupported picture format in '%s'\n", filename); goto fail; } buf = lib_realloc(buf, BUFSIZE); if ((l = fread(&buf[len], 1, BUFSIZE - 128, fd)) < 1) { log_error("loading '%s'\n", filename); goto fail; } if (l == (BUFSIZE - 128)) { log_error("suspiciosly large picture file '%s'\n", filename); goto fail; } len += l; ready: pic->len = len; pic->coded = buf; if (!fmt_pic_decode(pic)) { log_error("problem decoding '%s'\n", filename); goto fail; } res = true; fail: lib_free(buf); buf = NULL; pic->coded = NULL; if (fd) { fclose(fd); fd = NULL; } return res; #undef BUFSIZE } bool fmt_pic_save(const char *filename, struct pic_s *pic) { int res; if (pic->type == PIC_TYPE_PCX) { if (!fmt_pic_pcx_encode(pic)) { log_error("problem encoding '%s'\n", filename); return false; } } else { log_error("no type set for '%s'\n", filename); return false; } res = util_file_save(filename, pic->coded, pic->len); if (res != 0) { log_error("problem saving '%s'\n", filename); } lib_free(pic->coded); pic->coded = NULL; return (res == 0); } void fmt_pic_free(struct pic_s *pic) { if (pic) { lib_free(pic->pix); pic->pix = NULL; lib_free(pic->pal); pic->pal = NULL; lib_free(pic->coded); pic->coded = NULL; } } 1oom-1.11.2/src/fmt_pic.h000066400000000000000000000007401476061725400150450ustar00rootroot00000000000000#ifndef INC_1OOM_FMT_PIC_H #define INC_1OOM_FMT_PIC_H #include "types.h" typedef enum { PIC_TYPE_UNKNOWN = 0, PIC_TYPE_EQUALDEF, PIC_TYPE_PCX } pic_type_t; struct pic_s { pic_type_t type; int w, h, pitch, len; uint8_t *pix; uint8_t *pal; uint8_t *coded; }; extern bool fmt_pic_load(const char *filename, struct pic_s *pic); extern bool fmt_pic_save(const char *filename, struct pic_s *pic); extern void fmt_pic_free(struct pic_s *pic); #endif 1oom-1.11.2/src/fmt_sfx.c000066400000000000000000000413161476061725400150710ustar00rootroot00000000000000#include "config.h" #include #include #ifdef HAVE_SAMPLERATE #include #endif #include "fmt_sfx.h" #include "bits.h" #include "fmt_id.h" #include "lib.h" #include "log.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define LOW_PASS_FILTER #define DEBUGLEVEL_FMTSFX 4 struct sfx_conv_s { int16_t *data; uint32_t num; /* number of stereo samples */ uint32_t samplerate; }; /* -------------------------------------------------------------------------- */ #ifdef HAVE_SAMPLERATE static struct sfx_conv_s fmt_sfx_resample_libsamplerate(struct sfx_conv_s *s_in, int audiorate) { struct sfx_conv_s s_out = { NULL, 0, audiorate }; /* code from chocolate-doom_2.3.0 */ SRC_DATA src_data; float *data_in; uint32_t i, clipped = 0; float libsamplerate_scale = opt_libsamplerate_scale / 100.0; src_data.input_frames = s_in->num; data_in = lib_malloc(s_in->num * 2 * sizeof(float)); src_data.data_in = data_in; src_data.src_ratio = (double)audiorate / s_in->samplerate; /* We include some extra space here in case of rounding-up. */ src_data.output_frames = src_data.src_ratio * s_in->num + (audiorate / 4); src_data.data_out = lib_malloc(src_data.output_frames * 2 * sizeof(float)); /* Convert input data to floats */ for (i = 0; i < (s_in->num * 2); ++i) { data_in[i] = s_in->data[i] / 32768.0; } /* Do the sound conversion */ { int retn = src_simple(&src_data, opt_libsamplerate_mode, 2); if (retn) { log_fatal_and_die("%s: libsamplerate returned %i\n", __func__, retn); } } /* Allocate a chunk in which to expand the sound */ s_out.num = src_data.output_frames_gen; s_out.data = lib_malloc(s_out.num * 2/*16b*/ * 2/*stereo*/); /* Convert the result back into 16-bit integers. */ for (i = 0; i < src_data.output_frames_gen * 2; ++i) { /* libsamplerate does not limit itself to the -1.0 .. 1.0 range on output, so a multiplier less than INT16_MAX (32767) is required to avoid overflows or clipping. However, the smaller the multiplier, the quieter the sound effects get, and the more you have to turn down the music to keep it in balance. */ float cvtval_f = src_data.data_out[i] * libsamplerate_scale * INT16_MAX; int32_t cvtval_i = cvtval_f + (cvtval_f < 0 ? -0.5 : 0.5); /* Asymmetrical sound worries me, so we won't use -32768. */ if (cvtval_i < -INT16_MAX) { cvtval_i = -INT16_MAX; ++clipped; } else if (cvtval_i > INT16_MAX) { cvtval_i = INT16_MAX; ++clipped; } s_out.data[i] = cvtval_i; } if (clipped) { log_warning("libsamplerate clipped %i samples with scale %i\n", clipped, opt_libsamplerate_scale); } lib_free(data_in); lib_free(src_data.data_out); return s_out; } #endif /* HAVE_SAMPLERATE */ static struct sfx_conv_s fmt_sfx_resample_simple(struct sfx_conv_s *s_in, int audiorate) { struct sfx_conv_s s_out = { NULL, 0, audiorate }; /* code from chocolate-doom_2.3.0 */ uint32_t expanded_length; int expand_ratio; int i; /* Calculate the length of the expanded version of the sample. */ expanded_length = (uint32_t) ((((uint64_t) s_in->num) * audiorate) / s_in->samplerate); s_out.num = expanded_length; /* Allocate a chunk in which to expand the sound */ s_out.data = lib_malloc(expanded_length * 2/*16b*/ * 2/*stereo*/); expand_ratio = (s_in->num << 8) / s_out.num; for (i = 0; i < s_out.num; ++i) { int src; src = (i * expand_ratio) >> 8; s_out.data[i * 2 + 0] = s_in->data[src * 2 + 0]; s_out.data[i * 2 + 1] = s_in->data[src * 2 + 1]; } #ifdef LOW_PASS_FILTER /* Perform a low-pass filter on the upscaled sound to filter out high-frequency noise from the conversion process. */ if (s_in->samplerate < audiorate) { float rc, dt, alpha; /* Low-pass filter for cutoff frequency f: For sampling rate r, dt = 1 / r rc = 1 / 2*pi*f alpha = dt / (rc + dt) Filter to the half sample rate of the original sound effect (maximum frequency, by nyquist) */ dt = 1.0f / audiorate; rc = 1.0f / (3.14f * s_in->samplerate); alpha = dt / (rc + dt); /* Both channels are processed in parallel, hence [i - 2]: */ for (i = 2; i < s_out.num * 2; ++i) { s_out.data[i] = (int16_t) (alpha * s_out.data[i] + (1 - alpha) * s_out.data[i - 2]); } } #endif /* #ifdef LOW_PASS_FILTER */ return s_out; } static struct sfx_conv_s fmt_sfx_convert_voc(const uint8_t *data_in, uint32_t len_in) { struct sfx_conv_s res = { NULL, 0, 0 }; uint32_t cursize = 0; int16_t *data = NULL, *q; const uint8_t *p = data_in; if ((len_in < HDR_VOC_LEN) || (memcmp(p, HDR_VOC, HDR_VOC_LEN) != 0)) { log_error("VOC: invalid header\n"); return res; } p += HDR_VOC_LEN; len_in -= HDR_VOC_LEN; cursize = len_in * 2/*16b*/ * 2/*stereo*/; q = data = lib_malloc(cursize); while (len_in) { uint8_t block_type, ctype = 0, stereo = 0, sr; uint32_t block_size, newrate; block_type = *p++; --len_in; LOG_DEBUG((DEBUGLEVEL_FMTSFX, "VOC: block %02x ", block_type)); if (block_type == 0x00) { /* Terminator */ LOG_DEBUG((DEBUGLEVEL_FMTSFX, "\n")); break; } if (block_type > 0x08) { log_error("VOC: invalid block %02x\n", block_type); goto fail; } if (len_in < 3) { log_error("VOC: no size for block %02x\n", block_type); goto fail; } block_size = GET_LE_24(p); LOG_DEBUG((DEBUGLEVEL_FMTSFX, "sz %x ", block_size)); p += 3; len_in -= 3; if (len_in < block_size) { log_error("VOC: block %02x sz %i but only %i left\n", block_type, block_size, len_in); goto fail; } switch (block_type) { case 0x01: /* Sound data */ sr = *p++; --len_in; newrate = 1000000 / (256 - sr); ctype = *p++; --len_in; LOG_DEBUG((DEBUGLEVEL_FMTSFX, " sr %i->%iHz ct %i ", sr, newrate, ctype)); block_size -= 2; if ((res.samplerate != 0) && (res.samplerate != newrate)) { log_error("VOC: multiple sample rates unimpl (%i -> %i)\n", res.samplerate, newrate); goto fail; } res.samplerate = newrate; /* fall through */ case 0x02: /* Sound continue */ LOG_DEBUG((DEBUGLEVEL_FMTSFX, " \n")); len_in -= block_size; if (((res.num + block_size) * 4) > cursize) { uint32_t newsize; newsize = cursize + ((block_size * 4) | 0xff) + 1; LOG_DEBUG((DEBUGLEVEL_FMTSFX, " realloc %i->%i ", cursize, newsize)); data = lib_realloc(data, newsize); cursize = newsize; q = &data[res.num * 2/*stereo*/]; } /* TODO handle ctype!=0 and stereo */ if ((ctype != 0/*8-bit*/)) { log_error("VOC: non-8-bit compression type %u unimpl\n", ctype); goto fail; } res.num += block_size; while (block_size--) { int16_t s; s = (((int16_t)*p++) - 128) << 8; *q++ = s; *q++ = s; } break; case 0x03: /* Silence */ { uint16_t len_silence; len_silence = GET_LE_16(p) + 1; p += 2; len_in -= 2; sr = *p++; --len_in; newrate = 1000000 / (256 - sr); LOG_DEBUG((DEBUGLEVEL_FMTSFX, " silence %i sr %i->%iHz\n", len_silence, sr, newrate)); if (((res.num + len_silence) * 4) > cursize) { uint32_t newsize; newsize = cursize + ((len_silence * 4) | 0xff) + 1; LOG_DEBUG((DEBUGLEVEL_FMTSFX, " realloc %i->%i ", cursize, newsize)); data = lib_realloc(data, newsize); cursize = newsize; q = &data[res.num * 2/*stereo*/]; } res.num += len_silence; while (len_silence--) { *q++ = 0; *q++ = 0; } } break; case 0x04: /* Marker */ { IF_DEBUG(uint16_t marker; marker = GET_LE_16(p);) p += 2; len_in -= 2; LOG_DEBUG((DEBUGLEVEL_FMTSFX, " marker %i at %i\n", marker, p - data_in)); } break; case 0x05: /* ASCII */ LOG_DEBUG((DEBUGLEVEL_FMTSFX, " '%s'\n", p)); p += block_size; len_in -= block_size; break; case 0x06: /* Repeat */ { IF_DEBUG(uint16_t repeatnum; repeatnum = GET_LE_16(p);) p += 2; len_in -= 2; LOG_DEBUG((DEBUGLEVEL_FMTSFX, " repeat %i\n", repeatnum)); /* TODO */ } break; case 0x07: /* End repeat */ /* TODO */ LOG_DEBUG((DEBUGLEVEL_FMTSFX, "end repeat\n")); break; case 0x08: /* Extended */ { uint16_t tc; IF_DEBUG(uint8_t pack;) tc = GET_LE_16(p); p += 2; len_in -= 2; IF_DEBUG(pack = *p;) ++p; --len_in; stereo = *p++; --len_in; newrate = stereo ? (128000000 / (65536 - tc)) : (256000000 / (65536 - tc)); if ((res.samplerate != 0) && (res.samplerate != newrate)) { log_error("VOC: multiple sample rates unimpl (%i -> %i)\n", res.samplerate, newrate); goto fail; } res.samplerate = newrate; LOG_DEBUG((DEBUGLEVEL_FMTSFX, "tc %i->%iHz pack:%02x st:%02x\n", tc, newrate, pack, stereo)); } break; default: break; } } if (len_in > 3) { log_warning("VOC: got terminator with %i bytes left\n", len_in); } res.data = data; return res; fail: lib_free(data); return res; } static struct sfx_conv_s fmt_sfx_convert_wav(const uint8_t *data_in, uint32_t len_in) { struct sfx_conv_s res = { NULL, 0, 0 }; uint32_t cursize, len = 0; int16_t *data = NULL, *q, s; const uint8_t *p = data_in; int ch_in, bps_in; if (0 || (len_in < HDR_WAV_LEN) || (memcmp(&p[0x00], (const uint8_t *)"RIFF", 0) != 0) || (memcmp(&p[0x0c], (const uint8_t *)"fmt ", 0) != 0) || (GET_LE_32(&p[0x10]) != 0x10) || (GET_LE_16(&p[0x14]) != 1) || (((ch_in = GET_LE_16(&p[0x16])) != 1) && (ch_in != 2)) || (((bps_in = GET_LE_16(&p[0x22])) != 8) && (bps_in != 16)) || (memcmp(&p[0x24], (const uint8_t *)"data", 0) != 0) || ((len = GET_LE_32(&p[0x28])) > (len_in - HDR_WAV_LEN)) ) { log_error("WAV: invalid header\n"); return res; } res.samplerate = GET_LE_32(&p[0x18]); p += HDR_WAV_LEN; len_in -= HDR_WAV_LEN; cursize = len; if (ch_in == 1) { cursize <<= 1; } if (bps_in == 8) { cursize <<= 1; } q = data = lib_malloc(cursize); if (bps_in == 8) { if (ch_in == 1) { res.num = len; for (int i = 0; i < len; ++i) { s = *p++ << 8; *q++ = s; *q++ = s; } } else { res.num = len / 2; for (int i = 0; i < (len / 2); ++i) { s = *p++ << 8; *q++ = s; s = *p++ << 8; *q++ = s; } } } else /*(bps_in == 16)*/{ const int16_t *d = (const int16_t *)p; if (ch_in == 1) { res.num = len / 2; for (int i = 0; i < (len / 2); ++i) { s = GET_LE_16(d); ++d; *q++ = s; *q++ = s; } } else { res.num = len / 4; for (int i = 0; i < (len / 4); ++i) { s = GET_LE_16(d); ++d; *q++ = s; s = GET_LE_16(d); ++d; *q++ = s; } } } res.data = data; return res; } /* -------------------------------------------------------------------------- */ sfx_type_t fmt_sfx_detect(const uint8_t *data, uint32_t len) { uint32_t hdrid; if (len < 32) { return SFX_TYPE_UNKNOWN; } hdrid = GET_BE_32(data); if (hdrid == HDRID_LBXVOC) { return SFX_TYPE_LBXVOC; } else if (hdrid == HDRID_VOC) { return SFX_TYPE_VOC; } else if (hdrid == HDRID_WAV) { return SFX_TYPE_WAV; } return SFX_TYPE_UNKNOWN; } bool fmt_sfx_convert(const uint8_t *data_in, uint32_t len_in, uint8_t **data_out_ptr, uint32_t *len_out_ptr, sfx_type_t *type_out, int audiorate, bool add_wav_header) { sfx_type_t type = fmt_sfx_detect(data_in, len_in); struct sfx_conv_s conv_res = { NULL, 0, 0 }; uint8_t *data; uint32_t len; if (type_out) { *type_out = type; } switch (type) { case SFX_TYPE_LBXVOC: data_in += HDR_LBXVOC_LEN; len_in -= HDR_LBXVOC_LEN; /* fall through */ case SFX_TYPE_VOC: conv_res = fmt_sfx_convert_voc(data_in, len_in); break; case SFX_TYPE_WAV: conv_res = fmt_sfx_convert_wav(data_in, len_in); break; default: break; } if (!conv_res.data) { goto fail; } if (audiorate && (audiorate != conv_res.samplerate)) { struct sfx_conv_s conv_old; conv_old = conv_res; #ifdef HAVE_SAMPLERATE if (opt_use_libsamplerate) { conv_res = fmt_sfx_resample_libsamplerate(&conv_old, audiorate); } else #endif { conv_res = fmt_sfx_resample_simple(&conv_old, audiorate); } lib_free(conv_old.data); } data = (uint8_t *)conv_res.data; len = conv_res.num * 2/*16b*/ * 2/*stereo*/; if (add_wav_header) { uint8_t wav_header[] = { /*00*/ 'R', 'I', 'F', 'F', /*04*/ 0, 0, 0, 0, /* filesize - 8 */ /*08*/ 'W', 'A', 'V', 'E', /*0c*/ 'f', 'm', 't', ' ', /*10*/ 16, 0, 0, 0, /* length of fmt chunk */ /*14*/ 1, 0, /* format */ /*16*/ 2, 0, /* channels */ /*18*/ 0, 0, 0, 0, /* Hz */ /*1c*/ 0, 0, 0, 0, /* Hz * 2B/sample * stereo */ /*20*/ 4, 0, /* block align */ /*22*/ 16, 0, /* bits per sample */ /*24*/ 'd', 'a', 't', 'a', /*28*/ 0, 0, 0, 0 /* sample data size in bytes */ }; SET_LE_32(&wav_header[0x4], len + HDR_WAV_LEN - 8); SET_LE_32(&wav_header[0x18], audiorate); SET_LE_32(&wav_header[0x1c], audiorate * 4); SET_LE_32(&wav_header[0x28], len); data = lib_realloc(data, len + HDR_WAV_LEN); #ifdef WORDS_BIGENDIAN /* WAV file is little endian so swap bytes while relocating */ /* TODO maybe use the big endian variant RIFX? */ { uint16_t *q = (uint16_t *)&data[len - 2]; uint16_t *p = (uint16_t *)&data[len + HDR_WAV_LEN - 2]; int n = len / 2; while (n--) { uint16_t v = *q--; *p-- = BSWAP_16(v); } } #else memmove(&data[HDR_WAV_LEN], data, len); #endif memcpy(data, wav_header, HDR_WAV_LEN); len += HDR_WAV_LEN; } if (data_out_ptr) { *data_out_ptr = data; } if (len_out_ptr) { *len_out_ptr = len; } return true; fail: lib_free(conv_res.data); if (data_out_ptr) { *data_out_ptr = NULL; } if (len_out_ptr) { *len_out_ptr = 0; } return false; } 1oom-1.11.2/src/fmt_sfx.h000066400000000000000000000006671476061725400151020ustar00rootroot00000000000000#ifndef INC_1OOM_FMT_SFX_H #define INC_1OOM_FMT_SFX_H #include "types.h" typedef enum { SFX_TYPE_UNKNOWN = 0, SFX_TYPE_LBXVOC, SFX_TYPE_VOC, SFX_TYPE_WAV } sfx_type_t; extern sfx_type_t fmt_sfx_detect(const uint8_t *data, uint32_t len); extern bool fmt_sfx_convert(const uint8_t *data_in, uint32_t len_in, uint8_t **data_out_ptr, uint32_t *len_out_ptr, sfx_type_t *type_out, int audiorate, bool add_wav_header); #endif 1oom-1.11.2/src/font8x8.c000066400000000000000000000226241476061725400147420ustar00rootroot00000000000000/** * 8x8 monochrome bitmap fonts for rendering * Author: Daniel Hepper * * License: Public Domain * * Based on: * // Summary: font8x8.h * // 8x8 monochrome bitmap fonts for rendering * // * // Author: * // Marcel Sondaar * // International Business Machines (public domain VGA fonts) * // * // License: * // Public Domain * * Fetched from: http://dimensionalrift.homelinux.net/combuster/mos3/?p=viewsource&file=/modules/gfx/font8_8.asm **/ #include // Constant: font8x8_basic // Contains an 8x8 font map for unicode points U+0000 - U+007F (basic latin) uint8_t font8x8_basic[128][8] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0000 (nul) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0001 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0002 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0003 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0004 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0005 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0006 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0007 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0008 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0009 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000A { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000B { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000C { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000E { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+000F { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0010 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0011 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0012 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0013 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0014 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0015 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0016 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0017 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0018 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0019 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001A { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001B { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001C { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001D { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001E { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+001F { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0020 (space) { 0x18, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x18, 0x00}, // U+0021 (!) { 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0022 (") { 0x36, 0x36, 0x7F, 0x36, 0x7F, 0x36, 0x36, 0x00}, // U+0023 (#) { 0x0C, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x0C, 0x00}, // U+0024 ($) { 0x00, 0x63, 0x33, 0x18, 0x0C, 0x66, 0x63, 0x00}, // U+0025 (%) { 0x1C, 0x36, 0x1C, 0x6E, 0x3B, 0x33, 0x6E, 0x00}, // U+0026 (&) { 0x06, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0027 (') { 0x18, 0x0C, 0x06, 0x06, 0x06, 0x0C, 0x18, 0x00}, // U+0028 (() { 0x06, 0x0C, 0x18, 0x18, 0x18, 0x0C, 0x06, 0x00}, // U+0029 ()) { 0x00, 0x66, 0x3C, 0xFF, 0x3C, 0x66, 0x00, 0x00}, // U+002A (*) { 0x00, 0x0C, 0x0C, 0x3F, 0x0C, 0x0C, 0x00, 0x00}, // U+002B (+) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+002C (,) { 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00}, // U+002D (-) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+002E (.) { 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x00}, // U+002F (/) { 0x3E, 0x63, 0x73, 0x7B, 0x6F, 0x67, 0x3E, 0x00}, // U+0030 (0) { 0x0C, 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x3F, 0x00}, // U+0031 (1) { 0x1E, 0x33, 0x30, 0x1C, 0x06, 0x33, 0x3F, 0x00}, // U+0032 (2) { 0x1E, 0x33, 0x30, 0x1C, 0x30, 0x33, 0x1E, 0x00}, // U+0033 (3) { 0x38, 0x3C, 0x36, 0x33, 0x7F, 0x30, 0x78, 0x00}, // U+0034 (4) { 0x3F, 0x03, 0x1F, 0x30, 0x30, 0x33, 0x1E, 0x00}, // U+0035 (5) { 0x1C, 0x06, 0x03, 0x1F, 0x33, 0x33, 0x1E, 0x00}, // U+0036 (6) { 0x3F, 0x33, 0x30, 0x18, 0x0C, 0x0C, 0x0C, 0x00}, // U+0037 (7) { 0x1E, 0x33, 0x33, 0x1E, 0x33, 0x33, 0x1E, 0x00}, // U+0038 (8) { 0x1E, 0x33, 0x33, 0x3E, 0x30, 0x18, 0x0E, 0x00}, // U+0039 (9) { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x00}, // U+003A (:) { 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C, 0x06}, // U+003B (;) { 0x18, 0x0C, 0x06, 0x03, 0x06, 0x0C, 0x18, 0x00}, // U+003C (<) { 0x00, 0x00, 0x3F, 0x00, 0x00, 0x3F, 0x00, 0x00}, // U+003D (=) { 0x06, 0x0C, 0x18, 0x30, 0x18, 0x0C, 0x06, 0x00}, // U+003E (>) { 0x1E, 0x33, 0x30, 0x18, 0x0C, 0x00, 0x0C, 0x00}, // U+003F (?) { 0x3E, 0x63, 0x7B, 0x7B, 0x7B, 0x03, 0x1E, 0x00}, // U+0040 (@) { 0x0C, 0x1E, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x00}, // U+0041 (A) { 0x3F, 0x66, 0x66, 0x3E, 0x66, 0x66, 0x3F, 0x00}, // U+0042 (B) { 0x3C, 0x66, 0x03, 0x03, 0x03, 0x66, 0x3C, 0x00}, // U+0043 (C) { 0x1F, 0x36, 0x66, 0x66, 0x66, 0x36, 0x1F, 0x00}, // U+0044 (D) { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x46, 0x7F, 0x00}, // U+0045 (E) { 0x7F, 0x46, 0x16, 0x1E, 0x16, 0x06, 0x0F, 0x00}, // U+0046 (F) { 0x3C, 0x66, 0x03, 0x03, 0x73, 0x66, 0x7C, 0x00}, // U+0047 (G) { 0x33, 0x33, 0x33, 0x3F, 0x33, 0x33, 0x33, 0x00}, // U+0048 (H) { 0x1E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0049 (I) { 0x78, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E, 0x00}, // U+004A (J) { 0x67, 0x66, 0x36, 0x1E, 0x36, 0x66, 0x67, 0x00}, // U+004B (K) { 0x0F, 0x06, 0x06, 0x06, 0x46, 0x66, 0x7F, 0x00}, // U+004C (L) { 0x63, 0x77, 0x7F, 0x7F, 0x6B, 0x63, 0x63, 0x00}, // U+004D (M) { 0x63, 0x67, 0x6F, 0x7B, 0x73, 0x63, 0x63, 0x00}, // U+004E (N) { 0x1C, 0x36, 0x63, 0x63, 0x63, 0x36, 0x1C, 0x00}, // U+004F (O) { 0x3F, 0x66, 0x66, 0x3E, 0x06, 0x06, 0x0F, 0x00}, // U+0050 (P) { 0x1E, 0x33, 0x33, 0x33, 0x3B, 0x1E, 0x38, 0x00}, // U+0051 (Q) { 0x3F, 0x66, 0x66, 0x3E, 0x36, 0x66, 0x67, 0x00}, // U+0052 (R) { 0x1E, 0x33, 0x07, 0x0E, 0x38, 0x33, 0x1E, 0x00}, // U+0053 (S) { 0x3F, 0x2D, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0054 (T) { 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x00}, // U+0055 (U) { 0x33, 0x33, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0056 (V) { 0x63, 0x63, 0x63, 0x6B, 0x7F, 0x77, 0x63, 0x00}, // U+0057 (W) { 0x63, 0x63, 0x36, 0x1C, 0x1C, 0x36, 0x63, 0x00}, // U+0058 (X) { 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x0C, 0x1E, 0x00}, // U+0059 (Y) { 0x7F, 0x63, 0x31, 0x18, 0x4C, 0x66, 0x7F, 0x00}, // U+005A (Z) { 0x1E, 0x06, 0x06, 0x06, 0x06, 0x06, 0x1E, 0x00}, // U+005B ([) { 0x03, 0x06, 0x0C, 0x18, 0x30, 0x60, 0x40, 0x00}, // U+005C (\) { 0x1E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1E, 0x00}, // U+005D (]) { 0x08, 0x1C, 0x36, 0x63, 0x00, 0x00, 0x00, 0x00}, // U+005E (^) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF}, // U+005F (_) { 0x0C, 0x0C, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+0060 (`) { 0x00, 0x00, 0x1E, 0x30, 0x3E, 0x33, 0x6E, 0x00}, // U+0061 (a) { 0x07, 0x06, 0x06, 0x3E, 0x66, 0x66, 0x3B, 0x00}, // U+0062 (b) { 0x00, 0x00, 0x1E, 0x33, 0x03, 0x33, 0x1E, 0x00}, // U+0063 (c) { 0x38, 0x30, 0x30, 0x3e, 0x33, 0x33, 0x6E, 0x00}, // U+0064 (d) { 0x00, 0x00, 0x1E, 0x33, 0x3f, 0x03, 0x1E, 0x00}, // U+0065 (e) { 0x1C, 0x36, 0x06, 0x0f, 0x06, 0x06, 0x0F, 0x00}, // U+0066 (f) { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0067 (g) { 0x07, 0x06, 0x36, 0x6E, 0x66, 0x66, 0x67, 0x00}, // U+0068 (h) { 0x0C, 0x00, 0x0E, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+0069 (i) { 0x30, 0x00, 0x30, 0x30, 0x30, 0x33, 0x33, 0x1E}, // U+006A (j) { 0x07, 0x06, 0x66, 0x36, 0x1E, 0x36, 0x67, 0x00}, // U+006B (k) { 0x0E, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x1E, 0x00}, // U+006C (l) { 0x00, 0x00, 0x33, 0x7F, 0x7F, 0x6B, 0x63, 0x00}, // U+006D (m) { 0x00, 0x00, 0x1F, 0x33, 0x33, 0x33, 0x33, 0x00}, // U+006E (n) { 0x00, 0x00, 0x1E, 0x33, 0x33, 0x33, 0x1E, 0x00}, // U+006F (o) { 0x00, 0x00, 0x3B, 0x66, 0x66, 0x3E, 0x06, 0x0F}, // U+0070 (p) { 0x00, 0x00, 0x6E, 0x33, 0x33, 0x3E, 0x30, 0x78}, // U+0071 (q) { 0x00, 0x00, 0x3B, 0x6E, 0x66, 0x06, 0x0F, 0x00}, // U+0072 (r) { 0x00, 0x00, 0x3E, 0x03, 0x1E, 0x30, 0x1F, 0x00}, // U+0073 (s) { 0x08, 0x0C, 0x3E, 0x0C, 0x0C, 0x2C, 0x18, 0x00}, // U+0074 (t) { 0x00, 0x00, 0x33, 0x33, 0x33, 0x33, 0x6E, 0x00}, // U+0075 (u) { 0x00, 0x00, 0x33, 0x33, 0x33, 0x1E, 0x0C, 0x00}, // U+0076 (v) { 0x00, 0x00, 0x63, 0x6B, 0x7F, 0x7F, 0x36, 0x00}, // U+0077 (w) { 0x00, 0x00, 0x63, 0x36, 0x1C, 0x36, 0x63, 0x00}, // U+0078 (x) { 0x00, 0x00, 0x33, 0x33, 0x33, 0x3E, 0x30, 0x1F}, // U+0079 (y) { 0x00, 0x00, 0x3F, 0x19, 0x0C, 0x26, 0x3F, 0x00}, // U+007A (z) { 0x38, 0x0C, 0x0C, 0x07, 0x0C, 0x0C, 0x38, 0x00}, // U+007B ({) { 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00}, // U+007C (|) { 0x07, 0x0C, 0x0C, 0x38, 0x0C, 0x0C, 0x07, 0x00}, // U+007D (}) { 0x6E, 0x3B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // U+007E (~) { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} // U+007F }; 1oom-1.11.2/src/font8x8.h000066400000000000000000000001421476061725400147360ustar00rootroot00000000000000#ifndef INC_1OOM_FONT8X8_H #define INC_1OOM_FONT8X8_H extern char font8x8_basic[128][8]; #endif 1oom-1.11.2/src/font8x8_draw.c000066400000000000000000000024041476061725400157510ustar00rootroot00000000000000#include "types.h" #include "font8x8.h" #include "hw.h" void font8x8_drawchar(int dx, int dy, uint16_t pitch, uint8_t c, uint8_t fg, uint8_t bg) { uint8_t *p = hw_video_get_buf() + dx + dy * pitch; for (int y = 0; y < 8; ++y) { uint8_t b; b = font8x8_basic[c][y]; for (int x = 0; x < 8; ++x) { p[x] = (b & (1 << (x))) ? fg : bg; } p += pitch; } } void font8x8_drawstr(int x, int y, uint16_t pitch, const char *str, uint8_t fg, uint8_t bg) { char c; while ((c = *str++)) { if (c == '\n') { x = 0; y += 8; continue; } font8x8_drawchar(x, y, pitch, c, fg, bg); x += 8; if (x > (pitch - 8)) { x = 0; y += 8; } } } void font8x8_drawstr_rect(int x1, int y1, int x2, int y2, uint16_t pitch, const char *str, uint8_t fg, uint8_t bg) { int x = x1, y = y1; char c; while ((c = *str++)) { if (y > (y2 - 8)) { break; } if (c == '\n') { x = x1; y += 8; continue; } font8x8_drawchar(x, y, pitch, c, fg, bg); x += 8; if (x > (x2 - 8)) { x = x1; y += 8; } } } 1oom-1.11.2/src/font8x8_draw.h000066400000000000000000000006351476061725400157620ustar00rootroot00000000000000#ifndef INC_1OOM_FONT8X8_DRAW_H #define INC_1OOM_FONT8X8_DRAW_H #include "types.h" extern void font8x8_drawchar(int dx, int dy, uint16_t pitch, uint8_t c, uint8_t fg, uint8_t bg); extern void font8x8_drawstr(int x, int y, uint16_t pitch, const char *str, uint8_t fg, uint8_t bg); extern void font8x8_drawstr_rect(int x1, int y1, int x2, int y2, uint16_t pitch, const char *str, uint8_t fg, uint8_t bg); #endif 1oom-1.11.2/src/game/000077500000000000000000000000001476061725400141635ustar00rootroot000000000000001oom-1.11.2/src/game/Makefile.am000066400000000000000000000033211476061725400162160ustar00rootroot00000000000000AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src noinst_LIBRARIES = libgame.a libgamemain.a libgamesaveconv.a libgamemain_a_SOURCES = \ game.c libgame_a_SOURCES = \ game.h \ game_ai.c \ game_ai.h \ game_ai_classic.c \ game_ai_classic.h \ game_audience.c \ game_audience.h \ game_aux.c \ game_aux.h \ game_battle.c \ game_battle.h \ game_battle_human.c \ game_battle_human.h \ game_bomb.c \ game_bomb.h \ game_cheat.c \ game_cheat.h \ game_design.c \ game_design.h \ game_diplo.c \ game_diplo.h \ game_election.c \ game_election.h \ game_end.h \ game_endecode.h \ game_event.c \ game_event.h \ game_fleet.c \ game_fleet.h \ game_ground.c \ game_ground.h \ game_misc.c \ game_misc.h \ game_nebula.c \ game_nebula.h \ game_new.c \ game_new.h \ game_news.c \ game_news.h \ game_num.c \ game_num.h \ game_nump.c \ game_nump.h \ game_parsed.c \ game_parsed.h \ game_planet.c \ game_planet.h \ game_save.c \ game_save.h \ game_save_moo13.c \ game_save_moo13.h \ game_shipdesign.c \ game_shipdesign.h \ game_shiptech.c \ game_shiptech.h \ game_spy.c \ game_spy.h \ game_stat.c \ game_stat.h \ game_str.c \ game_str_shipnames.c \ game_str.h \ game_strp.c \ game_strp.h \ game_tech.c \ game_tech.h \ game_techtypes.h \ game_turn.c \ game_turn.h \ game_turn_start.c \ game_turn_start.h \ game_types.h libgamesaveconv_a_SOURCES = \ game_nebula.c \ game_nebula.h \ game_save.c \ game_save.h \ game_str_shipnames.c \ game_str.h 1oom-1.11.2/src/game/game.c000066400000000000000000000777431476061725400152620ustar00rootroot00000000000000#include "config.h" #include #include #include "main.h" #include "cfg.h" #include "game.h" #include "gameapi.h" #include "game_ai.h" #include "game_aux.h" #include "game_misc.h" #include "game_new.h" #include "game_num.h" #include "game_nump.h" #include "game_end.h" #include "game_event.h" #include "game_save.h" #include "game_save_moo13.h" #include "game_strp.h" #include "game_turn.h" #include "game_tech.h" #include "log.h" #include "options.h" #include "rnd.h" #include "ui.h" #include "util.h" /* -------------------------------------------------------------------------- */ bool game_opt_skip_intro_always = false; static bool game_opt_skip_intro = false; static bool game_opt_new_game = false; static bool game_opt_continue = false; static int game_opt_load_game = 0; static const char *game_opt_load_fname = 0; static bool game_opt_undo_enabled = true; static bool game_opt_year_save_enabled = false; static bool game_opt_init_save_enabled = true; static bool game_opt_next_turn = false; static struct game_end_s game_opt_end = { GAME_END_NONE, 0, 0, 0, 0 }; static struct game_new_options_s game_opt_new = GAME_NEW_OPTS_DEFAULT; struct game_new_options_s game_opt_custom = GAME_NEW_OPTS_DEFAULT; static int game_opt_new_value = 200; static int game_opt_custom_race_value = 0xaaaaa0; static int game_opt_custom_banner_value = 666660; static int game_opt_custom_isai_value = 111110; bool game_opt_message_filter[FINISHED_NUM] = { false, false, false, false, false, false }; static struct game_s game; static struct game_aux_s game_aux; /* -------------------------------------------------------------------------- */ static void game_start(struct game_s *g) { if (g->seed == 0) { g->seed = rnd_get_new_seed(); log_message("Game: seed was 0, got new seed 0x%0x\n", g->seed); } if (g->ai_id >= GAME_AI_NUM) { log_warning("Game: AI ID was %i >= %i, setting to %i (%s)\n", g->ai_id, GAME_AI_NUM, GAME_AI_CLASSIC, game_ais[GAME_AI_CLASSIC]->name); g->ai_id = GAME_AI_CLASSIC; } game_ai = game_ais[g->ai_id]; game_update_production(g); game_update_tech_util(g); if (game_num_update_on_load) { for (int i = 0; i < g->players; ++i) { game_update_eco_on_waste(g, i, false); game_update_seen_by_orbit(g, i); } } game_update_within_range(g); game_update_visibility(g); game_update_have_reserve_fuel(g); } static void game_stop(struct game_s *g) { g->gaux->flag_cheat_galaxy = false; g->gaux->flag_cheat_elections = false; g->gaux->flag_cheat_events = false; g->gaux->flag_cheat_spy_hint = false; g->gaux->flag_cheat_stars = false; g->gaux->flag_cheat_tech_hint = false; } static void game_set_opts_from_value(struct game_new_options_s *go, int v) { int v2; v2 = v % 10; v = v / 10; go->difficulty = v2; v2 = v % 10; v = v / 10; go->galaxy_size = v2; go->players = v; } static int game_get_opts_value(const struct game_s *g) { return g->difficulty + g->galaxy_size * 10 + g->players * 100; } static void game_set_custom_opts_from_cfg(struct game_new_options_s *go) { uint32_t races = game_opt_custom_race_value; uint32_t banners = game_opt_custom_banner_value; uint32_t is_ai = game_opt_custom_isai_value; for (int i = 0; i < PLAYER_NUM; ++i) { go->pdata[i].race = races % 0x10; races /= 0x10; go->pdata[i].banner = banners % 10; banners /= 10; go->pdata[i].is_ai = is_ai % 10; is_ai /= 10; } } static void game_save_custom_opts_to_cfg(struct game_new_options_s *go) { game_opt_custom_race_value = 0; game_opt_custom_banner_value = 0; game_opt_custom_isai_value = 0; for (int i = PLAYER_NUM - 1; i >= 0; --i) { game_opt_custom_race_value *= 0x10; game_opt_custom_race_value += go->pdata[i].race; game_opt_custom_banner_value *= 10; game_opt_custom_banner_value += go->pdata[i].banner; game_opt_custom_isai_value *= 10; game_opt_custom_isai_value += go->pdata[i].is_ai; } } void game_apply_rules(void) { if (game_opt_fix_bugs) { game_num_fix_bugs(); } if (game_opt_fix_guardian_repair) { game_num_fix_guardian_repair(); } if (game_opt_fix_starting_ships) { game_num_fix_starting_ships(); } } /* -------------------------------------------------------------------------- */ static int game_opt_do_new_seed(char **argv, void *var) { uint32_t vo, vr, vb, vs, va; char buf[512]; char *stropt = NULL; char *strrace = NULL; char *strbanner = NULL; char *strseed = NULL; char *strhuman = NULL; strncpy(buf, argv[1], 511); buf[511] = 0; { char *p = buf; stropt = (*p != ':') ? p : NULL; p = strchr(p, ':'); if (p) { *p++ = 0; strrace = (*p != ':') ? p : NULL; p = strchr(p, ':'); if (p) { *p++ = 0; strbanner = (*p != ':') ? p : NULL; p = strchr(p, ':'); if (p) { *p++ = 0; strseed = (*p != ':') ? p : NULL; p = strchr(p, ':'); if (p) { *p++ = 0; strhuman = (*p != ':') ? p : NULL; } } } } } { uint32_t v = 0, v2; if (stropt) { if (!util_parse_number(stropt, &v)) { log_error("invalid value '%s'\n", stropt); return -1; } } else { v = game_opt_new_value; } vo = v; v2 = v % 10; v = v / 10; if (v2 > DIFFICULTY_NUM) { log_error("invalid difficulty num %i\n", v2); return -1; } game_opt_new.difficulty = v2; v2 = v % 10; v = v / 10; if (v2 > GALAXY_SIZE_HUGE) { log_error("invalid galaxy size num %i\n", v2); return -1; } game_opt_new.galaxy_size = v2; v2 = v % 10; if ((v2 < 2) || (v2 > PLAYER_NUM)) { log_error("invalid players num %i\n", v2); return -1; } game_opt_new.players = v2; } { uint32_t v = 0, v2; if (strrace) { if (!util_parse_number(strrace, &v)) { log_error("invalid value '%s'\n", strrace); return -1; } } else { v = 0; } vr = v; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v & 0xf; v = v >> 4; if (v2 > RACE_NUM) { log_error("invalid race num %i\n", v2); return -1; } v2 = v2 ? (v2 - 1) : RACE_RANDOM; game_opt_new.pdata[i].race = v2; } } { uint32_t v = 0, v2; if (strbanner) { if (!util_parse_number(strbanner, &v)) { log_error("invalid value '%s'\n", strbanner); return -1; } } else { v = 0; } vb = v; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v % 10; v = v / 10; if (v2 > BANNER_NUM) { log_error("invalid banner num %i\n", v2); return -1; } v2 = v2 ? (v2 - 1) : BANNER_RANDOM; game_opt_new.pdata[i].banner = v2; } } { uint32_t v = 0; if (strseed) { if (!util_parse_number(strseed, &v)) { log_error("invalid value '%s'\n", strseed); return -1; } } else { v = 0; } vs = v; game_opt_new.galaxy_seed = v; } { uint32_t v = 0, v2; if (strhuman) { if (!util_parse_number(strhuman, &v)) { log_error("invalid value '%s'\n", strhuman); return -1; } } else { v = 1; } va = v; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v % 10; v = v / 10; game_opt_new.pdata[i].is_ai = !v2; } } game_opt_skip_intro = true; game_opt_load_game = 0; game_opt_load_fname = 0; game_opt_continue = false; game_opt_new_game = true; log_message("Game: -new %u:0x%x:%u:0x%x:%u\n", vo, vr, vb, vs, va); return 0; } static int game_opt_set_new_name(char **argv, void *var) { uint32_t v = 0; char *buf; if (!util_parse_number(argv[1], &v)) { log_error("invalid value '%s'\n", argv[1]); return -1; } else if ((v < 1) || (v > PLAYER_NUM)) { log_error("invalid player num %i\n", v); return -1; } buf = game_opt_new.pdata[v - 1].playername; strncpy(buf, argv[2], EMPEROR_NAME_LEN); buf[EMPEROR_NAME_LEN - 1] = '\0'; log_message("Game: player %i name '%s'\n", v, buf); return 0; } static int game_opt_set_new_home(char **argv, void *var) { uint32_t v = 0; char *buf; if (!util_parse_number(argv[1], &v)) { log_error("invalid value '%s'\n", argv[1]); return -1; } else if ((v < 1) || (v > PLAYER_NUM)) { log_error("invalid player num %i\n", v); return -1; } buf = game_opt_new.pdata[v - 1].homename; strncpy(buf, argv[2], PLANET_NAME_LEN); buf[PLANET_NAME_LEN - 1] = '\0'; log_message("Game: player %i home '%s'\n", v, buf); return 0; } static int game_opt_set_new_ai(char **argv, void *var) { uint32_t v = 0; if (!util_parse_number(argv[1], &v)) { log_error("invalid value '%s'\n", argv[1]); return -1; } else if (v > GAME_AI_NUM) { log_error("invalid AI num %i\n", v); return -1; } game_opt_new.ai_id = v; log_message("Game: AI type %i '%s'\n", v, game_ais[v]->name); return 0; } static int game_opt_do_load(char **argv, void *var) { uint32_t v = 0; if (1 && util_parse_number(argv[1], &v) && (((v >= 1) && (v <= NUM_ALL_SAVES)) || ((v >= 2300) && (v <= 9999))) ) { game_opt_load_game = v; game_opt_load_fname = 0; log_message("Game: load game %i\n", game_opt_load_game); } else { game_opt_load_game = 0; game_opt_load_fname = argv[1]; log_message("Game: load game '%s'\n", game_opt_load_fname); } game_opt_skip_intro = true; game_opt_continue = false; game_opt_new_game = false; return 0; } static int game_opt_do_continue(char **argv, void *var) { game_opt_load_game = 0; game_opt_load_fname = 0; game_opt_skip_intro = true; game_opt_continue = true; game_opt_new_game = false; log_message("Game: continue game\n"); return 0; } static int dump_strings(char **argv, void *var) { game_str_dump(); return -1; } static int dump_numbers(char **argv, void *var) { game_num_dump(); return -1; } /* -------------------------------------------------------------------------- */ const char *idstr_main = "game"; bool main_use_lbx = true; bool main_use_cfg = true; void (*main_usage)(void) = 0; const struct cmdline_options_s main_cmdline_options_early[] = { { "-dumpstr", 0, dump_strings, NULL, NULL, "Dump strings in PBXIN format" }, { "-dumpnum", 0, dump_numbers, NULL, NULL, "Dump numbers in PBXIN format" }, { 0, 0, 0, 0, 0, 0 } }; const struct cmdline_options_s main_cmdline_options[] = { { "-new", 1, game_opt_do_new_seed, 0, "GAMESEED", "Start new game using given game seed\n" "GAMESEED is OPT[:RACES[:BANNERS[:GSEED[:HUMANS]]]]\n" "OPT is PLAYERS*100+GALAXYSIZE*10+DIFFICULTY\n 2..6, 0..3 = small..huge, 0..4 = simple..impossible\n default same as last new game\n" "RACES is PLAYERnRACE*(0x10^n), n=0..5\n 0 = random, 1..0xA = human..darlok\n default 0 (all random)\n" "BANNERS is PLAYERnBANNER*(10^n), n=0..5\n 0 = random, 1..6 = blue..yellow\n default 0 (all random)\n" "GSEED is a 32 bit galaxy seed or 0 for random\n default 0\n" "HUMANS is PLAYERnISHUMAN*(10^n), n=0..5\n default 1 (player 1 is human, others AI)" }, { "-ngn", 2, game_opt_set_new_name, 0, "PLAYER NAME", "Set new game emperor name for player 1..6" }, { "-ngh", 2, game_opt_set_new_home, 0, "PLAYER NAME", "Set new game home world name for player 1..6" }, { "-nga", 1, game_opt_set_new_ai, 0, "AITYPE", "Set new game AI type (0..1)" }, { "-load", 1, game_opt_do_load, 0, "SAVE", "Load game (1..8, 2300.. or filename)\n1..6 are regular save slots\n7 is continue game\n8 is undo\n2300 and over are yearly saves" }, { "-continue", 0, game_opt_do_continue, 0, NULL, "Continue game" }, { "-undo", 0, options_enable_bool_var, (void *)&game_opt_undo_enabled, NULL, "Enable undo saves" }, { "-noundo", 0, options_disable_bool_var, (void *)&game_opt_undo_enabled, NULL, "Disable undo saves" }, { "-yearsave", 0, options_enable_bool_var, (void *)&game_opt_year_save_enabled, NULL, "Enable yearly saves" }, { "-noyearsave", 0, options_disable_bool_var, (void *)&game_opt_year_save_enabled, NULL, "Disable yearly saves" }, { "-skipintro", 0, options_enable_bool_var, (void *)&game_opt_skip_intro_always, NULL, "Skip intro" }, { "-noskipintro", 0, options_disable_bool_var, (void *)&game_opt_skip_intro_always, NULL, "Do not skip intro" }, { "-nextturn", 0, options_enable_bool_var, (void *)&game_opt_next_turn, NULL, "Go directly to next turn (for reproducing bugs)" }, { 0, 0, 0, 0, 0, 0 } }; /* -------------------------------------------------------------------------- */ static bool game_cfg_check_difficulty_value(void *val) { int v = (int)(intptr_t)val; if (v >= DIFFICULTY_NUM) { log_error("invalid difficulty num %i\n", v); return false; } return true; } static bool game_cfg_check_galaxy_size_value(void *val) { int v = (int)(intptr_t)val; if (v > GALAXY_SIZE_HUGE) { log_error("invalid galaxy size num %i\n", v); return false; } return true; } static bool game_cfg_check_players_value(void *val) { int v = (int)(intptr_t)val; if ((v < 2) || (v > PLAYER_NUM)) { log_error("invalid players num %i\n", v); return false; } return true; } static bool game_cfg_check_custom_game_ai_id(void *val) { int v = (int)(intptr_t)val; if (v >= GAME_AI_NUM || v < 0) { log_error("invalid ai id %i\n", v); return false; } return true; } static bool game_cfg_check_new_game_opts(void *val) { int v2, v = (int)(intptr_t)val; v2 = v % 10; v = v / 10; if (v2 >= DIFFICULTY_NUM) { log_error("invalid difficulty num %i\n", v2); return false; } v2 = v % 10; v = v / 10; if (v2 > GALAXY_SIZE_HUGE) { log_error("invalid galaxy size num %i\n", v2); return false; } v2 = v % 10; if ((v2 < 2) || (v2 > PLAYER_NUM)) { log_error("invalid players num %i\n", v2); return false; } return true; } static bool game_cfg_check_race_value(void *val) { int v2, v = (int)(intptr_t)val; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v % 0x10; v = v / 0x10; if (v2 > RACE_RANDOM) { log_error("invalid race num %i\n", v2); return false; } } return true; } static bool game_cfg_check_banner_value(void *val) { int v2, v = (int)(intptr_t)val; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v % 10; v = v / 10; if (v2 > BANNER_RANDOM) { log_error("invalid banner num %i\n", v2); return false; } } return true; } static bool game_cfg_check_isai_value(void *val) { int v2, v = (int)(intptr_t)val; for (int i = 0; i < PLAYER_NUM; ++i) { v2 = v % 10; v = v / 10; if (v2 > 1) { log_error("invalid isai num %i\n", v2); return false; } } return true; } const struct cfg_items_s game_cfg_items[] = { CFG_ITEM_BOOL("undo", &game_opt_undo_enabled), CFG_ITEM_BOOL("yearsave", &game_opt_year_save_enabled), CFG_ITEM_BOOL("initsave", &game_opt_init_save_enabled), CFG_ITEM_BOOL("skipintro", &game_opt_skip_intro_always), CFG_ITEM_BOOL("skiprandomnews", &game_opt_skip_random_news), CFG_ITEM_BOOL("news_orion_colonized", &game_num_news_orion), CFG_ITEM_COMMENT("PLAYERS*100+GALAXYSIZE*10+DIFFICULTY"), CFG_ITEM_COMMENT(" 2..6, 0..3 = small..huge, 0..4 = simple..impossible"), CFG_ITEM_INT("new_game_opts", &game_opt_new_value, game_cfg_check_new_game_opts), CFG_ITEM_INT("custom_game_ai_id", &game_opt_custom.ai_id, game_cfg_check_custom_game_ai_id), CFG_ITEM_INT("custom_game_difficulty", &game_opt_custom.difficulty, game_cfg_check_difficulty_value), CFG_ITEM_INT("custom_game_galaxy_size", &game_opt_custom.galaxy_size, game_cfg_check_galaxy_size_value), CFG_ITEM_INT("custom_game_players", &game_opt_custom.players, game_cfg_check_players_value), CFG_ITEM_INT("custom_game_races", &game_opt_custom_race_value, game_cfg_check_race_value), CFG_ITEM_INT("custom_game_banners", &game_opt_custom_banner_value, game_cfg_check_banner_value), CFG_ITEM_INT("custom_game_isai", &game_opt_custom_isai_value, game_cfg_check_isai_value), CFG_ITEM_INT("custom_game_galaxy_seed", &game_opt_custom.galaxy_seed, NULL), CFG_ITEM_BOOL("custom_game_improved_galaxy_generator", &game_opt_custom.improved_galaxy_generator), CFG_ITEM_BOOL("custom_game_nebulae", &game_opt_custom.nebulae), CFG_ITEM_INT("custom_game_home_max_pop", &game_opt_custom.homeworlds.max_pop, NULL), CFG_ITEM_INT("custom_game_home_special", &game_opt_custom.homeworlds.special, NULL), CFG_ITEM_INT("custom_game_home_num_dist_checks", &game_opt_custom.homeworlds.num_dist_checks, NULL), CFG_ITEM_INT("custom_game_home_num_ok_planet_checks", &game_opt_custom.homeworlds.num_ok_planet_checks, NULL), CFG_ITEM_INT("custom_game_home_num_scouts", &game_opt_custom.homeworlds.num_scouts, NULL), CFG_ITEM_INT("custom_game_home_num_fighters", &game_opt_custom.homeworlds.num_fighters, NULL), CFG_ITEM_INT("custom_game_home_num_colony_ships", &game_opt_custom.homeworlds.num_colony_ships, NULL), CFG_ITEM_BOOL("custom_game_home_armed_colony_ships", &game_opt_custom.homeworlds.armed_colony_ships), CFG_ITEM_BOOL("msg_filter_fact", &game_opt_message_filter[FINISHED_FACT]), CFG_ITEM_BOOL("msg_filter_popmax", &game_opt_message_filter[FINISHED_POPMAX]), CFG_ITEM_BOOL("msg_filter_soilatmos", &game_opt_message_filter[FINISHED_SOILATMOS]), CFG_ITEM_BOOL("msg_filter_stargate", &game_opt_message_filter[FINISHED_STARGATE]), CFG_ITEM_BOOL("msg_filter_shield", &game_opt_message_filter[FINISHED_SHIELD]), CFG_ITEM_INT("rules_tech_cost_mul", &game_num_tech_costmul, NULL), CFG_ITEM_INT("rules_tech_cost_mul_human", &game_num_tech_costmuld2, NULL), CFG_ITEM_INT("rules_tech_cost_mul_ai", &game_num_tech_costmula2, NULL), CFG_ITEM_BOOL("rules_ai_transport_range_fix", &game_num_ai_trans_range_fix), CFG_ITEM_BOOL("rules_ai_4th_colony_curse_fix", &game_num_ai_4_colony_curse_fix), CFG_ITEM_BOOL("rules_ai_first_tech_cost_fix", &game_num_ai_first_tech_cost_fix), CFG_ITEM_BOOL("rules_doom_stack_fix", &game_num_doom_stack_fix), CFG_ITEM_BOOL("rules_bt_no_tohit_acc", &game_num_bt_no_tohit_acc), CFG_ITEM_BOOL("rules_bt_oracle_fix", &game_num_bt_oracle_fix), CFG_ITEM_BOOL("rules_bt_precap_tohit", &game_num_bt_precap_tohit), CFG_ITEM_BOOL("rules_bt_wait_no_reload", &game_num_bt_wait_no_reload), CFG_ITEM_BOOL("rules_deterministic_rng", &game_num_deterministic), CFG_ITEM_BOOL("rules_first_tech_rp_fix", &game_num_first_tech_rp_fix), CFG_ITEM_BOOL("rules_hidden_child_labor_fix", &game_num_hidden_child_labor_fix), CFG_ITEM_BOOL("rules_leaving_trans_fix", &game_num_leaving_trans_fix), CFG_ITEM_BOOL("rules_monster_rest_attack", &game_num_monster_rest_att), CFG_ITEM_BOOL("rules_pop_tenths_fix", &game_num_pop_tenths_fix), CFG_ITEM_BOOL("rules_factory_cost_fix", &game_num_factory_cost_fix), CFG_ITEM_BOOL("rules_colonized_factories_fix", &game_num_colonized_factories_fix), CFG_ITEM_BOOL("rules_newtech_adjust_fix", &game_num_newtech_adjust_fix), CFG_ITEM_BOOL("rules_slider_eco_done_fix", &game_num_slider_eco_done_fix), CFG_ITEM_BOOL("rules_cond_switch_to_ind_fix", &game_num_cond_switch_to_ind_fix), CFG_ITEM_BOOL("rules_waste_adjust_fix", &game_num_waste_adjust_fix), CFG_ITEM_BOOL("rules_slider_respects_locks", &game_num_slider_respects_locks), CFG_ITEM_BOOL("rules_orbital_bio_fix", &game_num_orbital_bio_fix), CFG_ITEM_BOOL("rules_orbital_weap_any", &game_num_orbital_weap_any), CFG_ITEM_BOOL("rules_orbital_weap_4", &game_num_orbital_weap_4), CFG_ITEM_BOOL("rules_orbital_torpedo", &game_num_orbital_torpedo), CFG_ITEM_BOOL("rules_orbital_comp_fix", &game_num_orbital_comp_fix), CFG_ITEM_BOOL("rules_extended_reloc_range", &game_num_extended_reloc_range), CFG_ITEM_BOOL("rules_retreat_redir_fix", &game_num_retreat_redir_fix), CFG_ITEM_BOOL("rules_ship_scanner_fix", &game_num_ship_scanner_fix), CFG_ITEM_BOOL("rules_ship_stargate_redir_fix", &game_num_stargate_redir_fix), CFG_ITEM_BOOL("rules_ship_trans_redir_fix", &game_num_trans_redir_fix), CFG_ITEM_BOOL("rules_soil_rounding_fix", &game_num_soil_rounding_fix), CFG_ITEM_BOOL("rules_waste_calc_fix", &game_num_waste_calc_fix), CFG_ITEM_BOOL("rules_ai_fleet_cheating_fix", &game_num_ai_fleet_cheating_fix), CFG_ITEM_BOOL("rules_fix_bugs", &game_opt_fix_bugs), CFG_ITEM_BOOL("rules_fix_guardian_repair", &game_opt_fix_guardian_repair), CFG_ITEM_BOOL("rules_fix_starting_ships", &game_opt_fix_starting_ships), CFG_ITEM_END }; /* -------------------------------------------------------------------------- */ int main_handle_option(const char *argv) { if (game_opt_end.type == GAME_END_NONE) { if ((argv[1] == '\0') && (argv[0] >= '0') && (argv[0] <= '3')) { switch (argv[0]) { case '0': game_opt_end.type = GAME_END_WON_GOOD; break; case '1': game_opt_end.type = GAME_END_LOST_FUNERAL; break; case '2': game_opt_end.type = GAME_END_LOST_EXILE; break; case '3': game_opt_end.type = GAME_END_WON_TYRANT; break; } game_opt_load_game = 0; game_opt_load_fname = 0; game_opt_new_game = false; game_opt_skip_intro = true; game_opt_continue = false; return 0; } else if (strcmp(argv, "YOMAMA") == 0) { log_message("Game: skip intro for YOMAMA\n"); game_opt_skip_intro = true; return 0; } else if (strcmp(argv, "s") == 0) { log_message("Game: direct continue\n"); game_opt_load_game = 0; game_opt_load_fname = 0; game_opt_new_game = false; game_opt_skip_intro = true; game_opt_continue = true; return 0; } } else { if (game_opt_end.varnum == 0) { switch (game_opt_end.type) { case GAME_END_LOST_EXILE: game_opt_end.name = argv; break; default: game_opt_end.race = atoi(argv); break; } } else if (game_opt_end.varnum == 1) { switch (game_opt_end.type) { case GAME_END_WON_GOOD: case GAME_END_WON_TYRANT: game_opt_end.name = argv; log_message("Game: ending %s %i '%s'\n", (game_opt_end.type == GAME_END_WON_GOOD) ? "good" : "tyrant", game_opt_end.race, game_opt_end.name); break; case GAME_END_LOST_FUNERAL: game_opt_end.banner_dead = atoi(argv); log_message("Game: ending funeral %i %i\n", game_opt_end.race, game_opt_end.banner_dead); break; case GAME_END_LOST_EXILE: log_message("Game: ending exile '%s'\n", game_opt_end.name); break; default: break; } } else { return -1; } ++game_opt_end.varnum; return 0; } return -1; } int main_do(void) { struct game_end_s game_end = game_opt_end; if (ui_late_init()) { return 1; } game_aux_init(&game_aux, &game); game_save_check_saves(game_aux.savenamebuf, game_aux.savenamebuflen); if ((game_opt_end.type != GAME_END_NONE) && (game_opt_end.varnum == 2)) { goto do_ending; } if (!(game_opt_skip_intro || game_opt_skip_intro_always)) { ui_play_intro(); } while (1) { struct game_new_options_s game_new_opts = GAME_NEW_OPTS_DEFAULT; struct game_new_options_s game_challenge_opts = GAME_NEW_OPTS_DEFAULT; main_menu_action_t main_menu_action; int load_game_i = 0; if (game_opt_new_game) { game_opt_new_game = false; game_new_opts = game_opt_new; goto main_menu_new_game; } else if (game_opt_load_fname) { if (game_save_do_load_fname(game_opt_load_fname, 0, &game)) { log_fatal_and_die("Game: could not load save '%s'\n", game_opt_load_fname); } game_opt_load_fname = 0; goto main_menu_start_game; } else if (game_opt_load_game) { load_game_i = game_opt_load_game; if (load_game_i < 2300) { --load_game_i; } game_opt_load_game = 0; if ((load_game_i >= 2300) || game_save_tbl_have_save[load_game_i]) { goto main_menu_load_game; } else { log_warning("Game: direct load game %i failed due to missing savegame\n", load_game_i + 1); /* try again, now with game_opt_load_game set to 0 */ continue; } } else if (game_opt_continue) { game_opt_continue = false; if (game_save_tbl_have_save[GAME_SAVE_I_CONTINUE]) { goto main_menu_continue_game; } else { log_warning("Game: direct continue failed due to missing savegame\n"); /* try again, now with game_opt_continue set to false */ continue; } } else { game_set_opts_from_value(&game_new_opts, game_opt_new_value); game_set_custom_opts_from_cfg(&game_opt_custom); main_menu_action = ui_main_menu(&game_new_opts, &game_opt_custom, &game_challenge_opts, &load_game_i); } switch (main_menu_action) { case MAIN_MENU_ACT_NEW_GAME: main_menu_new_game: game_new(&game, &game_aux, &game_new_opts); game_opt_new_value = game_get_opts_value(&game); if (game_opt_init_save_enabled) { game_save_do_save_i(GAME_SAVE_I_INIT, "Init", &game); } break; case MAIN_MENU_ACT_CUSTOM_GAME: game_new(&game, &game_aux, &game_opt_custom); game_save_custom_opts_to_cfg(&game_opt_custom); if (game_opt_init_save_enabled) { game_save_do_save_i(GAME_SAVE_I_INIT, "Init", &game); } break; case MAIN_MENU_ACT_CHALLENGE_GAME: game_new(&game, &game_aux, &game_challenge_opts); if (game_opt_init_save_enabled) { game_save_do_save_i(GAME_SAVE_I_INIT, "Init", &game); } break; case MAIN_MENU_ACT_TUTOR: game_new_tutor(&game, &game_aux); break; case MAIN_MENU_ACT_LOAD_GAME: main_menu_load_game: if (0 || ((load_game_i < NUM_ALL_SAVES) && game_save_do_load_i(load_game_i, &game)) || ((load_game_i >= 2300) && game_save_do_load_year(load_game_i, 0, &game)) ) { log_fatal_and_die("Game: could not load save %i\n", load_game_i); } break; case MAIN_MENU_ACT_LOAD_GAME_MOO13: { char fname[12] = "SAVEX.GAM"; fname[4] = load_game_i + '0' + 1; /* FIXME */ if (game_save_de_moo13(&game, fname) < 0) { continue; } } break; case MAIN_MENU_ACT_CONTINUE_GAME: main_menu_continue_game: if (game_save_do_load_i(GAME_SAVE_I_CONTINUE, &game)) { log_fatal_and_die("Game: could not start or continue from save 7\n"); } break; case MAIN_MENU_ACT_QUIT_GAME: log_message("Game: quit (main)\n"); goto done; } main_menu_start_game: game_aux_start(&game_aux, &game); game_start(&game); ui_game_start(&game); game_end.type = GAME_END_NONE; while ((game_end.type == GAME_END_NONE) || (game_end.type == GAME_END_FINAL_WAR)) { for (; ((game_end.type == GAME_END_NONE) || (game_end.type == GAME_END_FINAL_WAR)) && (game.active_player < game.players); ++game.active_player) { if (!IS_HUMAN(&game, game.active_player) || (!IS_ALIVE(&game, game.active_player))) { continue; } if (game_opt_next_turn) { game_opt_next_turn = false; break; } switch (ui_game_turn(&game, &load_game_i, game.active_player)) { case UI_TURN_ACT_LOAD_GAME: main_menu_action = MAIN_MENU_ACT_LOAD_GAME; ui_game_end(&game); goto main_menu_load_game; case UI_TURN_ACT_QUIT_GAME: if (game_save_do_save_i(GAME_SAVE_I_CONTINUE, "Continue", &game)) { log_error("Game: could create continue save\n"); } game_end.type = GAME_END_QUIT; break; case UI_TURN_ACT_NEXT_TURN: if (game_opt_undo_enabled && game_save_do_save_i(GAME_SAVE_I_UNDO, "Undo", &game)) { log_error("Game: could create undo save\n"); } if (game_opt_year_save_enabled && game_save_do_save_year(NULL, &game)) { log_error("Game: could create year save\n"); } break; } } if (game_end.type != GAME_END_QUIT) { game_end = game_turn_process(&game); } game.active_player = PLAYER_0; } ui_game_end(&game); do_ending: switch (game_end.type) { case GAME_END_QUIT: log_message("Game: quit (ingame)\n"); break; case GAME_END_NONE: case GAME_END_FINAL_WAR: break; case GAME_END_WON_GOOD: ui_play_ending_good(game_end.race, game_end.name); break; case GAME_END_WON_TYRANT: ui_play_ending_tyrant(game_end.race, game_end.name); break; case GAME_END_LOST_FUNERAL: ui_play_ending_funeral(game_end.race, game_end.banner_dead); break; case GAME_END_LOST_EXILE: ui_play_ending_exile(game_end.name); break; } game_end.type = GAME_END_NONE; game_stop(&game); } done: return 0; } void main_do_shutdown(void) { /* TODO save game if in progress */ game_aux_shutdown(&game_aux); game_str_shutdown(); } 1oom-1.11.2/src/game/game.h000066400000000000000000000261741476061725400152570ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_H #define INC_1OOM_GAME_H #include "boolvec.h" #include "game_planet.h" #include "game_shipdesign.h" #include "game_shiptech.h" #include "game_types.h" #include "types.h" typedef struct fleet_enroute_s { player_id_t owner; uint16_t x; uint16_t y; uint8_t dest; /* planet index */ uint8_t speed; bool retreat; BOOLVEC_DECLARE(visible, PLAYER_NUM); shipcount_t ships[NUM_SHIPDESIGNS]; } fleet_enroute_t; typedef struct transport_s { player_id_t owner; uint16_t x; uint16_t y; uint8_t dest; /* planet index */ uint8_t speed; BOOLVEC_DECLARE(visible, PLAYER_NUM); uint16_t pop; } transport_t; typedef struct fleet_orbit_s { BOOLVEC_DECLARE(visible, PLAYER_NUM); shipcount_t ships[NUM_SHIPDESIGNS]; } fleet_orbit_t; typedef struct techdata_s { uint8_t percent[TECH_FIELD_NUM]; /* tech level % */ int16_t slider[TECH_FIELD_NUM]; /* % */ uint16_t slider_lock[TECH_FIELD_NUM]; /* FIXME should be boolvec but uiobj uses uint16_t */ uint32_t investment[TECH_FIELD_NUM]; uint8_t project[TECH_FIELD_NUM]; uint32_t cost[TECH_FIELD_NUM]; uint16_t completed[TECH_FIELD_NUM]; /* number of completed projects (len of srd[i].researchcompleted) */ } techdata_t; #define TECH_TIER_NUM 10 #define TECH_PER_FIELD 60 #define TECH_MAX_LEVEL 100 typedef struct shipresearch_s { shipdesign_t design[NUM_SHIPDESIGNS]; uint8_t researchlist[TECH_FIELD_NUM][TECH_TIER_NUM][3]; uint8_t researchcompleted[TECH_FIELD_NUM][TECH_PER_FIELD]; bool have_reserve_fuel[NUM_SHIPDESIGNS]; uint16_t year[NUM_SHIPDESIGNS]; shipsum_t shipcount[NUM_SHIPDESIGNS]; } shipresearch_t; typedef struct empiretechorbit_s { race_t race; banner_t banner; trait1_t trait1; trait2_t trait2; int8_t ai_p3_countdown; int8_t ai_p2_countdown; BOOLVEC_DECLARE(contact, PLAYER_NUM); BOOLVEC_DECLARE(contact_broken, PLAYER_NUM); int16_t relation1[PLAYER_NUM]; int16_t relation2[PLAYER_NUM]; uint8_t diplo_type[PLAYER_NUM]; int16_t diplo_val[PLAYER_NUM]; uint16_t diplo_p1[PLAYER_NUM]; int16_t diplo_p2[PLAYER_NUM]; int16_t trust[PLAYER_NUM]; treaty_t broken_treaty[PLAYER_NUM]; int8_t blunder[PLAYER_NUM]; tech_field_t tribute_field[PLAYER_NUM]; uint8_t tribute_tech[PLAYER_NUM]; int16_t mood_treaty[PLAYER_NUM]; int16_t mood_trade[PLAYER_NUM]; int16_t mood_tech[PLAYER_NUM]; int16_t mood_peace[PLAYER_NUM]; treaty_t treaty[PLAYER_NUM]; uint16_t trade_bc[PLAYER_NUM]; int16_t trade_percent[PLAYER_NUM]; spymode_t spymode_next[PLAYER_NUM]; uint16_t au_want_trade[PLAYER_NUM]; tech_field_t au_want_field[PLAYER_NUM]; uint8_t au_want_tech[PLAYER_NUM]; uint8_t au_tech_trade_num[PLAYER_NUM]; tech_field_t au_tech_trade_field[PLAYER_NUM][TECH_SPY_MAX]; uint8_t au_tech_trade_tech[PLAYER_NUM][TECH_SPY_MAX]; tech_field_t offer_field[PLAYER_NUM]; uint8_t offer_tech[PLAYER_NUM]; /* tech_i */ uint16_t offer_bc[PLAYER_NUM]; player_id_t au_ally_attacker[PLAYER_NUM]; player_id_t au_ask_break_treaty[PLAYER_NUM]; player_id_t attack_bounty[PLAYER_NUM]; player_id_t bounty_collect[PLAYER_NUM]; tech_field_t attack_gift_field[PLAYER_NUM]; uint8_t attack_gift_tech[PLAYER_NUM]; int16_t attack_gift_bc[PLAYER_NUM]; int16_t hatred[PLAYER_NUM]; uint8_t have_met[PLAYER_NUM]; /* 0, 1, 2 */ uint16_t trade_established_bc[PLAYER_NUM]; uint8_t have_planet_shield; /* 0, 5, 10, 15, 20 */ uint16_t planet_shield_cost; int16_t spying[PLAYER_NUM]; /* tenths */ uint16_t spyfund[PLAYER_NUM]; spymode_t spymode[PLAYER_NUM]; int16_t security; /* tenths */ uint16_t spies[PLAYER_NUM]; int32_t total_trade_bc; uint32_t ship_maint_bc; uint32_t bases_maint_bc; uint16_t spying_maint_bc; uint16_t percent_prod_total_to_actual; int32_t total_maint_bc; uint32_t total_research_bc; uint32_t total_production_bc; uint32_t reserve_bc; int16_t tax; uint8_t base_shield; uint8_t base_comp; uint8_t base_weapon; bool have_sub_space_int; uint8_t antidote; planet_type_t have_colony_for; uint8_t have_eco_restoration_n; /* 2, 3, 5, 10, 20 */ uint8_t have_terraform_n; /* 0, 10, ... 120 */ uint8_t terraform_cost_per_inc; /* 5..2 */ bool have_adv_soil_enrich; bool have_atmos_terra; bool have_soil_enrich; uint8_t inc_pop_cost; /* cost of adding 1 population */ uint8_t scanner_range; /* 3, 5, 7, 9 */ bool have_ia_scanner; bool have_adv_scanner; bool have_hyperspace_comm; bool have_stargates; uint8_t colonist_oper_factories; /* 2.. */ uint8_t factory_cost; /* 10..2 */ uint8_t factory_adj_cost; /* meklar ? factory_cost : factory_cost*colonist_oper_factories/2 */ uint8_t ind_waste_scale; /* 0, 2, ..10 */ uint8_t fuel_range; /* 3..10, 30 */ bool have_combat_transporter; techdata_t tech; uint8_t have_engine; /* 1.. */ uint8_t shipdesigns_num; fleet_orbit_t orbit[PLANETS_MAX]; uint8_t spyreportfield[PLAYER_NUM][TECH_FIELD_NUM]; uint16_t spyreportyear[PLAYER_NUM]; int8_t shipi_colony; int8_t shipi_bomber; } empiretechorbit_t; #define NEWTECH_MAX 15 typedef struct monster_s { uint8_t exists; /* 0..3 */ int16_t x; int16_t y; player_id_t killer; /* MOO1: 0 or id+1 */ uint8_t dest; int8_t counter; int8_t nuked; /* planets destroyed */ } monster_t; typedef struct newtech_s { tech_field_t field; uint8_t tech; techsource_t source; int8_t v06; /* 4: race_t giver 2: NEWTECH_V06_ORION or planet_i ruins or -(planet_i+1) artifact */ player_id_t stolen_from; bool frame; player_id_t other1; player_id_t other2; } newtech_t; typedef struct nexttech_s { uint8_t num; uint8_t tech[TECH_NEXT_MAX]; } nexttech_t; #define NEWTECH_V06_ORION PLANETS_MAX typedef struct newtechs_s { uint8_t num; newtech_t d[NEWTECH_MAX]; nexttech_t next[TECH_FIELD_NUM]; } newtechs_t; #define GAME_EVENT_TBL_NUM 20 #define HELP_SHOWN_NUM 16 typedef struct gameevents_s { uint16_t year; BOOLVEC_DECLARE(done, GAME_EVENT_TBL_NUM); int8_t diplo_msg_subtype; /* -1..13 */ uint8_t have_plague; /* 0..3 */ player_id_t plague_player; uint8_t plague_planet_i; int plague_val; bool have_quake; player_id_t quake_player; uint8_t quake_planet_i; uint8_t have_nova; /* 0..3 */ player_id_t nova_player; uint8_t nova_planet_i; int8_t nova_years; int nova_val; uint8_t have_accident; /* 0..2 */ player_id_t accident_player; uint8_t accident_planet_i; bool have_assassin; player_id_t assassin_player; player_id_t assassin_player2; bool have_virus; player_id_t virus_player; tech_field_t virus_field; uint8_t have_comet; /* 0..3 */ player_id_t comet_player; uint8_t comet_planet_i; uint8_t comet_years; uint16_t comet_hp; uint16_t comet_dmg; uint8_t have_pirates; /* 0..3 */ uint8_t pirates_planet_i; uint16_t pirates_hp; bool have_derelict; player_id_t derelict_player; monster_t crystal; monster_t amoeba; bool have_enviro; uint8_t enviro_planet_i; bool have_rich; uint8_t rich_planet_i; bool have_support; player_id_t support_player; bool have_poor; uint8_t poor_planet_i; uint8_t have_orion_conquer; /* 0, pi+1 */ uint8_t planet_orion_i; bool have_guardian; uint8_t home[PLAYER_NUM]; /* home planet index or PLANET_NONE if dead */ uint8_t report_stars; BOOLVEC_DECLARE(coup, PLAYER_NUM); newtechs_t newtech[PLAYER_NUM]; shipsum_t new_ships[PLAYER_NUM][NUM_SHIPDESIGNS]; uint16_t spies_caught[PLAYER_NUM][PLAYER_NUM]; /* [catcher][spy] */ uint16_t spied_num[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ int16_t spied_spy[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ tech_field_t stolen_field[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ uint8_t stolen_tech[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ player_id_t stolen_spy[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ bool sabotage_is_bases[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ uint8_t sabotage_planet[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ uint16_t sabotage_num[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ player_id_t sabotage_spy[PLAYER_NUM][PLAYER_NUM]; /* [victim][spy] */ uint8_t ceasefire[PLAYER_NUM][PLAYER_NUM]; /* [human][ai] */ BOOLVEC_TBL_DECLARE(help_shown, PLAYER_NUM, HELP_SHOWN_NUM); uint16_t build_finished_num[PLAYER_NUM]; player_id_t voted[PLAYER_NUM]; uint8_t best_ecorestore[PLAYER_NUM]; uint8_t best_wastereduce[PLAYER_NUM]; uint8_t best_roboctrl[PLAYER_NUM]; uint8_t best_terraform[PLAYER_NUM]; } gameevents_t; typedef struct seen_s { player_id_t owner; uint16_t pop; uint16_t bases; uint16_t factories; } seen_t; #define EMPEROR_NAME_LEN 15 #define NEBULA_MAX 4 #define YEAR_BASE 2299 struct game_aux_s; struct game_s { uint16_t enroute_num; uint16_t transport_num; uint16_t year; /* init to 1 */ uint8_t players; uint8_t ai_id; BOOLVEC_DECLARE(is_ai, PLAYER_NUM); player_id_t active_player; difficulty_t difficulty; galaxy_size_t galaxy_size; uint8_t galaxy_w; /* 6 8 a c */ uint8_t galaxy_h; /* 4 6 7 9 */ uint8_t galaxy_stars; /* w*h */ uint16_t galaxy_maxx; uint16_t galaxy_maxy; uint32_t seed; /* current random seed */ uint32_t galaxy_seed; /* seed of generated galaxy */ game_end_type_t end; player_id_t winner; player_id_t guardian_killer; bool election_held; BOOLVEC_DECLARE(refuse, PLAYER_NUM); uint8_t planet_focus_i[PLAYER_NUM]; uint8_t nebula_num; /* 0..4 */ uint8_t nebula_type[NEBULA_MAX]; /* 0..9 */ uint16_t nebula_x[NEBULA_MAX]; uint16_t nebula_y[NEBULA_MAX]; uint16_t nebula_x0[NEBULA_MAX][4]; uint16_t nebula_x1[NEBULA_MAX][4]; uint16_t nebula_y0[NEBULA_MAX][4]; uint16_t nebula_y1[NEBULA_MAX][4]; planet_t planet[PLANETS_MAX]; fleet_enroute_t enroute[FLEET_ENROUTE_MAX]; transport_t transport[TRANSPORT_MAX]; empiretechorbit_t eto[PLAYER_NUM]; shipresearch_t srd[PLAYER_NUM]; gameevents_t evn; char emperor_names[PLAYER_NUM][EMPEROR_NAME_LEN]; seen_t seen[PLAYER_NUM][PLANETS_MAX]; shipdesign_t current_design[PLAYER_NUM]; struct game_aux_s *gaux; }; static inline bool IS_PLAYER(const struct game_s *g, player_id_t i) { return (i >= 0) && (i < g->players); } static inline bool IS_HUMAN(const struct game_s *g, player_id_t i) { /* In MOO1, instead of IS_HUMAN, the index is checked for equality to zero, which in turn implicitly guarantees that the index is less than g->players. The IS_PLAYER check eliminates the potential for memory corruption. */ return IS_PLAYER(g, i) && BOOLVEC_IS0(g->is_ai, i); } static inline bool IS_ALIVE(const struct game_s *g, player_id_t i) { return (g->evn.home[i] != PLANET_NONE); } #define IS_AI(_g_, _i_) BOOLVEC_IS1((_g_)->is_ai, (_i_)) extern bool game_opt_skip_intro_always; extern bool game_opt_message_filter[FINISHED_NUM]; extern struct game_new_options_s game_opt_custom; #endif 1oom-1.11.2/src/game/game_ai.c000066400000000000000000000005411476061725400157110ustar00rootroot00000000000000#include "config.h" #include "game_ai.h" #include "game_ai_classic.h" #include "game.h" #include "game_aux.h" /* -------------------------------------------------------------------------- */ const struct game_ai_s *game_ai = &game_ai_classic; const struct game_ai_s *const game_ais[GAME_AI_NUM] = { &game_ai_classic, &game_ai_classicplus }; 1oom-1.11.2/src/game/game_ai.h000066400000000000000000000047031476061725400157220ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_AI_H #define INC_1OOM_GAME_AI_H #include "game_types.h" #include "types.h" struct game_s; struct battle_s; struct election_s; struct audience_s; typedef enum { GAME_AI_CLASSIC = 0, GAME_AI_CLASSICPLUS, /*1*/ GAME_AI_NUM } game_ai_id_t; struct game_ai_s { game_ai_id_t id; char const * const name; void (*new_game_init)(struct game_s *g, player_id_t player, uint8_t home); void (*new_game_tech)(struct game_s *g); void (*turn_p1)(struct game_s *g); void (*turn_p2)(struct game_s *g); void (*turn_p3)(struct game_s *g); bool (*battle_ai_ai_resolve)(struct battle_s *bt); /* true if right side won */ void (*battle_ai_turn)(struct battle_s *bt); bool (*battle_ai_retreat)(struct battle_s *bt); /* true if retreat all */ uint8_t (*tech_next)(struct game_s *g, player_id_t player, tech_field_t field, uint8_t *tbl, int num); bool (*bomb)(struct game_s *g, player_id_t player, uint8_t planet, int pop_inbound); void (*ground)(struct game_s *g, player_id_t def, player_id_t att, uint8_t planet, int pop_killed, bool owner_changed); void (*plague)(struct game_s *g, uint8_t planet); void (*nova)(struct game_s *g, uint8_t planet); void (*comet)(struct game_s *g, uint8_t planet); void (*pirates)(struct game_s *g, uint8_t planet); int (*vote)(struct election_s *el, player_id_t player); /* 0 = abstain, N = candidate N */ void (*turn_diplo_p1)(struct game_s *g); void (*turn_diplo_p2)(struct game_s *g); void (*aud_start_human)(struct audience_s *au); int (*aud_treaty_nap)(struct audience_s *au); int (*aud_treaty_alliance)(struct audience_s *au); int (*aud_treaty_peace)(struct audience_s *au); int (*aud_treaty_declare_war)(struct audience_s *au); int (*aud_treaty_break_alliance)(struct audience_s *au); int (*aud_trade)(struct audience_s *au); bool (*aud_sweeten)(struct audience_s *au, int *bcptr, tech_field_t *fieldptr, uint8_t *techptr); uint8_t (*aud_threaten)(struct audience_s *au); void (*aud_tribute_bc)(struct audience_s *au, int selected, int bc); void (*aud_tribute_tech)(struct audience_s *au, int selected, tech_field_t field, uint8_t tech); int (*aud_tech_scale)(struct audience_s *au); uint8_t (*aud_get_dtype)(struct audience_s *au, uint8_t dtype, int a2); bool (*aud_later)(struct audience_s *au); }; extern const struct game_ai_s *game_ai; extern const struct game_ai_s *const game_ais[GAME_AI_NUM]; #endif 1oom-1.11.2/src/game/game_ai_classic.c000066400000000000000000004774661476061725400174420ustar00rootroot00000000000000/* The "Classic" AI mimics MOO1 v1.3 behaviour. Minor bug fixes are allowed. The "Classic+" AI fixes small bugs and does small improvements. Major improvements go to other game_ai_* implementations. */ #include "config.h" #include /* abs */ #include #include "game_ai_classic.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_audience.h" #include "game_aux.h" #include "game_battle.h" #include "game_battle_human.h" #include "game_design.h" #include "game_diplo.h" #include "game_election.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_shiptech.h" #include "game_spy.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ static void game_ai_classic_new_game_init(struct game_s *g, player_id_t player, uint8_t home) { int n = 0; planet_t *p = &g->planet[home]; empiretechorbit_t *e = &g->eto[player]; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *q; q = &g->planet[i]; if (1 && (q->type > (PLANET_TYPE_MINIMAL - 1)) && (util_math_dist_fast(q->x, q->y, p->x, p->y) <= 30) ) { ++n; } } e->ai_p3_countdown = rnd_1_n(6, &g->seed) + 14; e->ai_p2_countdown = rnd_1_n(10, &g->seed); if (n > 1) { p->slider[PLANET_SLIDER_SHIP] = 10; p->slider[PLANET_SLIDER_DEF] = 0; p->slider[PLANET_SLIDER_IND] = 90; p->slider[PLANET_SLIDER_ECO] = 0; p->slider[PLANET_SLIDER_TECH] = 0; e->tech.slider[TECH_FIELD_COMPUTER] = 20; e->tech.slider[TECH_FIELD_CONSTRUCTION] = 20; e->tech.slider[TECH_FIELD_FORCE_FIELD] = 0; e->tech.slider[TECH_FIELD_PLANETOLOGY] = 40; e->tech.slider[TECH_FIELD_PROPULSION] = 20; e->tech.slider[TECH_FIELD_WEAPON] = 0; } else { e->ai_p3_countdown = rnd_1_n(6, &g->seed) + 24; p->slider[PLANET_SLIDER_SHIP] = 0; p->slider[PLANET_SLIDER_DEF] = 0; p->slider[PLANET_SLIDER_IND] = 60; p->slider[PLANET_SLIDER_ECO] = 10; p->slider[PLANET_SLIDER_TECH] = 40; e->tech.slider[TECH_FIELD_COMPUTER] = 0; e->tech.slider[TECH_FIELD_CONSTRUCTION] = 0; e->tech.slider[TECH_FIELD_FORCE_FIELD] = 0; e->tech.slider[TECH_FIELD_PLANETOLOGY] = 0; e->tech.slider[TECH_FIELD_PROPULSION] = 100; e->tech.slider[TECH_FIELD_WEAPON] = 0; } /* XXX these shipi values are wrong, but fixed by first next turn */ e->shipi_colony = 1; e->shipi_bomber = 4; } static void game_ai_classic_new_game_tech(struct game_s *g) { for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { if (IS_HUMAN(g, pli)) { continue; } for (tech_field_t field = TECH_FIELD_COMPUTER; field < TECH_FIELD_NUM; ++field) { uint8_t tech; uint8_t *rl; rl = g->srd[pli].researchlist[field][0]; do { tech = rl[rnd_0_nm1(3, &g->seed)]; } while (tech == 0); if (game_num_ai_first_tech_cost_fix) { game_tech_start_next(g, pli, field, tech); } else { empiretechorbit_t *e; e = &g->eto[pli]; e->tech.project[field] = tech; e->tech.cost[field] = tech * tech * 50; } } } } /* -------------------------------------------------------------------------- */ struct ai_turn_p1_s { bool have_colonizable; bool need_conquer; uint32_t tbl_shipthreat[PLAYER_NUM + 1][NUM_SHIPDESIGNS]; uint16_t tbl_xcenter[PLAYER_NUM]; uint16_t tbl_ycenter[PLAYER_NUM]; uint64_t tbl_force_own[PLANETS_MAX]; int num_fronts; int tbl_front_relation[PLAYER_NUM]; uint8_t tbl_front_planet[PLAYER_NUM]; uint64_t force_own_sum; int planet_en_num; int planet_own_num; int tbl_planet_own_w[PLANETS_MAX]; int tbl_planet_en_w[PLANETS_MAX]; uint8_t tbl_planet_own_i[PLANETS_MAX]; uint8_t tbl_planet_en_i[PLANETS_MAX]; }; struct ai_turn_p2_s { struct game_design_s gd; int shiptype; ship_hull_t hull; uint8_t shiplook; bool have_pulsar; bool have_repulwarp; }; /* -------------------------------------------------------------------------- */ static int game_ai_best_speed(const struct game_s *g, player_id_t player_i) { /* FIXME: The name of the function does not correctly reflect its meaning. Misunderstanding of the meaning of this function was the cause of errors. */ return game_tech_player_best_tech(g, TECH_FIELD_PROPULSION, 0, 6, 50, player_i) + 3; } static void game_ai_classic_turn_p1_send_scout(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); BOOLVEC_DECLARE(tbl_planet_ignore, PLANETS_MAX); uint8_t tbl_planet_scout[PLANETS_MAX]; shipsum_t tbl_ownorbit[PLANETS_MAX]; int num_to_scout = 0; BOOLVEC_CLEAR(tbl_planet_ignore, PLANETS_MAX); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); shipsum_t ships; ships = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if ((pi != pi2) && (e->treaty[pi2] != TREATY_ALLIANCE)) { const shipcount_t *t = &(g->eto[pi2].orbit[i].ships[0]); int sd_num = g->eto[pi2].shipdesigns_num; for (int j = 0; j < sd_num; ++j) { ships += t[j]; } } } if (0 || BOOLVEC_IS1(p->explored, pi) || (!p->within_frange[pi]) || ((g->year < 150) && (g->evn.planet_orion_i == i)) /* XXX Orion is unconditionally ignored below */ || (ships > 0) ) { BOOLVEC_SET1(tbl_planet_ignore, i); } } for (int j = 0; j < g->enroute_num; ++j) { const fleet_enroute_t *r = &(g->enroute[j]); if (r->owner == pi) { BOOLVEC_SET1(tbl_planet_ignore, r->dest); } } ait->have_colonizable = false; ait->need_conquer = !rnd_0_nm1(8 - g->difficulty, &g->seed); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == PLAYER_NONE) { if (BOOLVEC_IS0(tbl_planet_ignore, i) && (g->evn.planet_orion_i != i)) { tbl_planet_scout[num_to_scout++] = i; } if ((p->type >= e->have_colony_for) && ((g->evn.planet_orion_i != i) || (!g->evn.have_guardian))) { ait->have_colonizable = true; ait->need_conquer = false; } } } if (g->end != GAME_END_NONE) { ait->need_conquer = false; } for (int i = 0; i < g->galaxy_stars; ++i) { const shipcount_t *t = &(e->orbit[i].ships[0]); shipsum_t ships; /* MOO1 uses uint16_t */ ships = 0; for (int j = 0; j < e->shipdesigns_num; ++j) { ships += t[j]; } tbl_ownorbit[i] = ships; } for (int i = 0; i < num_to_scout; ++i) { uint8_t mini, pli; int mindist; const planet_t *p; mindist = 10000; mini = PLANET_NONE; pli = tbl_planet_scout[i]; p = &(g->planet[pli]); for (int j = 0; j < g->galaxy_stars; ++j) { if (tbl_ownorbit[j] > 0) { const planet_t *p2 = &(g->planet[j]); int dist; dist = util_math_dist_fast(p->x, p->y, p2->x, p2->y); if (dist < mindist) { mindist = dist; mini = j; } } } if (mini != PLANET_NONE) { if (g->enroute_num >= FLEET_ENROUTE_AI_MAX) { log_warning("fleet enroute table (size %i/%i) too large for AI fleet (%i)!\n", g->enroute_num, FLEET_ENROUTE_MAX, FLEET_ENROUTE_AI_MAX); } else { shipcount_t *t = &(e->orbit[mini].ships[0]); const bool *hrf = &(g->srd[pi].have_reserve_fuel[0]); int shipi; shipi = -1; for (int j = 0; j < e->shipdesigns_num; ++j) { if ((t[j] != 0) && ((shipi == -1) || (!hrf[shipi]))) { shipi = j; } } if (!((p->within_frange[pi] == 1) || ((p->within_frange[pi] == 2) && hrf[shipi]))) { shipi = -1; } if (shipi != -1) { fleet_enroute_t *r; const planet_t *p2 = &(g->planet[mini]); shipcount_t num_send; r = &(g->enroute[g->enroute_num++]); num_send = t[shipi] / 4 + 1; r->dest = pli; r->owner = pi; r->x = p2->x; r->y = p2->y; r->speed = g->srd[pi].design[shipi].engine + 1; r->retreat = false; for (int k = 0; k < NUM_SHIPDESIGNS; ++k) { r->ships[k] = 0; } r->ships[shipi] = num_send; BOOLVEC_CLEAR(r->visible, PLAYER_NUM); BOOLVEC_SET1(r->visible, pi); t[shipi] -= num_send; tbl_ownorbit[mini] -= num_send; } } } } } static uint8_t game_ai_classic_turn_p1_front_find_planet(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi, int x, int y) { empiretechorbit_t *e = &(g->eto[pi]); uint8_t mini = 0; int mindist = 10000; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { int dist; dist = util_math_dist_fast(p->x, p->y, x, y); if (dist < mindist) { mindist = dist; mini = i; } } } mindist = 10000; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { shipsum_t defense; defense = p->missile_bases ? 1 : 0; for (int j = 0; (j < e->shipdesigns_num) && (defense == 0); ++j) { defense += e->orbit[i].ships[j]; } if (defense == 1) { int dist; dist = util_math_dist_fast(p->x, p->y, x, y); if (dist < mindist) { mindist = dist; mini = i; } } } } return mini; } static void game_ai_classic_turn_p1_front(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); int bestspeed; int tbl_x[PLAYER_NUM], tbl_y[PLAYER_NUM]; bestspeed = game_ai_best_speed(g, pi) * 10 + 10; ait->num_fronts = 0; /* unused BOOLVEC_DECLARE(tbl_own_transport_dest, PLANETS_MAX); BOOLVEC_CLEAR(tbl_own_transport_dest, PLANETS_MAX); for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[j]); if (r->owner == pi) { BOOLVEC_SET1(tbl_own_transport_dest, r->dest); } } */ for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (1 && (pi != pi2) && BOOLVEC_IS1(e->contact, pi2) && ((g->end == GAME_END_NONE) || BOOLVEC_IS1(g->refuse, pi2)) ) { int v8, vc; ait->tbl_front_relation[ait->num_fronts] = 0; tbl_x[ait->num_fronts] = (ait->tbl_xcenter[pi2] * 4 + ait->tbl_xcenter[pi] * 6) / 10; tbl_y[ait->num_fronts] = (ait->tbl_ycenter[pi2] * 4 + ait->tbl_ycenter[pi] * 6) / 10; vc = 0; for (int i = 0; i < ait->num_fronts; ++i) { if (util_math_dist_fast(tbl_x[i], tbl_y[i], tbl_x[ait->num_fronts], tbl_y[ait->num_fronts]) <= bestspeed) { vc = i + 1; } } v8 = e->relation1[pi2]; SETMIN(v8, 0); if (vc == 0) { ait->tbl_front_relation[ait->num_fronts++] = v8; /* unused before overwritten below } else { ait->tbl_force_own[vc] += v8; */ } } } if (ait->num_fronts == 0) { tbl_x[ait->num_fronts] = ait->tbl_xcenter[pi]; tbl_y[ait->num_fronts] = ait->tbl_ycenter[pi]; /* WASBUG: tbs_front_relation could be used uninitialized when there was no real front. In case of no real fronts, initialize the dummy front with a peaceful relation */ ait->tbl_front_relation[ait->num_fronts++] = 80; } for (int i = 0; i < ait->num_fronts; ++i) { ait->tbl_front_planet[i] = game_ai_classic_turn_p1_front_find_planet(g, ait, pi, tbl_x[i], tbl_y[i]); } for (int k = 0; k < (PLAYER_NUM - 1); ++k) { for (int i = 0; i < ait->num_fronts;) { int m; m = -1; for (int j = i + 1; j < ait->num_fronts; ++j) { if (ait->tbl_front_planet[i] == ait->tbl_front_planet[j]) { m = j; } } if (m != -1) { ait->tbl_front_relation[i] += ait->tbl_front_relation[m]; for (int j = m; j < (ait->num_fronts - 1); ++j) { ait->tbl_front_relation[j] = ait->tbl_front_relation[j + 1]; ait->tbl_front_planet[j] = ait->tbl_front_planet[j + 1]; } --ait->num_fronts; } else { ++i; } } } /*7ff9d*/ /* unused foreach shipdesign { tbl_shipweight[i] = game_num_tbl_hull_w[sd[i].hull]; } */ { uint64_t sum = 0; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); ait->tbl_force_own[i] = 0; if ((p->owner == pi) || (p->owner == PLAYER_NONE)) { for (int j = 0; j < e->shipdesigns_num; ++j) { shipcount_t n; n = e->orbit[i].ships[j]; if (n) { uint64_t v; v = ait->tbl_shipthreat[pi][j] * n; sum += v; if (g->ai_id == GAME_AI_CLASSIC) { v &= 0xffffffff; /* WASBUG MOO1 uses 32 bit var */ } ait->tbl_force_own[i] += v; } } } } if (g->ai_id == GAME_AI_CLASSIC) { sum &= 0xffffffff; /* WASBUG MOO1 uses 32 bit var */ } if (sum != 0) { for (int i = 0; i < ait->num_fronts; ++i) { ait->tbl_front_relation[i] += (ait->tbl_force_own[ait->tbl_front_planet[i]] * 100) / sum; } } ait->force_own_sum = sum / 25; } } static bool game_ai_classic_turn_p1_have_colony_ship(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); shipresearch_t *srd = &(g->srd[pi]); int shipi = e->shipi_colony; uint32_t prod; uint8_t planeti; shipcount_t shipn; if (0 || (ait->num_fronts == 0) /* never true? */ || (shipi == -1) || (e->total_production_bc == 0) ) { return false; } shipn = srd->shipcount[shipi]; if (!game_num_ai_4_colony_curse_fix && (shipn > 3)) { return false; } planeti = ait->tbl_front_planet[rnd_0_nm1(ait->num_fronts, &g->seed)]; if (planeti == PLANET_NONE) { /* never true? */ return false; } if (shipn > 3) { return true; } prod = (e->total_production_bc * 2) / 5; SETRANGE(prod, 1, 500); if (g->difficulty < DIFFICULTY_AVERAGE) { if (rnd_0_nm1(6, &g->seed) > g->difficulty) { prod = 0; } } if ((!ait->have_colonizable) || (rnd_1_n(500, &g->seed) > prod)) { return (shipn > 0); } /* spawn a new colony ship by magic */ srd->shipcount[shipi] = ++shipn; ++e->orbit[planeti].ships[shipi]; return true; } static void game_turn_fleet_send(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi, uint8_t from, uint8_t dest) { empiretechorbit_t *e = &(g->eto[pi]); fleet_enroute_t *r; const planet_t *pf, *pt; fleet_orbit_t *o; uint8_t speed, num_shiptypes; if (from == dest) { return; } ait->tbl_force_own[from] = 0; if (g->enroute_num == FLEET_ENROUTE_MAX) { log_warning("fleet enroute table (size %i) full, could not leave orbit!\n", FLEET_ENROUTE_MAX); return; } pf = &(g->planet[from]); pt = &(g->planet[dest]); r = &(g->enroute[g->enroute_num]); o = &(e->orbit[from]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { r->ships[i] = 0; } speed = 50; num_shiptypes = 0; for (int i = 0; i < e->shipdesigns_num; ++i) { int n; n = o->ships[i]; if ((pt->within_frange[pi] == 0) || ((pt->within_frange[pi] == 2) && !g->srd[pi].have_reserve_fuel[i])) { n = 0; } if (n > 0) { uint8_t s; r->ships[i] = n; if (g->ai_id == GAME_AI_CLASSICPLUS) { o->ships[i] = 0; } ++num_shiptypes; s = g->srd[pi].design[i].engine; SETMIN(speed, s); } } if ((pt->owner == pf->owner) && pt->have_stargate && pf->have_stargate) { speed = 100; } if (num_shiptypes > 0) { r->speed = speed + 1; BOOLVEC_CLEAR(r->visible, PLAYER_NUM); BOOLVEC_SET1(r->visible, pi); r->dest = dest; r->owner = pi; r->x = pf->x; r->y = pf->y; ++g->enroute_num; } { bool all_sent = true; if (g->ai_id == GAME_AI_CLASSICPLUS) { for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (o->ships[i]) { all_sent = false; break; } } } else { for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { o->ships[i] = 0; /* BUG ships removed even if they were not sent due to range == 2 && !reserve_fuel */ } } if (all_sent) { BOOLVEC_CLEAR(o->visible, NUM_SHIPDESIGNS); } } } static void game_ai_classic_turn_p1_send_colony_ships(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); planet_type_t can_colonize = PLANET_TYPE_MINIMAL; int range = e->fuel_range * 15, si = e->shipi_colony, num_planet_colonize = 0; uint8_t tbl_planet_colonize[PLANETS_MAX]; shipcount_t tbl_orbit[PLANETS_MAX]; BOOLVEC_DECLARE(tbl_planet_ignore, PLANETS_MAX); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); BOOLVEC_SET(tbl_planet_ignore, i, (p->owner != PLAYER_NONE) || (p->within_frange[pi] == 0)); } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if ((r->owner == pi) && (r->ships[si] > 0)) { BOOLVEC_SET1(tbl_planet_ignore, r->dest); } } { const shipdesign_t *sd = &(g->srd[pi].design[si]); for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t s; s = sd->special[i]; if ((s >= SHIP_SPECIAL_STANDARD_COLONY_BASE) && (s <= SHIP_SPECIAL_RADIATED_COLONY_BASE)) { can_colonize = PLANET_TYPE_MINIMAL - (s - SHIP_SPECIAL_STANDARD_COLONY_BASE); } } } if (e->race == RACE_SILICOID) { can_colonize = PLANET_TYPE_RADIATED; } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (1 && (p->owner == PLAYER_NONE) && BOOLVEC_IS0(tbl_planet_ignore, i) && ((g->evn.planet_orion_i != i) || (!g->evn.have_guardian)) && (p->type >= can_colonize) ) { tbl_planet_colonize[num_planet_colonize++] = i; } } for (int i = 0; i < g->galaxy_stars; ++i) { tbl_orbit[i] = e->orbit[i].ships[si]; } for (int i = 0; i < num_planet_colonize; ++i) { const planet_t *p; uint8_t pli, mini; int mindist; pli = tbl_planet_colonize[i]; p = &(g->planet[pli]); mini = PLANET_NONE; if ((p->within_frange[pi] == 1) || ((p->within_frange[pi] == 2) && g->srd[pi].have_reserve_fuel[si])) { mindist = 10000; for (int j = 0; j < g->galaxy_stars; ++j) { if (tbl_orbit[j] > 0) { const planet_t *p2 = &(g->planet[j]); int dist; dist = util_math_dist_fast(p->x, p->y, p2->x, p2->y); if (dist < mindist) { mindist = dist; mini = j; } } } } if (mini != PLANET_NONE) { const planet_t *p2; p2 = &(g->planet[mini]); if ((g->ai_id == GAME_AI_CLASSICPLUS) || (util_math_dist_fast(p->x, p->y, p2->x, p2->y) <= range)) { if (g->enroute_num >= FLEET_ENROUTE_AI_MAX) { log_warning("fleet enroute table (size %i/%i) too large for AI fleet (%i)!\n", g->enroute_num, FLEET_ENROUTE_MAX, FLEET_ENROUTE_AI_MAX); } else { game_turn_fleet_send(g, ait, pi, mini, pli); if (g->ai_id == GAME_AI_CLASSICPLUS) { /* WASBUG MOO1 does not update the local copy and may try to send multiple colony ship fleets from the same planet */ tbl_orbit[mini] = e->orbit[mini].ships[si]; } } } } } } static void game_ai_classic_turn_p1_planet_w(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { ait->planet_en_num = 0; ait->planet_own_num = 0; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); player_id_t owner; int v4; v4 = (p->special - 2) * 20 + p->special * 10 + 20; owner = p->owner; if (owner == PLAYER_NONE) { for (player_id_t pi2 = PLAYER_0; (pi2 < PLAYER_NUM) && (owner == PLAYER_NONE); ++pi2) { const empiretechorbit_t *e2 = &(g->eto[pi2]); if (pi2 != pi) { for (int j = 0; (j < e2->shipdesigns_num) && (owner == PLAYER_NONE); ++j) { if (e2->orbit[i].ships[j]) { owner = pi2; } } } } } if (owner == pi) { ait->tbl_planet_own_i[ait->planet_own_num] = i; ait->tbl_planet_own_w[ait->planet_own_num] = p->pop - (p->missile_bases * 5) + v4; ++ait->planet_own_num; } else if (owner != PLAYER_NONE) { empiretechorbit_t *e = &(g->eto[pi]); if (1 && ((e->treaty[owner] >= TREATY_WAR) || ait->need_conquer || (g->end != GAME_END_NONE)) && (p->within_frange[pi] == 1) && (p->type >= e->have_colony_for) && ((g->year > 120) || (g->evn.planet_orion_i != i)) ) { ait->tbl_planet_en_i[ait->planet_en_num] = i; ait->tbl_planet_en_w[ait->planet_en_num] = p->pop - (p->missile_bases * 10) + v4; ++ait->planet_en_num; } } } { bool work_left = true; for (int i = 0; (i < ait->planet_en_num) && work_left; ++i) { for (int j = 0; j < (ait->planet_en_num - 1); ++j) { work_left = false; if (ait->tbl_planet_en_w[j] < ait->tbl_planet_en_w[j + 1]) { { int t; t = ait->tbl_planet_en_w[j]; ait->tbl_planet_en_w[j] = ait->tbl_planet_en_w[j + 1]; ait->tbl_planet_en_w[j + 1] = t; } { uint8_t t; t = ait->tbl_planet_en_i[j]; ait->tbl_planet_en_i[j] = ait->tbl_planet_en_i[j + 1]; ait->tbl_planet_en_i[j + 1] = t; } work_left = true; } } } } } static void game_ai_classic_turn_p1_send_attack(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); int range = e->fuel_range * 15; for (int i = 0; i < ait->num_fronts; ++i) { uint8_t pfrom, pto, pto2; pto2 = PLANET_NONE; pfrom = ait->tbl_front_planet[i]; for (int j = 0; (j < ait->planet_en_num) && (pto2 == PLANET_NONE); ++j) { const planet_t *pt; pto = ait->tbl_planet_en_i[j]; pt = &(g->planet[pto]); if (1 && (ait->tbl_planet_en_w[j] != -1000) && (util_math_dist_fast(pt->x, pt->y, g->planet[pfrom].x, g->planet[pfrom].y) < range) && ((rnd_1_n(100, &g->seed) < 40) || (ait->planet_en_num < 2)) ) { empiretechorbit_t *e2; uint64_t weight; weight = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (pi2 != pi) { e2 = &(g->eto[pi2]); for (int l = 0; l < e2->shipdesigns_num; ++l) { /* WASBUG MOO1 uses e->shipdesigns_num */ shipcount_t n; if ((n = e2->orbit[pto].ships[l]) != 0) { weight += n * ait->tbl_shipthreat[pi2][l]; } } } } if (pt->owner != PLAYER_NONE) { e2 = &(g->eto[pt->owner]); weight += ((e2->tech.percent[TECH_FIELD_WEAPON] * 5) + (e2->have_planet_shield + 10) * 10) * pt->missile_bases; } if (g->ai_id == GAME_AI_CLASSIC) { weight &= 0xffffffff; /* WASBUG MOO1 uses 32 bit var */ } if (ait->tbl_force_own[pfrom] > weight) { pto2 = pto; if (pt->owner == PLAYER_NONE) { game_turn_fleet_send(g, ait, pi, pfrom, pto2); } else if (e2->treaty[pi] == TREATY_ALLIANCE) { if ((rnd_1_n(4, &g->seed) == 1) || ((rnd_1_n(2, &g->seed) == 1) && (e->trait2 == TRAIT2_EXPANSIONIST))) { game_diplo_act(g, -10000, pt->owner, pi, 32, pto2, pto2); /* BUG? 2 * pto2?? */ game_diplo_break_treaty(g, pi, pt->owner); if (e->relation1[pt->owner] > 30) { e->relation1[pt->owner] = 30; e2->relation1[pi] = 30; } } } else if (e2->treaty[pi] == TREATY_NONAGGRESSION) { if ((rnd_1_n(2, &g->seed) == 1) || (e->trait2 == TRAIT2_EXPANSIONIST)) { game_diplo_act(g, -10000, pt->owner, pi, 32, pto2, pto2); /* BUG? 2 * pto2?? */ game_diplo_break_treaty(g, pi, pt->owner); if (e->relation1[pt->owner] > 30) { /* BUG? should be 20? */ e->relation1[pt->owner] = 20; e2->relation1[pi] = 20; } } } else { game_turn_fleet_send(g, ait, pi, pfrom, pto2); } ait->tbl_planet_en_w[j] = -1000; } } } } for (uint8_t pfrom = 0; pfrom < g->galaxy_stars; ++pfrom) { const planet_t *p = &(g->planet[pfrom]); if ((p->owner != PLAYER_NONE) && (p->owner != pi) && (ait->tbl_force_own[pfrom] != 0)) { for (int j = 0; j < ait->planet_en_num; ++j) { if (ait->tbl_planet_en_w[j] > -1000) { const planet_t *pt; uint8_t pto; pto = ait->tbl_planet_en_i[j]; pt = &(g->planet[pto]); if (1 && (util_math_dist_fast(pt->x, pt->y, g->planet[pfrom].x, g->planet[pfrom].y) < range) && (rnd_1_n(100, &g->seed) < 60) ) { uint32_t weight; weight = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (pi2 != pi) { const empiretechorbit_t *e2; const shipdesign_t *sd; e2 = &(g->eto[pi2]); sd = &(g->srd[pi2].design[0]); for (int k = 0; k < e2->shipdesigns_num; ++k) { weight += e2->orbit[pto].ships[k] * game_num_tbl_hull_w[sd[k].hull]; /* FIXME? why not tbl_shipthreat? */ } } } if (((ait->tbl_force_own[pfrom] * 3) / 2) > weight) { game_turn_fleet_send(g, ait, pi, pfrom, pto); ait->tbl_planet_en_w[j] = -1000; break; } } } } } } } static void game_ai_classic_turn_p1_send_defend(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { int bestspeed = game_ai_best_speed(g, pi) * 30 + 20; uint8_t tbl_shipw[PLAYER_NUM][NUM_SHIPDESIGNS]; uint64_t tbl_planet_threat[PLANETS_MAX]; uint8_t tbl_defend[PLANETS_MAX]; int num_defend = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { const empiretechorbit_t *e2 = &(g->eto[pi2]); const shipdesign_t *sd = &(g->srd[pi2].design[0]); for (int i = 0; i < e2->shipdesigns_num; ++i) { tbl_shipw[pi2][i] = game_num_tbl_hull_w[sd[i].hull]; } } for (int i = 0; i < g->galaxy_stars; ++i) { tbl_planet_threat[i] = 0; } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if ((r->owner != pi) && (g->planet[r->dest].owner == pi)) { const empiretechorbit_t *e2 = &(g->eto[r->owner]); for (int j = 0; j < e2->shipdesigns_num; ++j) { shipcount_t n; n = r->ships[j]; if (n != 0) { tbl_planet_threat[r->dest] += n * tbl_shipw[r->owner][j]; } } } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if ((r->owner != pi) && (g->planet[r->dest].owner == pi)) { tbl_planet_threat[r->dest] += r->pop * game_num_tbl_hull_w[SHIP_HULL_MEDIUM]; } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if ((p->missile_bases < 5) && (ait->tbl_force_own[i] == 0)) { tbl_planet_threat[i] = 50; } } if (g->ai_id == GAME_AI_CLASSIC) { for (int i = 0; i < g->galaxy_stars; ++i) { tbl_planet_threat[i] &= 0xffffffff; /* WASBUG MOO1 uses 32 bit var */ } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if ((p->owner == pi) && (((ait->tbl_force_own[i] * 4) / 3) < tbl_planet_threat[i])) { tbl_defend[num_defend++] = i; } } for (int i = 0; i < g->galaxy_stars; ++i) { if ((ait->tbl_force_own[i] > 0) && (tbl_planet_threat[i] == 0)) { const planet_t *pf; uint8_t pto; pto = PLANET_NONE; pf = &(g->planet[i]); for (int j = 0; (j < num_defend) && (pto == PLANET_NONE); ++j) { const planet_t *pt; uint8_t pli = tbl_defend[j]; pt = &(g->planet[pli]); if (util_math_dist_fast(pf->x, pf->y, pt->x, pt->y) <= bestspeed) { pto = pli; } } if ((pto != PLANET_NONE) && ((tbl_planet_threat[pto] * 5) / 3) < ait->tbl_force_own[i]) { game_turn_fleet_send(g, ait, pi, i, pto); tbl_planet_threat[pto] = 100000000; } } } } static void game_ai_classic_turn_p1_send_idle(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { int bestspeed = game_ai_best_speed(g, pi) * 20 + 20; for (int i = 0; i < ait->num_fronts; ++i) { ait->tbl_force_own[ait->tbl_front_planet[i]] = 0; } for (int i = 0; i < ait->planet_own_num; ++i) { if ((ait->tbl_force_own[ait->tbl_planet_own_i[i]] - ait->tbl_planet_own_w[i]) < 0) { ait->tbl_force_own[i] = 0; } } if (g->election_held) { ait->force_own_sum /= 2; } if (g->end != GAME_END_NONE) { ait->force_own_sum /= 2; } for (int i = 0; i < g->galaxy_stars; ++i) { if (ait->tbl_force_own[i] < ait->force_own_sum) { ait->tbl_force_own[i] = 0; } } for (int i = 0; i < g->galaxy_stars; ++i) { if (ait->tbl_force_own[i] > 0) { uint8_t pto; const planet_t *pf; int minv; pf = &(g->planet[i]); pto = PLANET_NONE; minv = 10000; for (int j = 0; j < ait->num_fronts; ++j) { const planet_t *pt; int v; uint8_t pli; pli = ait->tbl_front_planet[j]; pt = &(g->planet[pli]); v = (util_math_dist_fast(pt->x, pt->y, pf->x, pf->y) * 10) / bestspeed + ait->tbl_front_relation[j]; if (v < minv) { minv = v; pto = pli; } } if (pto != PLANET_NONE) { game_turn_fleet_send(g, ait, pi, i, pto); } } } } static void game_ai_classic_turn_p1_trans_en(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { int bestspeed = game_ai_best_speed(g, pi) * 30 + 30; empiretechorbit_t *e = &(g->eto[pi]); BOOLVEC_DECLARE(tbl_trans_from, PLANETS_MAX); /* NOTE overwrites ait->tbl_planet_own_i */ BOOLVEC_DECLARE(tbl_trans_to, PLANETS_MAX); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); bool have_orbit; have_orbit = false; if (1 && (p->owner != PLAYER_NONE) && (p->owner != pi) && (IS_AI(g, p->owner) || (g->evn.ceasefire[p->owner][pi] <= 0)) && (e->treaty[p->owner] != TREATY_ALLIANCE) && (e->have_colony_for <= p->type) && ((!game_num_ai_trans_range_fix) || (p->within_frange[pi] == 1)) ) { const shipcount_t *s; s = &(e->orbit[i].ships[0]); for (int j = 0; j < e->shipdesigns_num; ++j) { if (s[j]) { have_orbit = true; break; } } } BOOLVEC_SET(tbl_trans_to, i, have_orbit); BOOLVEC_SET(tbl_trans_from, i, (p->owner == pi) && (p->pop >= (p->max_pop3 / 2)) && (p->pop > 20) && ((g->ai_id == GAME_AI_CLASSIC) || (p->unrest != PLANET_UNREST_REBELLION))); } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (r->owner == pi) { BOOLVEC_SET0(tbl_trans_to, r->dest); } } for (int i = 0; i < g->galaxy_stars; ++i) { if (BOOLVEC_IS1(tbl_trans_to, i)) { const planet_t *pt; planet_t *pf; uint8_t pfrom; int mindist, dist; mindist = 10000; pfrom = PLANET_NONE; pt = &(g->planet[i]); for (int j = 0; j < g->galaxy_stars; ++j) { if (BOOLVEC_IS1(tbl_trans_from, j)) { pf = &(g->planet[j]); if ((dist = util_math_dist_fast(pt->x, pt->y, pf->x, pf->y)) < mindist) { mindist = dist; pfrom = j; } } } if ((pfrom != PLANET_NONE) && (mindist < bestspeed)) { pf = &(g->planet[pfrom]); pf->trans_num = pf->pop / 2; pf->trans_dest = i; BOOLVEC_SET0(tbl_trans_from, pfrom); } } } } static void game_ai_classic_turn_p1_trans_own(struct game_s *g, struct ai_turn_p1_s *ait, player_id_t pi) { int bestspeed = game_ai_best_speed(g, pi) * 20 + 20; BOOLVEC_DECLARE(tbl_trans_from, PLANETS_MAX); BOOLVEC_DECLARE(tbl_trans_to, PLANETS_MAX); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); BOOLVEC_SET0(tbl_trans_to, i); BOOLVEC_SET0(tbl_trans_from, i); if (p->owner == pi) { if ((p->pop < (p->max_pop3 / 3)) || (p->unrest == PLANET_UNREST_REBELLION)) { BOOLVEC_SET1(tbl_trans_to, i); } if (p->pop > ((p->max_pop3 * 3) / 4) && ((g->ai_id == GAME_AI_CLASSIC) || (p->unrest != PLANET_UNREST_REBELLION))) { BOOLVEC_SET1(tbl_trans_from, i); } } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (r->owner == pi) { BOOLVEC_SET0(tbl_trans_to, r->dest); } } for (int i = 0; i < g->galaxy_stars; ++i) { if (BOOLVEC_IS1(tbl_trans_to, i)) { const planet_t *pt; planet_t *pf; uint8_t pfrom; pfrom = PLANET_NONE; pt = &(g->planet[i]); for (int j = 0; (j < g->galaxy_stars) && (pfrom == PLANET_NONE); ++j) { if (BOOLVEC_IS1(tbl_trans_from, j)) { pf = &(g->planet[j]); if (util_math_dist_fast(pt->x, pt->y, pf->x, pf->y) < bestspeed) { pfrom = j; pf->trans_num = pf->pop / 3; pf->trans_dest = i; BOOLVEC_SET0(tbl_trans_from, j); } } } } } } static void game_ai_classic_turn_p1_build_defending_ships(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); BOOLVEC_DECLARE(tbl_incoming, PLANETS_MAX); BOOLVEC_CLEAR(tbl_incoming, PLANETS_MAX); for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (1 && (r->owner != pi) && ((g->ai_id == GAME_AI_CLASSIC) || (e->treaty[r->owner] != TREATY_ALLIANCE)) && (g->planet[r->dest].owner == pi) ) { BOOLVEC_SET1(tbl_incoming, r->dest); } } for (int i = 0; i < g->galaxy_stars; ++i) { if (BOOLVEC_IS1(tbl_incoming, i)) { uint32_t v; planet_t *p; p = &(g->planet[i]); p->slider[PLANET_SLIDER_SHIP] += p->slider[PLANET_SLIDER_DEF] + p->slider[PLANET_SLIDER_IND] + p->slider[PLANET_SLIDER_TECH]; p->slider[PLANET_SLIDER_DEF] = 0; p->slider[PLANET_SLIDER_IND] = 0; p->slider[PLANET_SLIDER_TECH] = 0; v = e->reserve_bc / 5; e->reserve_bc -= v; p->reserve += v; } } } static void game_ai_classic_turn_p1_fund_developing(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if ((p->owner == pi) && (p->pop < 20)) { uint32_t v; v = e->reserve_bc / 5; e->reserve_bc -= v; p->reserve += v; } } } static void game_ai_classic_turn_p1_tax(struct game_s *g, player_id_t pi) { g->eto[pi].tax = (g->year >= 20) ? (rnd_1_n(10, &g->seed) + g->difficulty + 2) : 0; } static void game_ai_classic_turn_p1(struct game_s *g) { struct ai_turn_p1_s ait[1]; for (player_id_t pi = PLAYER_0; pi < PLAYER_NUM; ++pi) { const empiretechorbit_t *e = &(g->eto[pi]); const shipdesign_t *sd = &(g->srd[pi].design[0]); for (int i = 0; i < e->shipdesigns_num; ++i) { uint32_t v; v = 0; for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { weapon_t wt; wt = sd[i].wpnt[j]; if (!tbl_shiptech_weap[wt].is_bomb) { v += tbl_shiptech_weap[wt].tech_i * sd[i].wpnn[j]; } } if (v != 0) { v += ((sd[i].shield + 10) * sd[i].hp) / 50; } for (int j = 0; j < SPECIAL_SLOT_NUM; ++j) { ship_special_t st; st = sd[i].special[j]; if (st >= SHIP_SPECIAL_BATTLE_SCANNER) { v += tbl_shiptech_special[st].tech_i * 2; } } if (IS_AI(g, pi)) { if (g->election_held) { v *= 2; } if (g->end != GAME_END_NONE) { v *= 2; } } if (g->ai_id == GAME_AI_CLASSIC) { v &= 0xffff; /* WASBUG the table variables are 16 bit in MOO1 */ } ait->tbl_shipthreat[pi][i] = v; } for (int i = e->shipdesigns_num; i < NUM_SHIPDESIGNS; ++i) { ait->tbl_shipthreat[pi][i] = 0; } } for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { ait->tbl_shipthreat[PLAYER_NUM][i] = 1800; } game_update_maint_costs(g); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (IS_ALIVE(g, pi)) { int xsum, ysum, num_planets; /* BUG moved below to next loop as only the last player affected num_enroute int num_enroute; num_enroute = 0; for (int i = 0; i < g->enroute_num; ++i) { if (g->enroute[i].owner == pi) { ++num_enroute; } } */ xsum = 0; ysum = 0; num_planets = 0; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { xsum += p->x; ysum += p->y; ++num_planets; } } if (num_planets) { ait->tbl_xcenter[pi] = xsum / num_planets; ait->tbl_ycenter[pi] = ysum / num_planets; } else { ait->tbl_xcenter[pi] = 0; ait->tbl_ycenter[pi] = 0; } } } for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { bool flag_send_colony; if (IS_HUMAN(g, pi)) { continue; } flag_send_colony = true; if (g->eto[pi].trait2 != TRAIT2_EXPANSIONIST) { int num_planets, num_developing_planets; num_planets = 0; num_developing_planets = 0; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { ++num_planets; if ((p->missile_bases < (p->max_pop3 / 20)) && (p->pop < ((p->max_pop3 * 2) / 3))) { ++num_developing_planets; } } } if ((num_planets / 2) < num_developing_planets) { for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (IS_HUMAN(g, pi2) && BOOLVEC_IS1(g->eto[pi2].contact, pi)) { flag_send_colony = false; break; } } } } game_ai_classic_turn_p1_send_scout(g, ait, pi); game_ai_classic_turn_p1_front(g, ait, pi); if (game_ai_classic_turn_p1_have_colony_ship(g, ait, pi)) { if (flag_send_colony) { game_ai_classic_turn_p1_send_colony_ships(g, ait, pi); } } game_ai_classic_turn_p1_front(g, ait, pi); game_ai_classic_turn_p1_planet_w(g, ait, pi); if (ait->planet_en_num != 0) { game_ai_classic_turn_p1_send_attack(g, ait, pi); } game_ai_classic_turn_p1_send_defend(g, ait, pi); /* WASBUG moved above to next loop as only the last player affected num_enroute */ { int num_enroute; num_enroute = 0; for (int i = 0; i < g->enroute_num; ++i) { if (g->enroute[i].owner == pi) { ++num_enroute; } } if (num_enroute < 8) { game_ai_classic_turn_p1_send_idle(g, ait, pi); } } game_ai_classic_turn_p1_trans_en(g, ait, pi); game_ai_classic_turn_p1_trans_own(g, ait, pi); game_ai_classic_turn_p1_build_defending_ships(g, pi); game_ai_classic_turn_p1_fund_developing(g, pi); game_ai_classic_turn_p1_tax(g, pi); } } /* -------------------------------------------------------------------------- */ static void game_ai_classic_design_scrap(struct game_s *g, player_id_t pi, int shipi) { empiretechorbit_t *e = &(g->eto[pi]); int si; game_design_scrap(g, pi, shipi, false); si = e->shipi_colony; if (si == shipi) { si = -1; } else if (si > shipi) { --si; } e->shipi_colony = si; si = e->shipi_bomber; if (si == shipi) { si = -1; } else if (si > shipi) { --si; } e->shipi_bomber = si; } static uint8_t game_ai_classic_design_ship_get_look(struct game_s *g, player_id_t pi, ship_hull_t hull) { empiretechorbit_t *e = &(g->eto[pi]); shipresearch_t *srd = &(g->srd[pi]); BOOLVEC_DECLARE(tbl_in_use, SHIP_LOOK_PER_HULL); BOOLVEC_CLEAR(tbl_in_use, SHIP_LOOK_PER_HULL); uint8_t look, lookmax, lookbase = SHIP_LOOK_PER_HULL * hull + e->banner * SHIP_LOOK_PER_BANNER; lookmax = lookbase + (SHIP_LOOK_PER_HULL - 1); for (int i = 0; i < e->shipdesigns_num; ++i) { look = srd->design[i].look; if ((look >= lookbase) && (look <= lookmax)) { BOOLVEC_SET1(tbl_in_use, look - lookbase); } } look = 0; while (BOOLVEC_IS1(tbl_in_use, look)) { ++look; } if (look > (SHIP_LOOK_PER_HULL - 1)) { look = 0; } return look + lookbase; } static int count_havebuf_items(const int8_t *tbl, int last) { int num = 0; for (int i = 0; i < last; ++i) { if (tbl[i] > 0) { ++num; } } return num; } static int find_havebuf_item(const int8_t *tbl, int num) { int i; for (i = 0; (num > 0); ++i) { if (tbl[i] > 0) { --num; } } return i ? (i - 1) : 0; } static int game_ai_classic_design_ship_get_item(struct game_s *g, int num, int chance) { while ((rnd_1_n(100, &g->seed) > chance) && (num > 1)) { chance *= 2; --num; } return num; } static int game_ai_classic_design_update_engines_space(struct game_design_s *gd) { shipdesign_t *sd = &(gd->sd); game_design_update_engines(sd); sd->space = game_design_calc_space(gd); return sd->space; } static void game_ai_classic_design_ship_base(struct game_s *g, struct ai_turn_p2_s *ait, player_id_t pi) { int8_t tbl_have[SHIP_SPECIAL_NUM]; /* largest of the used */ shipdesign_t *sd = &(ait->gd.sd); ship_hull_t hull = sd->hull; int space; const uint8_t tbl_chance_special[SHIP_SPECIAL_NUM][SHIP_HULL_NUM] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 30, 80 }, { 0, 10, 50, 80 }, { 0, 0, 25, 80 }, { 0, 0, 20, 70 }, { 0, 5, 20, 60 }, { 20, 30, 50, 80 }, { 0, 10, 40, 70 }, { 0, 0, 25, 50 }, { 0, 0, 20, 40 }, { 20, 30, 40, 70 }, { 0, 0, 20, 30 }, { 10, 20, 25, 35 }, { 0, 0, 20, 30 }, { 0, 0, 20, 40 }, { 10, 20, 30, 40 }, { 0, 10, 30, 50 }, { 0, 0, 30, 60 }, { 0, 0, 0, 50 }, { 0, 10, 20, 30 }, { 10, 20, 40, 60 }, { 10, 20, 40, 60 }, { 10, 20, 40, 60 } }; { int v; v = game_design_build_tbl_fit_engine(g, &ait->gd, tbl_have); v = count_havebuf_items(tbl_have, v); if (g->ai_id == GAME_AI_CLASSIC || v < 2) { v = game_ai_classic_design_ship_get_item(g, v, 60); } else { if (v > 2) { int best = find_havebuf_item(tbl_have, v); int next = find_havebuf_item(tbl_have, v - 1); if (next > 1 && best - next < 3) v = game_ai_classic_design_ship_get_item(g, v, 45 + (best - next)*15); } /* else v = v; */ } sd->engine = find_havebuf_item(tbl_have, v); } space = game_ai_classic_design_update_engines_space(&ait->gd) / 3; if (ait->shiptype == 0/*colony*/) { int v; v = game_design_build_tbl_fit_special(g, &ait->gd, tbl_have, 0); tbl_have[SHIP_SPECIAL_RESERVE_FUEL_TANKS] = 0; for (int i = SHIP_SPECIAL_BATTLE_SCANNER; i <= v; ++i) { tbl_have[i] = 0; } v = count_havebuf_items(tbl_have, v); if (v >= 2) { v = find_havebuf_item(tbl_have, v); if (v < SHIP_SPECIAL_STANDARD_COLONY_BASE) { LOG_DEBUG((1, "%s: BUG: invalid colony special %i\n", __func__, v)); v = SHIP_SPECIAL_STANDARD_COLONY_BASE; } } else { v = SHIP_SPECIAL_STANDARD_COLONY_BASE; } sd->special[0] = v; if (ait->gd.percent[TECH_FIELD_CONSTRUCTION] > 5) { sd->special[1] = SHIP_SPECIAL_RESERVE_FUEL_TANKS; } /* BUG? no update_engines */ } { const int tbl_chance[SHIP_HULL_NUM] = { 10, 20, 35, 50 }; int v; v = game_design_build_tbl_fit_comp(g, &ait->gd, tbl_have); v = count_havebuf_items(tbl_have, v); v = game_ai_classic_design_ship_get_item(g, v, tbl_chance[hull]); sd->comp = find_havebuf_item(tbl_have, v); } if (game_ai_classic_design_update_engines_space(&ait->gd) < space) { return; } { const int tbl_chance[SHIP_HULL_NUM] = { 5, 15, 40, 70 }; int v; v = game_design_build_tbl_fit_shield(g, &ait->gd, tbl_have); v = count_havebuf_items(tbl_have, v); v = game_ai_classic_design_ship_get_item(g, v, tbl_chance[hull]); sd->shield = find_havebuf_item(tbl_have, v); } if (game_ai_classic_design_update_engines_space(&ait->gd) < space) { return; } { const int tbl_chance[SHIP_HULL_NUM] = { 1, 2, 4, 8 }; int v; v = game_design_build_tbl_fit_armor(g, &ait->gd, tbl_have); if ((rnd_1_n(100, &g->seed) <= tbl_chance[hull]) && ((v & 1) == 1)) { /* NOP */ } else { v &= ~1; } sd->armor = v; } if (game_ai_classic_design_update_engines_space(&ait->gd) < space) { return; } if (ait->shiptype == 0/*colony*/) { return; } for (int si = 0; si <= 1; ++si) { int v; ship_special_t st; st = SHIP_SPECIAL_NONE; v = game_design_build_tbl_fit_special(g, &ait->gd, tbl_have, si); for (int i = SHIP_SPECIAL_RESERVE_FUEL_TANKS; i < SHIP_SPECIAL_BATTLE_SCANNER; ++i) { tbl_have[i] = 0; } for (int i = 0; i <= v; ++i) { if ((rnd_1_n(100, &g->seed) <= tbl_chance_special[i][hull]) && (tbl_have[i] > 0)) { st = i; } } sd->special[si] = st; if (game_ai_classic_design_update_engines_space(&ait->gd) < space) { return; } } { const int tbl_chance[SHIP_HULL_NUM] = { 30, 20, 20, 15 }; int v; v = game_design_build_tbl_fit_man(g, &ait->gd, tbl_have); v = count_havebuf_items(tbl_have, v); v = game_ai_classic_design_ship_get_item(g, v, tbl_chance[hull]); sd->man = find_havebuf_item(tbl_have, v); } if (game_ai_classic_design_update_engines_space(&ait->gd) < space) { return; } { const int tbl_chance[SHIP_HULL_NUM] = { 2, 8, 20, 30 }; int v; v = game_design_build_tbl_fit_jammer(g, &ait->gd, tbl_have); v = count_havebuf_items(tbl_have, v); v = game_ai_classic_design_ship_get_item(g, v, tbl_chance[hull]); sd->jammer = find_havebuf_item(tbl_have, v); } { int v; ship_special_t st; st = SHIP_SPECIAL_NONE; v = game_design_build_tbl_fit_special(g, &ait->gd, tbl_have, 2); for (int i = SHIP_SPECIAL_RESERVE_FUEL_TANKS; i < SHIP_SPECIAL_BATTLE_SCANNER; ++i) { tbl_have[i] = 0; } for (int i = 0; i <= v; ++i) { if ((rnd_1_n(100, &g->seed) <= tbl_chance_special[i][hull]) && (tbl_have[i] > 0)) { st = i; } } sd->special[2] = st; } } static void game_ai_classic_design_ship_sub2(struct game_s *g, struct ai_turn_p2_s *ait, player_id_t pi) { int8_t tbl_have[SHIP_SPECIAL_NUM]; shipdesign_t *sd = &(ait->gd.sd); ship_hull_t hull = sd->hull; if ((sd->special[2] != SHIP_SPECIAL_NONE) || (hull < SHIP_HULL_LARGE)) { return; } game_design_build_tbl_fit_special(g, &ait->gd, tbl_have, 2); if (tbl_have[SHIP_SPECIAL_BATTLE_SCANNER] > 0) { sd->special[2] = SHIP_SPECIAL_BATTLE_SCANNER; } if ((ait->gd.percent[TECH_FIELD_PROPULSION] < 30) || (sd->special[1] != SHIP_SPECIAL_NONE)) { return; } game_design_build_tbl_fit_special(g, &ait->gd, tbl_have, 2); /* BUG should be slot 1 */ if (tbl_have[SHIP_SPECIAL_INERTIAL_STABILIZER] > 0) { sd->special[1] = SHIP_SPECIAL_INERTIAL_STABILIZER; } } static void game_ai_classic_design_ship_weapon(struct game_s *g, struct ai_turn_p2_s *ait, player_id_t pi, int sloti, int numshots_ignore, int c1, int c2) { int8_t tbl_have[WEAPON_NUM]; shipdesign_t *sd = &(ait->gd.sd); int v; v = game_design_build_tbl_fit_weapon(g, &ait->gd, tbl_have, sloti, WEAPON_GROUP_ALL); if ((sloti == 0) && tbl_shiptech_weap[v].is_bomb && (ait->shiptype != 2/*bomber*/)) { --v; } SETMAX(v, 1); for (int i = 0; i < v; ++i) { /* FIXME <= v ? */ if (tbl_have[i] > 0) { if (0 || (tbl_shiptech_weap[i].numshots == numshots_ignore) || (ait->have_repulwarp && (tbl_shiptech_weap[i].range == 1)) ) { tbl_have[i] = 0; } } } for (int i = 0; i < sloti; ++i) { tbl_have[sd->wpnt[i]] = 0; } v = count_havebuf_items(tbl_have, v); if (v > 1) { int r; v = find_havebuf_item(tbl_have, v); sd->wpnt[sloti] = v; r = ((tbl_shiptech_weap[v].numfire > 0) || (tbl_shiptech_weap[v].nummiss > 0)) ? 41 : 11; sd->wpnn[sloti] = (tbl_have[v] * (rnd_1_n(c2 - c1 + r, &g->seed) + c1)) / 100; } } static void game_ai_classic_design_ship_weapons(struct game_s *g, struct ai_turn_p2_s *ait, player_id_t pi) { int numshots_ignore, weapnum = 1; numshots_ignore = rnd_0_nm1(2, &g->seed) ? 2 : 5; { const shipdesign_t *sd = &(ait->gd.sd); ship_hull_t hull = sd->hull; const int tbl_chance_2[SHIP_HULL_NUM] = { 0, 50, 75, 100 }; if (rnd_1_n(100, &g->seed) <= tbl_chance_2[hull]) { const int tbl_chance_3[SHIP_HULL_NUM] = { 0, 0, 50, 100 }; weapnum = 2; if (rnd_1_n(100, &g->seed) <= tbl_chance_3[hull]) { const int tbl_chance_4[SHIP_HULL_NUM] = { 0, 0, 25, 50 }; weapnum = 3; if (rnd_1_n(100, &g->seed) <= tbl_chance_4[hull]) { weapnum = 4; } } } } for (int i = 0; i < weapnum; ++i) { const uint8_t tbl_c1[WEAPON_SLOT_NUM][WEAPON_SLOT_NUM] = { { 100, 100, 100, 100 }, { 60, 100, 100, 100 }, { 40, 40, 100, 100 }, { 40, 40, 60, 100 } }; const uint8_t tbl_c2[WEAPON_SLOT_NUM][WEAPON_SLOT_NUM] = { { 100, 100, 100, 100 }, { 80, 100, 100, 100 }, { 70, 70, 100, 100 }, { 60, 60, 80, 100 } }; game_ai_classic_design_ship_weapon(g, ait, pi, i, numshots_ignore, tbl_c1[weapnum - 1][i], tbl_c2[weapnum - 1][i]); } } static void game_ai_classic_design_ship(struct game_s *g, struct ai_turn_p2_s *ait, player_id_t pi) { shipdesign_t *sd = &(ait->gd.sd); empiretechorbit_t *e = &(g->eto[pi]); bool temp_repulwarp = ait->have_repulwarp; int loops = 0; again: if (++loops >= 100000) { log_fatal_and_die("BUG: %s looped %i times\n", __func__, loops); } if (ait->shiptype != 0/*colony*/) { const int8_t tbl_hulldiff[RACE_NUM] = { 0, 0, 3, 0, 0, -3, -3, 3, 3, 0 }; const ship_hull_t tbl_hull[12] = { 0, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3 }; int v; v = rnd_0_nm1(12, &g->seed) + tbl_hulldiff[e->race]; SETMAX(v, 0); if (ait->have_pulsar) { ++v; } SETMIN(v, 11); ait->hull = tbl_hull[v]; } else { ait->hull = SHIP_HULL_LARGE; } ait->shiplook = game_ai_classic_design_ship_get_look(g, pi, ait->hull); sd->wpnn[0] = 0; for (int loops2 = 0; (sd->wpnn[0] == 0) && (loops2 < 100000); ++loops2) { game_design_prepare_ai(g, &ait->gd, pi, ait->hull, ait->shiplook); game_ai_classic_design_ship_base(g, ait, pi); game_ai_classic_design_ship_sub2(g, ait, pi); game_ai_classic_design_ship_weapons(g, ait, pi); game_design_set_hp(sd); game_design_compact_slots(sd); if (ait->shiptype == 0/*colony*/) { lib_strcpy(sd->name, game_str_ai_colonyship, SHIP_NAME_LEN); if (sd->wpnn[0] == 0) { sd->wpnt[0] = WEAPON_LASER; sd->wpnn[0] = 1; } } sd->cost = game_design_calc_cost(&ait->gd); } if (sd->wpnn[0] == 0) { if (ait->have_repulwarp) { log_warning("%s: failure to design against repulsor/warpdis (hull %i)\n", __func__, ait->hull); if (ait->hull == SHIP_HULL_SMALL) { log_warning("%s: trying again\n", __func__); } else { ait->have_repulwarp = false; log_warning("%s: relaxing 1 rng limit\n", __func__); } goto again; } else { log_fatal_and_die("BUG: %s loops2\n", __func__); } } { bool flag_again, is_missile; weapon_t wt; flag_again = false; wt = sd->wpnt[0]; is_missile = tbl_shiptech_weap[wt].damagemin == tbl_shiptech_weap[wt].damagemax; if (is_missile || tbl_shiptech_weap[wt].is_bomb) { for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { if (sd->special[i] == SHIP_SPECIAL_HIGH_ENERGY_FOCUS) { flag_again = true; } } } if (is_missile) { for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { if (sd->special[i] == SHIP_SPECIAL_ORACLE_INTERFACE) { flag_again = true; } } } if (flag_again) { goto again; } } game_design_add(g, pi, sd, false); ait->have_repulwarp = temp_repulwarp; } static void game_ai_classic_turn_p2_do(struct game_s *g, player_id_t pi) { struct ai_turn_p2_s ait[1]; empiretechorbit_t *e = &(g->eto[pi]); shipresearch_t *srd = &(g->srd[pi]); shipdesign_t *sd = &(srd->design[0]); int num_non0 = 0; ait->have_pulsar = false; ait->have_repulwarp = false; for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { const shipdesign_t *sd2; int sn; if (IS_AI(g, p2) || (!IS_ALIVE(g, p2))) { continue; } sn = g->eto[p2].shipdesigns_num; sd2 = &(g->srd[p2].design[0]); for (int i = 0; i < sn; ++i) { const ship_special_t *ss = &(sd2[i].special[0]); for (int j = 0; j < SPECIAL_SLOT_NUM; ++j) { ship_special_t s; s = ss[j]; if ((s == SHIP_SPECIAL_ENERGY_PULSAR) || (s == SHIP_SPECIAL_IONIC_PULSAR)) { ait->have_pulsar = true; } if ((s == SHIP_SPECIAL_REPULSOR_BEAM) || (s == SHIP_SPECIAL_WARP_DISSIPATOR)) { ait->have_repulwarp = true; } } } } e->ai_p2_countdown = rnd_1_n(12, &g->seed) + 8; game_update_maint_costs(g); e->shipi_colony = -1; e->shipi_bomber = -1; for (int i = 0; i < e->shipdesigns_num; ++i) { ship_special_t *ss = &(sd[i].special[0]); if (srd->shipcount[i] != 0) { ++num_non0; } for (int j = 0; j < SPECIAL_SLOT_NUM; ++j) { ship_special_t s; s = ss[j]; if ((s >= SHIP_SPECIAL_STANDARD_COLONY_BASE) && (s <= SHIP_SPECIAL_RADIATED_COLONY_BASE)) { e->shipi_colony = i; } } if (tbl_shiptech_weap[sd[i].wpnt[0]].is_bomb) { e->shipi_bomber = i; } } for (int i = 0; (i < e->shipdesigns_num) && (num_non0 > 1); ++i) { if (0 || ((g->year < 100) && ((g->year - srd->year[i]) > 50)) || ((g->year >= 100) && ((g->year - srd->year[i]) > 100)) ) { game_ai_classic_design_scrap(g, pi, i); --num_non0; /* BUG this could be a non-non0 ship design */ } } num_non0 = 0; for (int i = 0; i < e->shipdesigns_num; ++i) { if (srd->shipcount[i] != 0) { ++num_non0; } } { int shipi_remove = -1; if (num_non0 > 4) { int year_oldest = 0xffff; for (int i = 0; i < e->shipdesigns_num; ++i) { int sy; sy = srd->year[i]; if (sy < year_oldest) { year_oldest = sy; shipi_remove = i; } } } else if (e->shipdesigns_num > 1) { for (int i = 0; i < e->shipdesigns_num; ++i) { if (srd->shipcount[i] == 0) { shipi_remove = i; break; } } } if (shipi_remove != -1) { game_ai_classic_design_scrap(g, pi, shipi_remove); } } for (int loops = 0; (e->shipdesigns_num < NUM_SHIPDESIGNS) && (loops < 10000); ++loops) { int si; si = e->shipdesigns_num; if (e->shipi_colony == -1) { e->shipi_colony = si; ait->shiptype = 0/*colony*/; } else if (e->shipi_bomber == -1) { e->shipi_bomber = si; ait->shiptype = 2/*bomber*/; } else { ait->shiptype = 1/*fighter*/; } game_ai_classic_design_ship(g, ait, pi); } if (e->shipdesigns_num < NUM_SHIPDESIGNS) { log_fatal_and_die("BUG: %s hang\n", __func__); } for (int i = 0; i < e->shipdesigns_num; ++i) { ship_special_t *ss = &(sd[i].special[0]); for (int j = 0; j < SPECIAL_SLOT_NUM; ++j) { ship_special_t s; s = ss[j]; if ((s >= SHIP_SPECIAL_STANDARD_COLONY_BASE) && (s <= SHIP_SPECIAL_RADIATED_COLONY_BASE)) { e->shipi_colony = i; } } if (tbl_shiptech_weap[sd[i].wpnt[0]].is_bomb) { e->shipi_bomber = i; } } { uint8_t tbl_i[NUM_SHIPDESIGNS]; uint16_t tbl_year[NUM_SHIPDESIGNS]; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { tbl_i[i] = i; tbl_year[i] = srd->year[i]; if (i == e->shipi_colony) { tbl_year[i] = 0; } } for (int j = 0; j < NUM_SHIPDESIGNS - 1; ++j) { for (int i = 0; i < NUM_SHIPDESIGNS - 1; ++i) { uint16_t y1, y; y1 = tbl_year[i + 1]; y = tbl_year[i]; if (y1 > y) { uint8_t t; tbl_year[i + 1] = y; tbl_year[i] = y1; t = tbl_i[i]; tbl_i[i] = tbl_i[i + 1]; tbl_i[i + 1] = t; } } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { uint8_t n; if ((!p->have_stargate) && (e->have_stargates) && (rnd_0_nm1(2, &g->seed))) { n = BUILDSHIP_STARGATE; } else { n = tbl_i[rnd_0_nm1(3, &g->seed)]; } p->buildship = n; } } } } static void game_ai_classic_turn_p2(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (IS_AI(g, pi) && IS_ALIVE(g, pi)) { if (--g->eto[pi].ai_p2_countdown <= 0) { game_ai_classic_turn_p2_do(g, pi); } } } } /* -------------------------------------------------------------------------- */ static void game_ai_classic_turn_p3_sub1(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { e->spymode_next[pi2] = SPYMODE_HIDE; if (IS_HUMAN(g, pi2) && (g->evn.ceasefire[pi2][pi2] > 0)) { /* FIXME BUG should be [pi2][pi] */ e->spymode_next[pi2] = SPYMODE_HIDE; /* FIXME redundant */ } else if ((pi != pi2) && BOOLVEC_IS1(e->contact, pi2)) { if (e->treaty[pi2] >= TREATY_WAR) { e->spymode_next[pi2] = SPYMODE_SABOTAGE; } else if (e->spymode_next[pi2] == SPYMODE_HIDE) { /* FIXME BUG always true */ if ((e->race == RACE_DARLOK) || rnd_0_nm1(2, &g->seed)) { if (rnd_1_n(200, &g->seed) > (e->relation1[pi2] * 2 + 200)) { e->spymode_next[pi2] = SPYMODE_ESPIONAGE; } } else { e->spymode_next[pi2] = SPYMODE_HIDE; /* FIXME redundant */ } } else { if (rnd_1_n(100, &g->seed) > (e->relation1[pi2] + 100)) { e->spymode_next[pi2] = SPYMODE_SABOTAGE; } } } } } static void game_ai_classic_turn_p3(struct game_s *g) { /* AI p3 slider weights [0..3] ship/def/ind/eco [4..8] computer/construction/force field/planetology/propulsion */ static const int8_t ai_p3_tbl_w[TRAIT2_NUM + 1/*war*/][9] = { { 1, 2, 4, 1, 2, 2, 4, 2, 3 }, { 4, 1, 2, 1, 3, 1, 4, 2, 1 }, { 2, 4, 1, 1, 1, 1, 3, 5, 2 }, { 1, 2, 3, 1, 4, 2, 3, 2, 2 }, { 1, 2, 4, 1, 1, 5, 4, 1, 2 }, { 1, 1, 2, 4, 1, 2, 4, 1, 5 }, { 4, 1, 1, 1, 2, 2, 4, 2, 1 } /* War */ }; for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); trait2_t ti; race_t race; if (IS_HUMAN(g, pi)) { continue; } race = e->race; /* BUG this was inside the if (--countdown) and ti is used later outside it */ ti = e->trait2; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (e->treaty[pi2] >= TREATY_WAR) { ti = TRAIT2_NUM/*war*/; } } if (--e->ai_p3_countdown <= 0) { int w_ship, w_def, w_ind, w_eco; e->ai_p3_countdown = rnd_1_n(5, &g->seed) + 1; game_update_eco_on_waste(g, pi, true); w_ship = ai_p3_tbl_w[ti][0]; w_def = w_ship + ai_p3_tbl_w[ti][1]; w_ind = w_def + ai_p3_tbl_w[ti][2]; w_eco = w_ind + ai_p3_tbl_w[ti][2]; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { int left; int16_t *sl; sl = &(p->slider[0]); sl[PLANET_SLIDER_SHIP] = 0; sl[PLANET_SLIDER_DEF] = 0; sl[PLANET_SLIDER_IND] = 0; sl[PLANET_SLIDER_TECH] = 0; if (sl[PLANET_SLIDER_ECO] < 96) { sl[PLANET_SLIDER_SHIP] = 5; } if (sl[PLANET_SLIDER_ECO] < 91) { sl[PLANET_SLIDER_DEF] = 5; } if (sl[PLANET_SLIDER_ECO] < 81) { sl[PLANET_SLIDER_IND] = 10; } if (sl[PLANET_SLIDER_ECO] < 71) { sl[PLANET_SLIDER_TECH] = 25; } if (p->pop < ((p->max_pop3 * 3) / 4)) { sl[PLANET_SLIDER_IND] = 50; } if (((race == RACE_BULRATHI) || (race == RACE_SAKKRA)) && (p->pop < p->max_pop2)) { sl[PLANET_SLIDER_ECO] += 10; } if ((race == RACE_KLACKON) && (p->pop < p->max_pop2)) { sl[PLANET_SLIDER_ECO] += 15; } if (race == RACE_MEKLAR) { sl[PLANET_SLIDER_IND] += 20; } if (race == RACE_PSILON) { sl[PLANET_SLIDER_TECH] += 20; } if (race == RACE_MRRSHAN) { sl[PLANET_SLIDER_SHIP] += 15; } if ((p->special == PLANET_SPECIAL_ARTIFACTS) || (p->special == PLANET_SPECIAL_4XTECH)) { sl[PLANET_SLIDER_TECH] += 20; } if (p->special >= PLANET_SPECIAL_RICH) { sl[PLANET_SLIDER_IND] += 20; sl[PLANET_SLIDER_SHIP] += 10; } left = 100 - sl[PLANET_SLIDER_SHIP] - sl[PLANET_SLIDER_DEF] - sl[PLANET_SLIDER_IND] - sl[PLANET_SLIDER_ECO] - sl[PLANET_SLIDER_TECH]; while (left > 0) { int r1, r2; r1 = rnd_1_n(13, &g->seed); r2 = rnd_1_n(8, &g->seed) + 2; SETMIN(r2, left); left -= r2; if (r1 <= w_ship) { sl[PLANET_SLIDER_SHIP] += r2; } else if (r1 <= w_def) { sl[PLANET_SLIDER_DEF] += r2; } else if (r1 <= w_ind) { sl[PLANET_SLIDER_IND] += r2; } else if (r1 <= w_eco) { sl[PLANET_SLIDER_ECO] += r2; } else { sl[PLANET_SLIDER_TECH] += r2; } } } } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { int16_t *sl; sl = &(p->slider[0]); if (p->factories >= (p->pop * e->colonist_oper_factories)) { uint8_t si; si = sl[PLANET_SLIDER_IND]; sl[PLANET_SLIDER_DEF] += si / 2; sl[PLANET_SLIDER_TECH] += (si / 2) + (si % 2); sl[PLANET_SLIDER_IND] = 0; } if (1 && (p->missile_bases > 4) && ((p->missile_bases * 3) >= (p->pop / (5 - g->difficulty))) && (p->shield >= e->have_planet_shield) ) { uint16_t v; if (game_num_ai_fleet_cheating_fix) { v = sl[PLANET_SLIDER_DEF]; } else { v = sl[PLANET_SLIDER_SHIP]; /* BUG creates very large fleets */ } sl[PLANET_SLIDER_SHIP] += v; sl[PLANET_SLIDER_DEF] = 0; } } } if ((g->year % 10) == pi) { int16_t *sl; sl = &(e->tech.slider[0]); sl[TECH_FIELD_COMPUTER] = 5; sl[TECH_FIELD_CONSTRUCTION] = 5; sl[TECH_FIELD_FORCE_FIELD] = 5; sl[TECH_FIELD_PLANETOLOGY] = 5; sl[TECH_FIELD_PROPULSION] = 5; sl[TECH_FIELD_WEAPON] = 5; if ((g->year < 30) && rnd_0_nm1(2, &g->seed)) { sl[TECH_FIELD_PROPULSION] = 75; } else { bool flag_focus_own; flag_focus_own = !rnd_0_nm1(4, &g->seed); if (((race == RACE_BULRATHI) || (race == RACE_MRRSHAN)) && flag_focus_own) { sl[TECH_FIELD_WEAPON] = 75; } else if ((race == RACE_DARLOK) && flag_focus_own) { sl[TECH_FIELD_COMPUTER] = 75; } else if ((race == RACE_MEKLAR) && flag_focus_own) { sl[rnd_0_nm1(2, &g->seed) ? TECH_FIELD_CONSTRUCTION : TECH_FIELD_PLANETOLOGY] = 75; } else if ((race == RACE_ALKARI) && flag_focus_own) { sl[TECH_FIELD_PROPULSION] = 75; } else if ((race == RACE_SAKKRA) && flag_focus_own) { sl[TECH_FIELD_PLANETOLOGY] = 75; } else { int r1, w_comp, w_cons, w_ff, w_plan, w_prop; r1 = rnd_1_n(16, &g->seed); w_comp = ai_p3_tbl_w[ti][4]; w_cons = w_comp + ai_p3_tbl_w[ti][5]; w_ff = w_cons + ai_p3_tbl_w[ti][6]; w_prop = w_ff + ai_p3_tbl_w[ti][8]; w_plan = w_prop + ai_p3_tbl_w[ti][7]; if (r1 <= w_comp) { sl[TECH_FIELD_COMPUTER] = 75; } else if (r1 <= w_cons) { sl[TECH_FIELD_CONSTRUCTION] = 75; } else if (r1 <= w_ff) { sl[TECH_FIELD_FORCE_FIELD] = 75; } else if (r1 <= w_prop) { sl[TECH_FIELD_PROPULSION] = 75; } else if (r1 <= w_plan) { sl[TECH_FIELD_PLANETOLOGY] = 75; } else { sl[TECH_FIELD_WEAPON] = 75; } } } } if (g->year > 30) { uint32_t totalspies; int16_t sec; totalspies = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if (BOOLVEC_IS1(e->contact, pi2)) { totalspies += g->eto[pi2].spies[pi]; } } if (totalspies == 0) { sec = 0; } else { sec = rnd_0_nm1(2, &g->seed) * totalspies; } sec += g->difficulty * 8; SETMIN(sec, 100); e->security = sec; game_ai_classic_turn_p3_sub1(g, pi); for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { e->spying[pi2] = 0; e->spymode[pi2] = SPYMODE_HIDE; if (1 && (pi != pi2) && BOOLVEC_IS1(e->contact, pi2) && (e->spymode_next[pi2] != SPYMODE_HIDE) && (BOOLVEC_IS0(g->is_ai, pi2) || !rnd_0_nm1(3, &g->seed)) ) { e->spymode[pi2] = e->spymode_next[pi2]; e->spying[pi2] = rnd_1_n(5, &g->seed) + 5; } } } } } /* -------------------------------------------------------------------------- */ static void game_ai_classic_battle_ai_ai_get_weights(const struct game_s *g, player_id_t pi, int *tbl) { const empiretechorbit_t *e = &(g->eto[pi]); for (int i = 0; i < e->shipdesigns_num; ++i) { const shipdesign_t *sd = &(g->srd[pi].design[i]); tbl[i] += sd->shield * 5; tbl[i] += sd->comp * 5; tbl[i] += sd->wpnt[0]; tbl[i] += sd->armor * 10; tbl[i] += sd->special[0] * 2; tbl[i] += sd->special[1] * 2; tbl[i] += sd->special[2] * 2; tbl[i] += e->tech.percent[TECH_FIELD_CONSTRUCTION] / 2; if ((e->race == RACE_MRRSHAN) || (e->race == RACE_ALKARI)) { tbl[i] += ((g->ai_id == GAME_AI_CLASSIC) ? 15 : 20); } tbl[i] *= game_num_tbl_hull_w[sd->hull]; } } static bool game_ai_classic_battle_ai_ai_resolve_do(struct battle_s *bt) { struct game_s *g = bt->g; bool r_won; int tbl_weight_l[NUM_SHIPDESIGNS], tbl_weight_r[NUM_SHIPDESIGNS]; int base_l = 0, base_r = 0, wl = 0, wr = 0, wl2, wr2; bt->biodamage = 0; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { tbl_weight_l[i] = 0; tbl_weight_r[i] = 0; } if (bt->s[SIDE_L].party < PLAYER_NUM) { game_ai_classic_battle_ai_ai_get_weights(g, bt->s[SIDE_L].party, tbl_weight_l); } if (bt->s[SIDE_R].party < PLAYER_NUM) { game_ai_classic_battle_ai_ai_get_weights(g, bt->s[SIDE_R].party, tbl_weight_r); } switch (bt->planet_side) { case SIDE_NONE: break; case SIDE_L: { empiretechorbit_t *e = &(g->eto[bt->s[SIDE_L].party]); base_l = e->tech.percent[TECH_FIELD_WEAPON] + e->tech.percent[TECH_FIELD_FORCE_FIELD]; } break; case SIDE_R: { empiretechorbit_t *e = &(g->eto[bt->s[SIDE_R].party]); base_r = e->tech.percent[TECH_FIELD_WEAPON] + e->tech.percent[TECH_FIELD_FORCE_FIELD]; } break; } for (int i = 0; i < bt->s[SIDE_L].num_types; ++i) { wl += bt->s[SIDE_L].tbl_ships[i] * tbl_weight_l[bt->s[SIDE_L].tbl_shiptype[i]]; } for (int i = 0; i < bt->s[SIDE_R].num_types; ++i) { wr += bt->s[SIDE_R].tbl_ships[i] * tbl_weight_r[bt->s[SIDE_R].tbl_shiptype[i]]; } wl += base_l * 75 * bt->bases; wr += base_r * 75 * bt->bases; if (bt->s[SIDE_L].party >= PLAYER_NUM) { wl = ((bt->s[SIDE_L].party - PLAYER_NUM) == MONSTER_GUARDIAN) ? 100000 : 30000; } if (bt->s[SIDE_R].party >= PLAYER_NUM) { wr = ((bt->s[SIDE_R].party - PLAYER_NUM) == MONSTER_GUARDIAN) ? 100000 : 30000; } wl2 = wl; wr2 = wr; while ((wl2 > 0) && (wr2 > 0)) { int v; v = (rnd_1_n(10, &g->seed) * wl) / 100; SETMAX(v, 1); wr2 -= v; v = (rnd_1_n(10, &g->seed) * wr) / 100; SETMAX(v, 1); wl2 -= v; } SETMAX(wl2, 0); SETMAX(wr2, 0); r_won = wr2 > 0; for (battle_side_i_t s = SIDE_L; s <= SIDE_R; ++s) { if (bt->s[s].party < PLAYER_NUM) { int ws2, ws; ws2 = (s == SIDE_L) ? wl2 : wr2; ws = (s == SIDE_L) ? wl : wr; if (ws == 0) { for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { bt->s[s].tbl_ships[i] = 0; } } else { for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (game_num_doom_stack_fix) { bt->s[s].tbl_ships[i] = (((uint64_t)bt->s[s].tbl_ships[i]) * ws2) / ws; } else { /* WASBUG MOO1 uses 32bit math which results in negative overflows with large ws2, giving negative ship counts which get limited to 32000 later. */ bt->s[s].tbl_ships[i] = (bt->s[s].tbl_ships[i] * ws2) / ws; } } } } } if (g->ai_id == GAME_AI_CLASSIC) { /* WASBUG MOO1 uses ui_main_loop_action for the switch variable below; since it is UI_MAIN_LOOP_NEXT_TURN (== 8) at this point, bt->bases is unaffected. */ return r_won; } switch (bt->planet_side) { case SIDE_NONE: bt->bases = 0; break; case SIDE_L: bt->bases = wl ? ((bt->bases * (uint64_t)wl2) / wl) : 0; break; case SIDE_R: bt->bases = wr ? ((bt->bases * (uint64_t)wr2) / wr) : 0; break; } /* BUG? MOO1 passes pointers to pop1 and factories but does not touch them */ return r_won; } static bool game_ai_classic_battle_ai_ai_resolve(struct battle_s *bt) { bool r_won; r_won = game_ai_classic_battle_ai_ai_resolve_do(bt); game_battle_finish(bt); return r_won; } /* -------------------------------------------------------------------------- */ static int game_ai_battle_missile_dmg(const struct battle_s *bt, int missile_i) { const struct battle_missile_s *m = &(bt->missile[missile_i]); /*di*/const struct battle_item_s *b = &(bt->item[m->target]); const struct battle_item_s *bs = &(bt->item[m->source]); const struct shiptech_weap_s *w = &(tbl_shiptech_weap[m->wpnt]); int damagepotential, damagediv = 1, /*si*/miss_chance, damage; miss_chance = 50 - (bs->complevel - b->misdefense) * 10; if (b->cloak == 1) { miss_chance += 50; } miss_chance -= w->extraacc * 10; SETRANGE(miss_chance, 0, 95); if ((m->target == 0/*planet*/) && (!w->is_bomb) && (w->misstype > 0)) { damagediv = 2; } damage = w->damagemax / damagediv; if (bt->g->ai_id == GAME_AI_CLASSIC) { int absorbdiv = game_battle_get_absorbdiv(b, w, true); /* WASBUG checks target's Oracle */ /* WASBUG should be damage -= b->absorb / absorbdiv; if Oracle worked for missiles */ damage -= b->absorb; damage /= absorbdiv; } else { damage -= b->absorb; /* missiles are not affected by Oracle */ } damage *= w->damagemul; SETMIN(damage, b->hp1); damage *= m->damagemul2; damage *= m->nummissiles; if (damage > 0) { damagepotential = ((100 - miss_chance) * damage) / 100; } else { damagepotential = 0; } SETMAX(damagepotential, 0); return damagepotential; } static int game_ai_battle_incoming_missiles_dmg(const struct battle_s *bt, int itemi) { int v = 0, hp; if (itemi == 0/*plamet*/) { return 0; } hp = bt->item[itemi].hp1; for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if (m->target == itemi) { v += game_ai_battle_missile_dmg(bt, i) / hp; } } return v; } static int game_ai_battle_dmgmax(struct battle_s *bt, int itemi) { const struct battle_item_s *b = &(bt->item[itemi]); int v = 0, num_weap = (itemi == 0/*planet*/) ? 1 : 4; bool flag_planet_opponent = false; #if 1 if ((b->side + bt->item[0/*planet*/].side) == 1) { flag_planet_opponent = true; } #else /* FIXME MOO1 does this, but v8 is unused */ int v8 = 0; if (b->side == SIDE_L) { if (bt->item[0/*planet*/].side == SIDE_R) { flag_planet_opponent = true; v8 = bt->item[0/*planet*/].absorb; } for (int i = bt->s[SIDE_L].items + 1; i <= bt->items_num; ++i) { v8 += bt->item[i].absorb; } if ((bt->s[SIDE_R].items > 0) || flag_planet_opponent) { v8 /= bt->s[SIDE_R].items + (flag_planet_opponent ? 1 : 0); } } else { if (bt->item[0/*planet*/].side == SIDE_L) { flag_planet_opponent = true; v8 = bt->item[0/*planet*/].absorb; } for (int i = 1; i <= bt->s[SIDE_L].items; ++i) { v8 += bt->item[i].absorb; } if ((bt->s[SIDE_R].items > 0) || flag_planet_opponent) { v8 /= bt->s[SIDE_R].items + (flag_planet_opponent ? 1 : 0); } } #endif for (int i = 0; i < num_weap; ++i) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[i].t]); if (b->wpn[i].numshots != 0) { if (w->is_bomb) { if (flag_planet_opponent) { int dmg; dmg = w->damagemax - bt->item[0/*planet*/].absorb; if (dmg > 0) { v += dmg * b->wpn[i].n * w->numfire; } if (w->is_bio) { dmg = w->damagemax - bt->antidote; if (dmg > 0) { v += dmg * b->wpn[i].n * w->numfire * 50; } } } } else { v += w->damagemax * b->wpn[i].n * w->numfire; } } } if (b->blackhole == 1) { v += 1000; } return v; } static int game_ai_battle_dmggive(struct battle_s *bt, int itemi1, int itemi2, int a2) { struct battle_item_s *b = &(bt->item[itemi1]); /*si*/struct battle_item_s *bd = &(bt->item[itemi2]); int v = 0, num_weap = (itemi1 == 0/*planet*/) ? 1 : 4, miss_chance_beam, miss_chance_missile, dist, damagediv = 1, dmg; if ((bd->stasisby > 0) && ((a2 == 0) || (a2 == 2))) { return 0; } miss_chance_beam = 50 - (b->complevel - bd->defense) * 10; miss_chance_missile = 50 - (b->complevel - bd->misdefense) * 10; if (bd->cloak == 1) { miss_chance_beam += 50; miss_chance_missile += 50; } SETRANGE(miss_chance_beam, 0, 95); if (bt->g->ai_id == GAME_AI_CLASSICPLUS) { SETMIN(miss_chance_missile, 95); } dist = util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy); for (int i = 0; i < num_weap; ++i) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[i].t]); int absorbdiv, range; if (bt->g->ai_id == GAME_AI_CLASSIC) { absorbdiv = game_battle_get_absorbdiv(bd, w, true); /* WASBUG checks target's oracle */ } else { absorbdiv = game_battle_get_absorbdiv(b, w, false); } if (itemi2 == 0/*planet*/) { if ((!w->is_bomb) && ((w->misstype > 0) || (w->damagemin != w->damagemax))) { damagediv = 2; } else { damagediv = 1; } } range = 0; if ((w->damagemin != w->damagemax) && (!w->is_bomb)) { range = b->extrarange; } else if (b->maxrange < 0) { range = b->maxrange; } if (itemi1 == 0/*planet*/) { range += 40; } if (1 && ((!w->is_bomb) || (itemi2 == 0/*planet*/)) && (b->wpn[i].numshots != 0) && (((w->range + range) >= dist) || (a2 > 0)) && ((b->wpn[i].numfire > 0) || (a2 > 0)) ) { if (w->damagemin == w->damagemax) { /*584de*/ int miss_chance; miss_chance = miss_chance_missile - w->extraacc * 10; SETRANGE(miss_chance, 0, 95); if (bt->g->ai_id == GAME_AI_CLASSIC) { miss_chance_missile = miss_chance; /* WASBUG MOO1 substracts for every missile weapon */ } dmg = ((100 - miss_chance) / 5) * (w->damagemax - bd->absorb / absorbdiv); dmg /= damagediv; dmg *= w->damagemul; dmg *= w->nummiss; } else { /*585ae*/ int miss_chance; miss_chance = miss_chance_beam; if (bd->absorb > w->damagemin) { miss_chance += ((100 - miss_chance) * (bd->absorb + 1 - w->damagemin)) / (w->damagemax + 1 - w->damagemin); if (bt->g->ai_id == GAME_AI_CLASSICPLUS) { SETMIN(miss_chance, 95); } } if (bt->g->ai_id == GAME_AI_CLASSIC) { miss_chance_beam = miss_chance; /* WASBUG MOO1 adds for every beam weapon */ } /*5861e*/ if ((w->damagemax / damagediv) > (bd->absorb / absorbdiv)) { int dmgmin, dmgmax; dmgmax = (w->damagemax / damagediv) - (bd->absorb / absorbdiv); if (bt->g->ai_id == GAME_AI_CLASSIC) { dmgmin = (w->damagemin > bd->absorb) ? (w->damagemin - bd->absorb) : 1; /* WASBUG {damage,absorb}div? */ } else { dmgmin = (w->damagemin / damagediv) - (bd->absorb / absorbdiv); SETMAX(dmgmin, 1); } dmg = (dmgmax + dmgmin) / 2; dmg = ((100 - miss_chance) * dmg) / 5; dmg *= w->damagemul; } else { dmg = 0; } } /*58729*/ if (w->is_bio && (b->wpn[i].numshots != 0)) { dmg = 500 * w->damagemax; } /*58785*/ if (dmg <= 0) { dmg = ((w->damagemax / damagediv) > (bd->absorb / absorbdiv)); } if (a2 > 0) { v += b->wpn[i].n * dmg * w->numfire; } else { /*5882d*/ v += b->wpn[i].n * dmg * b->wpn[i].numfire; } /*58873*/ } } if ((b->warpdis == 1) && ((dist <= 3) || (a2 > 0)) && (itemi2 != 0/*planet*/) && (bd->unman < bd->man)) { v += 100; } if ((b->blackhole == 1) && ((dist <= 1) || (a2 > 0))) { v += 1000; } if ((b->technull == 1) && ((dist <= 4) || (a2 > 0))) { v += 500; } if ((b->pulsar == 1) && (bt->special_button == 1) && ((dist <= 1) || (a2 > 0))) { dmg = (5 - bd->absorb) * bd->num; /* FIXME BUG? should be b->num ? */ if (dmg > 0) { v += dmg; } } if ((b->pulsar == 2) && (bt->special_button == 1) && ((dist <= 1) || (a2 > 0))) { dmg = (14 - bd->absorb) * bd->num; /* FIXME BUG? should be b->num ? */ if (dmg > 0) { v += dmg; } } if ((b->stream == 1) && ((dist <= 2) || (a2 > 0))) { dmg = ((bd->hp1 * ((b->num / 2) + 20)) / 100) * bd->num; if (dmg > 0) { v += dmg; } } if ((b->stream == 2) && ((dist <= 2) || (a2 > 0))) { dmg = ((bd->hp1 * (b->num + 40)) / 100) * bd->num; if (dmg > 0) { v += dmg; } } return v; } static int game_ai_battle_rival(struct battle_s *bt, int itemi, int a2) { /*di*/struct battle_item_s *b = &(bt->item[itemi]); int rival = -1, maxw = 0; for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if (((b->side + b2->side) == 1) && (b->num > 0)) { int dmgmissile, dmgmax, w, dmgmany, dmggive, repair; dmgmissile = game_ai_battle_incoming_missiles_dmg(bt, i); dmgmax = game_ai_battle_dmgmax(bt, i); dmggive = game_ai_battle_dmggive(bt, itemi, i, a2); repair = (b2->repair * b2->hp2) / 100; if (itemi == 0/*planet*/) { int dmgother; weapon_t t; t = b->wpn[0].t; b->wpn[0].t = b->wpn[1].t; b->wpn[1].t = t; dmgother = game_ai_battle_dmggive(bt, itemi, i, a2); if (dmgother > dmggive) { dmggive = dmgother; } else { t = b->wpn[0].t; b->wpn[0].t = b->wpn[1].t; b->wpn[1].t = t; } } /*58fc7*/ dmgmany = (b->num * dmggive - repair) / (b2->hp1 * 20); if (dmgmany > 0) { int vt; vt = b2->num - dmgmissile; /* FIMXE BUG? num - dmg? */ if (vt < dmgmany) { dmgmany = vt; SETMAX(dmgmany, 0); } /*59099*/ w = dmgmany * dmgmax * 20; } else { /*590c1*/ if ((dmgmissile > 0) && (dmggive > 0)) { w = 3; } else { /*590e1*/ w = ((dmggive - repair) * dmgmax) / b2->hp1; } /*59124*/ SETMAX(w, 0); if (dmggive > 0) { SETMAX(w, 3); } if ((w == 1) && (i != 0/*planet*/)) { w = 2; } } /*5917c*/ if ((dmgmax <= 0) && (dmggive > 0)) { w = (i == 0/*planet*/) ? 1 : 2; } if ((itemi == 0/*planet*/) && (w > 0)) { int dist; dist = util_math_dist_maxabs(b->sx, b->sy, b2->sx, b2->sy); w += (10 - dist) * 750; } /*59221*/ if ((i == 0/*planet*/) && (w == 1)) { for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { weapon_t wpnt = b->wpn[j].t; if ((tbl_shiptech_weap[wpnt].is_bio) && (b->wpn[j].numshots != 0)) { dmggive = tbl_shiptech_weap[wpnt].damagemax - bt->antidote; if (dmggive > 0) { w += dmggive * b->wpn[j].n * 100; } } } } /*59306*/ if (w > maxw) { rival = i; maxw = w; bt->bases_using_mirv = (tbl_shiptech_weap[bt->item[0/*planet*/].wpn[0].t].nummiss > 1); } } } /*59354*/ if (itemi == 0/*planet*/) { weapon_t t = b->wpn[0].t; bool is_mirv = (tbl_shiptech_weap[t].nummiss > 1); if (bt->bases_using_mirv != is_mirv) { b->wpn[0].t = b->wpn[1].t; b->wpn[1].t = t; } } return rival; } static bool game_battle_missile_none_fired_by(const struct battle_s *bt, int itemi) { for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if (m->source == itemi) { return false; } } return true; } static int game_battle_stasis_target(struct battle_s *bt) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); int target_i = -1; bool flag_have_unstasis = false; { int n = 0, itembase = (b->side == SIDE_R) ? 1 : (bt->s[SIDE_L].items + 1), itemnum = bt->s[b->side ^ 1].items; for (int i = 0; i < itemnum; ++i) { if (bt->item[itembase + i].stasisby > 0) { ++n; } } if ((itemnum - 2) >= n) { flag_have_unstasis = true; } } if (flag_have_unstasis) { int vmax = 0; b->stasis = 1; for (int i = 1; i <= bt->items_num; ++i) { struct battle_item_s *bd = &(bt->item[i]); if ((b->side != bd->side) && (bd->stasisby == 0) && (bd->cloak != 1)) { int v; v = game_ai_battle_dmgmax(bt, i) * bd->num; if (v > vmax) { vmax = v; target_i = i; } } } } else { b->stasis = 2; } return target_i; } static int game_battle_ai_missile_evade(const struct battle_s *bt) { int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); int evade = 0; if (b->unman == b->man) { return 0; } for (int i = 0; (i < bt->num_missile) && (evade <= 1); ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if (m->target == itemi) { int roomx, dangerdist, movex, dist, sx; sx = m->x / 32; if (b->subspace == 1) { roomx = 9 - sx; SETMAX(roomx, sx); } else { sx -= b->sx; if (sx < 0) { roomx = 9 - b->sx; } else /*if (sx > 0)*/ { /* WASBUG this was if > 0 and the == 0 case was unhandled */ roomx = b->sx; } } movex = (b->man - b->unman) * m->fuel; if ((movex > roomx) || (b->subspace == 1)) { movex = roomx; } dist = util_math_dist_fast(b->sx * 32 + 16, b->sy * 24 + 12, m->x, m->y); dangerdist = tbl_shiptech_weap[m->wpnt].dtbl[0] * m->fuel + 13; if (dist > dangerdist) { evade = 1; } dist += movex * 32 - 18; if ((rnd_1_n(3, &bt->g->seed) < bt->g->difficulty) && (dist > dangerdist)) { evade = 2; } } } return evade; } /* * Tries to approximate by how much enemy ship can increase distance in 2 turns. */ static void get_possible_distance_increase(struct battle_s *bt, int target_i) { struct battle_item_s *b = &(bt->item[bt->cur_item]); const struct battle_item_s *bd = &(bt->item[target_i]); int si, t; if (b->sx < bd->sx) { si = BATTLE_AREA_W - bd->sx - 1; } else { si = bd->sx; } t = (bd->man - bd->unman) * 2; b->maxrange = -(MIN(si, t)); } static int game_battle_ai_best_range(struct battle_s *bt, int target_i) { int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); const struct battle_item_s *bd = &(bt->item[target_i]); int bestrange = 1, damagediv = 1, weight1 = 0; if (target_i == 0/*planet*/) { return 1; } for (int i = 1; i < 10; ++i) { int weight; weight = 0; if ((b->blackhole > 0) && (i <= 1)) { weight += 2000; } if ((b->stasis == 1) && (i <= 1)) { weight += 2000; } if ((b->pulsar == 1) && (i <= 1)) { int v; v = (6 - bd->absorb) * bd->num; if (v > 0) { weight += v; } } if ((b->pulsar == 2) && (i <= 1)) { int v; v = (16 - bd->absorb) * bd->num; if (v > 0) { weight += v; } } if ((b->stream == 1) && (i <= 2)) { int v; v = ((bd->hp1 * (b->num + 20) + 99) / 100) * bd->num; if (v > 0) { weight += v; } } if ((b->stream == 2) && (i <= 2)) { int v; v = ((bd->hp1 * (b->num + 40) + 99) / 100) * bd->num; if (v > 0) { weight += v; } } for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[j].t]); int absorbdiv, range; if (bt->g->ai_id == GAME_AI_CLASSIC) { absorbdiv = game_battle_get_absorbdiv(bd, w, true); /* WASBUG checks target's oracle */ } else { if (w->damagemin != w->damagemax) { absorbdiv = game_battle_get_absorbdiv(b, w, false); } else { absorbdiv = 1; } } if (target_i == 0/*planet*/) { if ((!w->is_bomb) && ((w->misstype > 0) || (w->damagemin != w->damagemax))) { damagediv = 2; } else { damagediv = 1; /* WASBUG there was no else, so the 2 stuck */ } } range = (itemi == 0/*planet*/) ? 12 : 0; if ((w->damagemax != w->damagemin) && (!w->is_bomb)) { range = b->extrarange; } else if (!w->is_bomb) { /* if missile (or no weapon but it doesn't matter) */ get_possible_distance_increase(bt, target_i); range = b->maxrange; } if (((w->range + range) >= i) && (b->wpn[j].numshots != 0) && ((!w->damagefade) || (i == 1))) { int dmg; dmg = (w->damagemax / damagediv - bd->absorb / absorbdiv) * w->damagemul * b->wpn[j].n * w->numfire; if (w->is_bio) { dmg = w->damagemax * 100; } SETMAX(dmg, 0); weight += dmg; } } if (i == 1) { weight1 = weight; } if (weight == 0) { break; } if (b->cloak == 1) { if (weight1 > weight) { break; } else { bestrange = i; } } else { if (((weight1 * 2) / (weight * 3)) <= 1) { bestrange = i; } else { break; } } } return bestrange; } /* * Evaluate position (sx, sy) in case ship has pulsar. * If position is next to friendly ship that can't absorb pulsar damage devaluate it. * If position is next to enemy ship that can't absorb pulsar damage add value to it. */ static int eval_pos_for_pulsar_use(struct battle_s *bt, int sx, int sy) { struct battle_item_s *b = &(bt->item[bt->cur_item]); int ndiv, rbase, weight = 0, dmg; if (b->pulsar == 1) { ndiv = 2; rbase = 5; } else { ndiv = 1; rbase = 10; } dmg = rbase + b->num / ndiv; for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *bd = &(bt->item[i]); if (util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy) == 1) { if (b->side == bd->side) { if (bd->absorb < dmg) { weight -= 4; } } else { if (bd->absorb < dmg) { weight += 3; } } } } return weight; } static int game_battle_ai_target1_sub3(struct battle_s *bt, int sx, int sy, int target_i, int bestrange) { int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); const struct battle_item_s *bd = &(bt->item[target_i]); int si = 0, dist, len, tblx[20], tbly[20]; dist = util_math_dist_maxabs(sx, sy, bd->sx, bd->sy); len = util_math_line_plot(sx, sy, bd->sx, bd->sy, tblx, tbly); if (dist == bestrange) { si = 10; } else { si -= dist * 4; } if ((b->pulsar == 1) || (b->pulsar == 2)) { si += eval_pos_for_pulsar_use(bt, sx, sy); } if (game_battle_area_check_line_ok(bt, tblx, tbly, len) < 1) { si -= 2; } if (bt->area[sy][sx] == (itemi + 10)) { si += (dist == bestrange) ? 1 : -1; } return si; } static void game_battle_ai_target1_sub4(struct battle_s *bt) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); int dist = 0, mindist, n = 0, oppdist; uint8_t tblxy[10]; if (b->unman == b->man) { return; } if (b->subspace == 1) { oppdist = 0; for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { if (bt->area[sy][sx] == 1) { for (int i = 0; i <= bt->items_num; ++i) { const struct battle_item_s *bd = &(bt->item[i]); mindist = 10; /* FIXME BUG this results in always setting to last enemy dist */ if ((b->side + bd->side) == 1) { dist = util_math_dist_maxabs(sx, sy, bd->sx, bd->sy); SETMIN(mindist, dist); } } if (oppdist <= mindist) { if (oppdist < dist) { n = 0; } oppdist = dist; tblxy[n++] = BATTLE_XY_SET(sx, sy); SETMIN(n, TBLLEN(tblxy) - 1); /* WASBUG? not limited in MOO1 */ } } } } /*59d70*/ game_battle_item_move(bt, itemi, BATTLE_XY_GET_X(tblxy[0]), BATTLE_XY_GET_Y(tblxy[0])); } else { /*59d85*/ oppdist = 10; for (int i = 0; i <= bt->items_num; ++i) { const struct battle_item_s *bd = &(bt->item[i]); if ((b->side + bd->side) == 1) { dist = util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy); SETMIN(oppdist, dist); } } while (b->actman > 0) { n = 0; for (int sx = b->sx - 1; sx <= (b->sx + 1); ++sx) { if ((sx < 0) || (sx >= BATTLE_AREA_W)) { continue; } for (int sy = b->sy - 1; sy < (b->sy + 1); ++sy) { if ((sy < 0) || (sy >= BATTLE_AREA_H)) { continue; } if (bt->area[sy][sx] == 1) { mindist = 10; for (int i = 0; i <= bt->items_num; ++i) { const struct battle_item_s *bd = &(bt->item[i]); if ((b->side + bd->side) == 1) { dist = util_math_dist_maxabs(sx, sy, bd->sx, bd->sy); SETMIN(mindist, dist); } } if (mindist > oppdist) { oppdist = mindist; n = 1; tblxy[0] = BATTLE_XY_SET(sx, sy); } } } } if (n > 0) { game_battle_item_move(bt, itemi, BATTLE_XY_GET_X(tblxy[0]), BATTLE_XY_GET_Y(tblxy[0])); } else { b->actman = 0; } } } } static void game_battle_ai_target1_sub5(struct battle_s *bt) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); int dist = 0, mindist = 10, missdist = 0; uint8_t xy = BATTLE_XY_INVALID; if (b->unman == b->man) { return; } if (b->subspace == 1) { for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { if (bt->area[sy][sx] == 1) { for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if ((m->target == itemi) && (m->fuel < 8)) { mindist = 10; /* FIXME BUG this results in always setting to last missile dist */ dist = util_math_dist_maxabs(sx, sy, m->x / 32, m->y / 24); SETMIN(mindist, dist); } } if (missdist < mindist) { xy = BATTLE_XY_SET(sx, sy); missdist = dist; /* FIXME BUG? should be mindist ? */ } } } } if (xy == BATTLE_XY_INVALID) { log_warning("BUG: subspace destination not found\n"); xy = BATTLE_XY_SET(b->sx, b->sy); } game_battle_item_move(bt, itemi, BATTLE_XY_GET_X(xy), BATTLE_XY_GET_Y(xy)); } else { /*5a0d8*/ while (b->actman > 0) { missdist = 10; for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if ((m->target == itemi) && (m->fuel < 8)) { dist = util_math_dist_maxabs(b->sx, b->sy, m->x / 32, m->y / 24); SETMIN(missdist, dist); } } xy = BATTLE_XY_INVALID; for (int sx = b->sx - 1; sx <= (b->sx + 1); ++sx) { if ((sx < 0) || (sx >= BATTLE_AREA_W)) { continue; } for (int sy = b->sy - 1; sy < (b->sy + 1); ++sy) { if ((sy < 0) || (sy >= BATTLE_AREA_H)) { continue; } if ((bt->area[sy][sx] == 1) && ((b->sx != sx) || (b->sy != sy))) { mindist = 10; for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if ((m->target == itemi) && (m->fuel < 8)) { dist = util_math_dist_maxabs(sx, sy, m->x / 32, m->y / 24); SETMIN(mindist, dist); } } if (mindist > missdist) { missdist = mindist; xy = BATTLE_XY_SET(sx, sy); } } } } if (xy != BATTLE_XY_INVALID) { game_battle_item_move(bt, itemi, BATTLE_XY_GET_X(xy), BATTLE_XY_GET_Y(xy)); } else { b->actman = 0; } } } } static int game_battle_ai_target1(struct battle_s *bt, int target_i) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); int bestrange; bestrange = game_battle_ai_best_range(bt, target_i); if ((b->actman > 0) || (b->subspace == 1)) { if ((target_i != -1) && (game_battle_ai_missile_evade(bt) == 0)) { int vmax = -999, n = 1, i; uint8_t tblxy[20]; for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { if ((bt->area[sy][sx] == 1) || ((b->sx == sx) && (b->sy == sy))) { int v; /*5a3dc*/ v = game_battle_ai_target1_sub3(bt, sx, sy, target_i, bestrange); if (v > vmax) { n = 1; tblxy[0] = BATTLE_XY_SET(sx, sy); vmax = v; } else if ((v == vmax) && (n < TBLLEN(tblxy))) { tblxy[n++] = BATTLE_XY_SET(sx, sy); } } } } /*5a449*/ i = (n < 2) ? 0 : rnd_0_nm1(n, &bt->g->seed); if (itemi != 0/*planet*/) { game_battle_item_move(bt, itemi, BATTLE_XY_GET_X(tblxy[i]), BATTLE_XY_GET_Y(tblxy[i])); } } else if (target_i == -1) { /*5a494*/ game_battle_ai_target1_sub4(bt); } else { /*5a4a0*/ game_battle_ai_target1_sub5(bt); } } return bestrange; } static void game_ai_classic_battle_ai_turn(struct battle_s *bt) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); /*5a581*/ int /*si*/target_i = 0; /* FIXME WASBUG used uninitialized later ; proper value ? */ int v4; game_battle_area_setup(bt); /* FIXME already done by caller */ if (1 && (b->side == SIDE_R) && (game_ai_battle_rival(bt, itemi, 1) == -1) && game_battle_missile_none_fired_by(bt, itemi) ) { ++b->retreat; } /*5a5cb*/ if ((b->man - b->unman) == 0) { b->retreat = 0; } /*5a604*/ if (b->stasis > 0) { target_i = game_battle_stasis_target(bt); if (target_i != -1) { game_battle_ai_target1(bt, target_i); game_battle_area_setup(bt); if (!bt->flag_cur_item_destroyed) { const struct battle_item_s *bd = &(bt->item[target_i]); if (util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy) <= 1) { get_possible_distance_increase(bt, target_i); game_battle_attack(bt, itemi, target_i, false); } } } } /*5a69e*/ game_battle_area_setup(bt); if (1 && (game_ai_battle_incoming_missiles_dmg(bt, itemi) > 0) && (target_i != -1) /* BUG used uninitialized if b->stasis == 0 */ && ((target_i = game_ai_battle_rival(bt, itemi, 0)) > -1) ) { if ((b->pulsar == 1) || (b->pulsar == 2)) { if (eval_pos_for_pulsar_use(bt, b->sx, b->sy) < 0) { bt->special_button = 0; } } /*5a72a*/ get_possible_distance_increase(bt, target_i); game_battle_attack(bt, itemi, target_i, false); } /*5a740*/ if (bt->special_button == -1) { bt->special_button = 1; } game_battle_area_setup(bt); if (b->retreat > 0) { target_i = -1; } else { target_i = game_ai_battle_rival(bt, itemi, 2); } if (!bt->flag_cur_item_destroyed) { v4 = game_battle_ai_target1(bt, target_i); } if (!bt->flag_cur_item_destroyed) { int loops; if ((b->pulsar == 1) || (b->pulsar == 2)) { if (eval_pos_for_pulsar_use(bt, b->sx, b->sy) < 0) { bt->special_button = 0; } } target_i = game_ai_battle_rival(bt, itemi, 0); if ((target_i == -1) && (itemi == 0/*planet*/) && (b->num > 0)) { int ii = (b->side == SIDE_R) ? 1 : (bt->s[SIDE_L].items + 1); if (bt->item[ii].side != b->side) { game_battle_attack(bt, itemi, ii, false); } } /*5a866*/ loops = 0; while (target_i != -1) { target_i = game_ai_battle_rival(bt, itemi, 0); ++loops; if ((b->cloak == 1) && (target_i != -1)) { /* WASBUG no test for -1 */ const struct battle_item_s *bd; bd = &(bt->item[target_i]); if (util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy) != v4) { /* WASBUG bd at index -1 */ target_i = -1; } } if (b->retreat > 0) { target_i = -1; } /*5a8e1*/ if (target_i > -1) { get_possible_distance_increase(bt, target_i); game_battle_attack(bt, itemi, target_i, false); } if (loops > 10) { /* MOO1 does not need this but it does have the loop counter */ LOG_DEBUG((3, "%s: BUG: break from loop, item:%i target_i:%i\n", __func__, itemi, target_i)); break; } } /*5a91b*/ b->selected = 0; bt->turn_done = true; } /*5a934*/ } /* -------------------------------------------------------------------------- */ static bool game_ai_classic_battle_ai_retreat(struct battle_s *bt) { int missile[BATTLE_ITEM_MAX]; uint32_t repair[BATTLE_ITEM_MAX]; int64_t dmg[2] = { 0, 0 }; uint32_t hp[2] = { 0, 0 }; for (int i = 0; i < BATTLE_ITEM_MAX; ++i) { const struct battle_item_s *b = &(bt->item[i]); missile[i] = 0; repair[i] = (b->hp1 * b->repair) / 5; } for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); if (m->target != MISSILE_TARGET_NONE) { int s; s = bt->item[m->target].side; missile[m->source] += 2; dmg[s] += game_ai_battle_missile_dmg(bt, i) / (missile[m->source] + 1); dmg[s] -= repair[m->target]; repair[m->target] = 0; } } for (int i = 1; i <= bt->items_num; ++i) { int j, s; s = (i <= bt->s[SIDE_L].items) ? SIDE_R : SIDE_L; j = game_ai_battle_rival(bt, i, 1); if (j >= 0) { const struct battle_item_s *b; b = &(bt->item[i]); hp[s ^ 1] += b->hp1 * b->num; dmg[s] += game_ai_battle_dmggive(bt, i, j, 1) * b->num; dmg[s] -= repair[j]; repair[j] = 0; } else { ++hp[s ^ 1]; } } if (bt->item[0/*planet*/].num > 0) { const struct battle_item_s *b = &(bt->item[0/*planet*/]); int j, s = (b->side == SIDE_L) ? SIDE_R : SIDE_L; hp[s ^ 1] += (b->hp1 * b->num * 7) / 10; j = game_ai_battle_rival(bt, 0/*planet*/, 1); if (j > 0) { dmg[s] += (game_ai_battle_dmggive(bt, 0/*planet*/, j, 1) * b->num * 7) / 10; dmg[s] -= (repair[j] * 7) / 10; repair[j] = 0; } } if (hp[SIDE_L] == 0) { return false; } if (hp[SIDE_R] == 0) { return false; } if (dmg[SIDE_L] == 0) { return true; } { int v; int64_t w[2]; v = (5 - bt->g->difficulty) * 5 + 5; switch (bt->item[0/*planet*/].side) { case SIDE_L: v += 10; break; case SIDE_R: v += 20; break; default: break; } v += rnd_1_n(15, &bt->g->seed); if (bt->g->ai_id == GAME_AI_CLASSICPLUS) { w[SIDE_R] = (dmg[SIDE_R] * 100) / hp[SIDE_R]; w[SIDE_L] = (dmg[SIDE_L] * 100 * v) / hp[SIDE_L]; } else { /* WASBUG MOO1 uses 32b vars which can overflow on extreme cases */ w[SIDE_R] = (int32_t)((((int32_t)dmg[SIDE_R]) * 100) / hp[SIDE_R]); w[SIDE_L] = (int32_t)((((int32_t)dmg[SIDE_L]) * 100 * v) / hp[SIDE_L]); } if (w[SIDE_R] > w[SIDE_L]) { return true; } } return false; } /* -------------------------------------------------------------------------- */ static uint8_t game_ai_classic_tech_next(struct game_s *g, player_id_t player, tech_field_t field, uint8_t *tbl, int num) { uint8_t tech; if (rnd_1_n(6, &g->seed) < g->difficulty) { tech = tbl[num - 1]; } else { tech = tbl[rnd_0_nm1(num, &g->seed)]; } return tech; } /* -------------------------------------------------------------------------- */ static bool game_ai_classic_bomb(struct game_s *g, player_id_t player, uint8_t planet, int pop_inbound) { bool flag_do_bomb; const planet_t *p = &(g->planet[planet]); if (g->eto[player].race == RACE_BULRATHI) { if (g->ai_id == GAME_AI_CLASSICPLUS) { /* OSG states 2.15:1 average kill:death ratio for +20 (+Bulrathi -Defense) advantage */ pop_inbound = (pop_inbound * 215) / 100; } else { pop_inbound += pop_inbound / 5; } } flag_do_bomb = (p->pop > pop_inbound); if ((IS_HUMAN(g, p->owner)) && (g->evn.ceasefire[p->owner][player] > 0)) { flag_do_bomb = false; } return flag_do_bomb; } /* -------------------------------------------------------------------------- */ static void game_ai_classic_ground(struct game_s *g, player_id_t def, player_id_t att, uint8_t planet, int pop_killed, bool owner_changed) { if (IS_HUMAN(g, def)) { return; } if (IS_AI(g, att)) { /*e996*/ pop_killed = 1; /* FIXME BUG? AI-AI ground diplo always sees 1 pop killed */ /*e9c4*/ game_diplo_act(g, -((rnd_1_n(4, &g->seed) + 4) * pop_killed), att, def, 0xa, planet, 0); } else if (owner_changed && IS_HUMAN(g, att)) { if (g->eto[att].treaty[def] < TREATY_WAR) { game_diplo_act(g, -50 - rnd_1_n(50, &g->seed), att, def, 0xd, planet, 0); game_diplo_start_war_swap(g, def, att); } else { /*e93f*/ game_diplo_act(g, -50 - rnd_1_n(50, &g->seed), att, def, 0xa, planet, 0); } } else { /*e969*/ game_diplo_act(g, -((rnd_1_n(5, &g->seed) + 5) * pop_killed), att, def, 0xa, planet, 0); } } /* -------------------------------------------------------------------------- */ static void game_ai_classic_add_reserve(struct game_s *g, planet_t *p) { empiretechorbit_t *e = &(g->eto[p->owner]); uint32_t v = e->reserve_bc / 5; e->reserve_bc -= v; p->reserve += v; } static void game_ai_classic_crank_tech(struct game_s *g, uint8_t planet) { planet_t *p = &(g->planet[planet]); int v; if ((p->owner == PLAYER_NONE) || IS_HUMAN(g, p->owner)) { return; } v = p->slider[PLANET_SLIDER_SHIP]; v += p->slider[PLANET_SLIDER_IND]; v += p->slider[PLANET_SLIDER_DEF]; p->slider[PLANET_SLIDER_TECH] += v; p->slider[PLANET_SLIDER_SHIP] = 0; p->slider[PLANET_SLIDER_IND] = 0; p->slider[PLANET_SLIDER_DEF] = 0; game_ai_classic_add_reserve(g, p); } static void game_ai_classic_crank_ship(struct game_s *g, uint8_t planet) { planet_t *p = &(g->planet[planet]); int v; if ((p->owner == PLAYER_NONE) || IS_HUMAN(g, p->owner)) { return; } v = p->slider[PLANET_SLIDER_TECH]; v += p->slider[PLANET_SLIDER_IND]; v += p->slider[PLANET_SLIDER_DEF]; p->slider[PLANET_SLIDER_SHIP] += v; p->slider[PLANET_SLIDER_TECH] = 0; p->slider[PLANET_SLIDER_IND] = 0; p->slider[PLANET_SLIDER_DEF] = 0; game_ai_classic_add_reserve(g, p); } /* -------------------------------------------------------------------------- */ static int game_ai_classic_vote_w(struct game_s *g, player_id_t player, player_id_t cand) { int v = 0; if (g->planet[g->evn.planet_orion_i].owner == cand) { v += 20; } if (g->eto[cand].race == RACE_HUMAN) { v += 20; } if (g->evn.voted[player] == cand) { v += 40; } return v; } static bool game_ai_classic_vote_like(struct game_s *g, player_id_t player, player_id_t cand) { int v; v = g->eto[player].relation1[cand] / 4; v += game_ai_classic_vote_w(g, player, cand); return (rnd_1_n(100, &g->seed) < v); } static bool game_ai_classic_vote_hate(struct game_s *g, player_id_t player, player_id_t c1, player_id_t c2) { int v; v = -g->eto[player].relation1[c1] / 4; v += game_ai_classic_vote_w(g, player, c2); return (rnd_1_n(100, &g->seed) < v); } static int game_ai_classic_vote(struct election_s *el, player_id_t player) { struct game_s *g = el->g; empiretechorbit_t *e = &(g->eto[player]); player_id_t c1 = el->candidate[0]; player_id_t c2 = el->candidate[1]; if (player == c1) { return 1; } if (player == c2) { return 2; } if (e->treaty[c1] == TREATY_ALLIANCE) { return 1; } if (e->treaty[c2] == TREATY_ALLIANCE) { return 2; } if (e->treaty[c1] == TREATY_WAR) { return 2; } if (e->treaty[c2] == TREATY_WAR) { return 1; } if (e->relation1[c1] >= 0) { if (game_ai_classic_vote_like(g, player, c1)) { return 1; } } else { if (game_ai_classic_vote_hate(g, player, c1, c2)) { return 2; } } if (e->relation1[c2] >= 0) { if (game_ai_classic_vote_like(g, player, c2)) { return 2; } } else { int v; v = -g->eto[player].relation1[c2] / 5; /* FIXME BUG? the other case uses / 4 */ v += game_ai_classic_vote_w(g, player, c1); if (rnd_1_n(100, &g->seed) < v) { return 1; } } return 0; } /* -------------------------------------------------------------------------- */ static int game_ai_classic_diplo_wage_war_fleet_w(struct game_s *g, player_id_t p1, player_id_t p2) { int ratio, fleetw[2]; for (int i = 0; i < 2; ++i) { player_id_t player; empiretechorbit_t *e; shipresearch_t *srd; player = (i == 0) ? p1 : p2; e = &(g->eto[player]); srd = &(g->srd[player]); fleetw[i] = 0; for (int j = 0; j < e->shipdesigns_num; ++j) { uint32_t v; v = srd->shipcount[j] * game_num_tbl_hull_w[srd->design[j].hull]; ADDSATT(fleetw[i], v, 3250000); } SETMAX(fleetw[i], 1); } ratio = ((fleetw[0] - fleetw[1]) * 100) / fleetw[1]; SETRANGE(ratio, -300, 300); if (ratio == 0) { return 0; } else if (ratio < 0) { return -rnd_1_n(-ratio, &g->seed); } else { return rnd_1_n(ratio, &g->seed); } } static void game_ai_classic_diplo_wage_war_do(struct game_s *g, player_id_t p1, player_id_t p2) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); if ((e1->treaty[p2] == TREATY_ALLIANCE) || (e1->treaty[p2] == TREATY_NONAGGRESSION)) { if (g->difficulty < DIFFICULTY_AVERAGE) { return; } if (0 || ((e1->treaty[p2] == TREATY_ALLIANCE) && ((!rnd_0_nm1(4, &g->seed)) || ((!rnd_0_nm1(2, &g->seed)) && (e2->trait2 == TRAIT2_EXPANSIONIST)))) || ((e1->treaty[p2] == TREATY_NONAGGRESSION) && ((!rnd_0_nm1(2, &g->seed)) || (e2->trait2 == TRAIT2_EXPANSIONIST))) ) { game_diplo_act(g, -10000, p1, p2, 32, 0, 0); game_diplo_break_treaty(g, p2, p1); if (e1->relation1[p2] > 30) { e1->relation1[p2] = 30; e2->relation1[p1] = 30; } } } else if (g->evn.ceasefire[p1][p2] <= 0) { game_diplo_act(g, -10000, p1, p2, (e1->relation1[p2] < 0) ? 13 : 60, 0, 0); game_diplo_start_war(g, p2, p1); } } static int game_ai_classic_diplo_wage_war_prod_w(struct game_s *g, player_id_t p1, player_id_t p2) { int ratio, prod[2]; prod[0] = g->eto[p1].total_production_bc; prod[1] = g->eto[p2].total_production_bc; SETRANGE(prod[1], 1, 3250000); /* FIXME BUG? only p2 prod limited */ ratio = ((prod[0] - prod[1]) * 100) / prod[1]; SETRANGE(ratio, -300, 300); if (ratio == 0) { return 0; } else if (ratio < 0) { return -rnd_1_n(-ratio, &g->seed); } else { return rnd_1_n(ratio, &g->seed); } } static void game_ai_classic_diplo_wage_war(struct game_s *g, player_id_t p1, player_id_t p2) { if (g->end != GAME_END_NONE) { for (p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); for (p2 = PLAYER_0; p2 < g->players; ++p2) { if ((p1 != p2) && (BOOLVEC_IS1(g->refuse, p1) == BOOLVEC_IS1(g->refuse, p2))) { e1->treaty[p2] = TREATY_ALLIANCE; } } } } else { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); if ((e1->treaty[p2] >= TREATY_WAR) || BOOLVEC_IS0(e1->contact, p2) || (!IS_ALIVE(g, p1))) { return; } if (1 && (e2->trait1 == TRAIT1_ERRATIC) && (rnd_1_n(300, &g->seed) <= g->difficulty) && (IS_AI(g, p1) || (g->evn.ceasefire[p1][p2] < 1)) ) { e1->diplo_type[p2] = 61; e1->diplo_val[p2] = 2000; game_diplo_start_war(g, p2, p1); } else { if (1 && (!rnd_0_nm1(20, &g->seed)) && ((e2->trait2 == TRAIT2_MILITARIST) || (e2->trait2 == TRAIT2_EXPANSIONIST)) && (e2->trait1 != TRAIT1_HONORABLE) && (IS_AI(g, p1) || (g->evn.ceasefire[p1][p2] < 1)) ) { int v; v = game_ai_classic_diplo_wage_war_fleet_w(g, p1, p2); v = e1->relation1[p2] - v + game_diplo_tbl_reldiff[e2->trait1] + e1->trust[p2]; if (v < -150) { game_ai_classic_diplo_wage_war_do(g, p1, p2); } } /*1679f*/ if (1 && (!rnd_0_nm1(20, &g->seed)) && (IS_AI(g, p1) || (g->evn.ceasefire[p1][p2] < 1)) ) { int v; v = game_ai_classic_diplo_wage_war_prod_w(g, p1, p2); v = e1->relation1[p2] - v + game_diplo_tbl_reldiff[e2->trait1] + e1->trust[p2]; if (v < -150) { game_ai_classic_diplo_wage_war_do(g, p1, p2); } } } /*16829*/ for (player_id_t p3 = PLAYER_0; p3 < g->players; ++p3) { if (IS_HUMAN(g, p3)) { continue; } for (player_id_t p4 = PLAYER_0; p4 < g->players; ++p4) { empiretechorbit_t *e4 = &(g->eto[p4]); if (IS_AI(g, p4)) { continue; } if (1 && (e4->treaty[p3] == TREATY_WAR) && (e2->treaty[p3] == TREATY_ALLIANCE) && (g->evn.ceasefire[p4][p2] <= 0) && (!rnd_0_nm1(10, &g->seed)) && (e2->treaty[p1] == TREATY_ALLIANCE) ) { game_ai_classic_diplo_wage_war_do(g, p1, p2); } } } if (IS_HUMAN(g, p1) && (g->difficulty >= DIFFICULTY_AVERAGE)) { int num = 0; for (player_id_t p3 = PLAYER_0; p3 < g->players; ++p3) { if (e1->treaty[p3] >= TREATY_WAR) { ++num; } } if (num < g->difficulty) { /* MOO1 does unused buggy count of planets ; overwrites local variable at tbl[-1] (which is also unused) */ int v = e1->relation1[p2]; if (v < -30) { v = (-v) / 10; if (rnd_1_n(10, &g->seed) <= v) { game_ai_classic_diplo_wage_war_do(g, p1, p2); } } } } } } static void game_ai_classic_turn_diplo_p1_sub1(struct game_s *g) { for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); if (IS_HUMAN(g, p1)) { continue; } for (player_id_t p2 = p1 + 1; p2 < g->players; ++p2) { empiretechorbit_t *e2 = &(g->eto[p2]); if (IS_HUMAN(g, p2)) { continue; } for (player_id_t p3 = p1 + 1; p2 < g->players; ++p2) { /* FIXME BUG? p2 + 1 ; BUG p3 < ; BUG ++p3 */ if (IS_HUMAN(g, p3)) { continue; } if ((e2->treaty[p3] == TREATY_WAR) && (e1->treaty[p2] == TREATY_ALLIANCE) && (e1->treaty[p3] == TREATY_ALLIANCE)) { game_diplo_break_treaty(g, p1, p2); game_diplo_break_treaty(g, p1, p3); } } } } } static int game_ai_classic_turn_diplo_p1_get_ai_trade_tech(struct game_s *g, player_id_t p1, player_id_t p2, tech_field_t *fieldptr, uint8_t *techptr) { struct spy_esp_s s; tech_field_t field = 0; uint8_t tech = 0; int num, r; s.target = p1; s.spy = p2; r = rnd_1_n(3, &g->seed); num = game_spy_esp_sub2(g, &s, r); /* WASBUG MOO1 does field = s.tbl_field[0] and tech = s.tbl_tech2[0] but neither is set by game_spy_esp_sub2. MOO1 uses global variables for the tables; the values are from some previous spy call (possibly ground combat tech steal). */ if (num > 0) { int i; i = (g->year ^ r) % num; /* "random" value without advancing the rng */ for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { int n; n = s.tbl_num[f]; if (i < n) { field = f; tech = s.tbl_techi[f][i]; break; } i -= n; } } *fieldptr = field; *techptr = tech; return num; } static void game_ai_classic_turn_diplo_p1(struct game_s *g) { for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); if (IS_HUMAN(g, p1)) { continue; } for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { empiretechorbit_t *e2 = &(g->eto[p2]); if ((p1 == p2) || IS_HUMAN(g, p2)) { continue; } if ((!(rnd_0_nm1(15 - g->difficulty * 2, &g->seed))) && BOOLVEC_IS1(e1->contact, p2)) { int v; v = e1->trust[p2] + e1->relation1[p2] + game_diplo_tbl_reldiff[e2->trait1] + rnd_1_n(100, &g->seed); if (e1->treaty[p2] == TREATY_NONAGGRESSION) { v += 10; } if (e1->treaty[p2] == TREATY_ALLIANCE) { v += 20; } if (e1->trade_bc[p2] != 0) { v += 10; } if (((v + e1->mood_treaty[p2]) > 150) && (e1->treaty[p2] != TREATY_ALLIANCE)) { game_diplo_set_treaty(g, p1, p2, TREATY_ALLIANCE); } else if (((v + e1->mood_treaty[p2]) > 150) && (e1->treaty[p2] != TREATY_NONAGGRESSION)) { /* BUG ignores Alliance, results in NAP/Alliance oscillation */ game_diplo_set_treaty(g, p1, p2, TREATY_NONAGGRESSION); } else { if ((e1->mood_tech[p2] + 80) < v) { tech_field_t field[2]; int num[2]; uint8_t tech[2]; num[0] = game_ai_classic_turn_diplo_p1_get_ai_trade_tech(g, p1, p2, &field[0], &tech[0]); num[1] = game_ai_classic_turn_diplo_p1_get_ai_trade_tech(g, p2, p1, &field[1], &tech[1]); if ((num[0] > 0) && (num[1] > 0)) { game_tech_get_new(g, p2, field[0], tech[0], TECHSOURCE_TRADE, 0, PLAYER_NONE, false); game_tech_get_new(g, p1, field[1], tech[1], TECHSOURCE_TRADE, 0, PLAYER_NONE, false); } } else if (v > 70) { int v1, v2; v1 = e1->total_production_bc / 4; v2 = e2->total_production_bc / 4; SETMIN(v1, v2); SETMIN(v1, 32000); game_diplo_set_trade(g, p1, p2, v1); } } if (!(rnd_0_nm1(20, &g->seed))) { game_diplo_act(g, rnd_1_n(5, &g->seed), p1, p2, 1, 0, 0); } /* WASBUG MOO1 uses the last audience message variant index (diplo_msg_subtype, -1..13) in place of v. This is weird, nondeterministic (in MOO1) and unworkable for multiplayer. Whether v is what was intended is unknown, but it makes a whole lot more sense. */ if (g->ai_id == GAME_AI_CLASSIC) { v = g->evn.diplo_msg_subtype; } if ((e1->treaty[p2] == TREATY_WAR) && ((v + e1->mood_peace[p2]) > 100)) { game_diplo_stop_war(g, p1, p2); } game_diplo_annoy(g, p1, p2, 3); game_ai_classic_turn_diplo_p1_sub1(g); game_ai_classic_diplo_wage_war(g, p1, p2); } } } for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); if (IS_HUMAN(g, p1)) { continue; } for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { if ((p1 == p2) || IS_HUMAN(g, p2)) { continue; } if (e1->treaty[p2] == TREATY_ALLIANCE) { for (player_id_t p3 = PLAYER_0; p3 < g->players; ++p3) { empiretechorbit_t *e3 = &(g->eto[p3]); if ((p1 != p3) && (p2 != p3) && IS_AI(g, p3) && (e3->treaty[p1] == TREATY_WAR) && (e3->treaty[p2] != TREATY_WAR)) { game_diplo_start_war(g, p2, p3); } } } } } } /* -------------------------------------------------------------------------- */ static void game_ai_classic_turn_diplo_p2_sub1(struct game_s *g, player_id_t p1, player_id_t p2) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); int v, v4; if (BOOLVEC_IS0(e1->contact, p2) || (e1->treaty[p2] >= TREATY_WAR)) { /* WASBUG? MOO1 also tests for "|| (e1->diplo_val == 0)" ; note the missing [p2] */ e1->diplo_type[p2] = 0; return; } if (game_fleet_any_dest_player(g, p2, p1)) { e1->diplo_type[p2] = 0; return; } if ((e1->diplo_type[p2] != 0) && (!rnd_0_nm1(2, &g->seed))) { return; } v4 = 0; v = e1->trust[p2] + e1->relation1[p2] + ((e1->race == RACE_HUMAN) ? 50 : 0) + game_diplo_tbl_reldiff[e2->trait1]; if ((e1->treaty[p2] == TREATY_NONE) && (e1->relation1[p2] > 15)) { int v8; v8 = v + rnd_1_n(100, &g->seed) + e1->mood_treaty[p2]; if (v8 > 50) { v4 = 1; e1->diplo_type[p2] = 24; } } /*41684*/ if (((e1->treaty[p2] == TREATY_NONAGGRESSION) || (v4 == 1)) && (e1->relation1[p2] > 50)) { int v8; v8 = v + rnd_1_n(100, &g->seed) + e1->mood_treaty[p2]; if (v8 > 100) { v4 = 2; e1->diplo_type[p2] = 25; } } /*416e8*/ if (v4 == 0) { int v8; v8 = v + rnd_1_n(150, &g->seed) + e1->mood_trade[p2]; if (v8 > 50) { int prod, want_trade; prod = MIN(e1->total_production_bc, e2->total_production_bc) / 4; SETMIN(prod, 32000); want_trade = prod / 25; if (want_trade != 0) { want_trade = rnd_1_n(want_trade, &g->seed) * 25; } if (e1->trade_bc[p2] < want_trade) { v4 = 3; e1->diplo_type[p2] = 26; e1->au_want_trade[p2] = want_trade; } } } /*417f2*/ if (v4 == 0) { player_id_t pa = PLAYER_NONE; for (player_id_t p3 = PLAYER_0; p3 < g->players; ++p3) { if ((p3 != p1) && (p3 != p2) && (e2->treaty[p3] >= TREATY_WAR) && BOOLVEC_IS1(e1->contact, p3)) { pa = p3; } } if ((pa != PLAYER_NONE) && (!rnd_0_nm1(10, &g->seed)) && (e1->attack_bounty[p2] == PLAYER_NONE)) { struct spy_esp_s s[1]; int num, bc; s->spy = p1; s->target = p2; num = game_spy_esp_sub1(g, s, 0, 2); /*game_spy_esp_get_random(g, s, &field, &tech); unused */ bc = 0; if (num == 0) { bc = (((rnd_1_n(3, &g->seed) + 1) * g->year) / 50) * 50; s->tbl_tech2[0] = 0; } if ((bc != 0) || (num != 0)) { v4 = 4; e1->diplo_type[p2] = 28; e1->attack_bounty[p2] = pa; e1->attack_gift_field[p2] = s->tbl_field[0]; e1->attack_gift_tech[p2] = s->tbl_tech2[0]; e1->attack_gift_bc[p2] = bc; e1->bounty_collect[p2] = PLAYER_NONE; } } } /*418d2*/ if (v4 == 0) { int v8; v8 = v + rnd_1_n(100, &g->seed) + e1->mood_trade[p2]; if (v8 > 25) { struct spy_esp_s s[1]; int v1c, v14, num; v1c = e1->mood_tech[p2]; if (v1c > 0) { v1c /= 5; } SETMIN(v1c, 30); if (e1->treaty[p2] == TREATY_ALLIANCE) { v1c += 25; } v = e1->trust[p2] + e1->relation1[p2] / 2 + ((e2->race == RACE_HUMAN) ? 50 : 0) + game_diplo_tbl_reldiff[e2->trait1] + v1c - 125; v8 = v + rnd_1_n(100, &g->seed) + v1c - 125; if (v8 < 0) { v14 = abs(v8) + 100; } else { v14 = 20000 / (v8 + 200); } SETMIN(v14, 50); s->spy = p2; s->target = p1; num = game_spy_esp_sub1(g, s, 0, 0); if (num > 0) { bool found; tech_field_t zfield; uint8_t ztech; int zvalue; zfield = s->tbl_field[0]; ztech = s->tbl_tech2[0]; zvalue = (s->tbl_value[0] * 100) / v14; s->spy = p1; s->target = p2; num = game_spy_esp_sub1(g, s, zvalue, 1); found = false; for (int i = 0; i < num; ++i) { if (s->tbl_value[i] <= zvalue) { found = true; break; } } if (found) { int n = 0; v4 = 5; e1->diplo_type[p2] = 29; e1->au_want_field[p2] = zfield; e1->au_want_tech[p2] = ztech; for (int i = 0; i < num; ++i) { if (s->tbl_value[i] <= zvalue) { e1->au_tech_trade_field[p2][n] = s->tbl_field[i]; e1->au_tech_trade_tech[p2][n] = s->tbl_tech2[i]; ++n; } } e1->au_tech_trade_num[p2] = n; e1->mood_tech[p2] = 0; e2->mood_tech[p1] = 0; } } } } /*41aa2*/ if (v4 == 0) { if ((e1->relation1[p2] < 0) && (e1->total_production_bc > e2->total_production_bc) && (e1->treaty[p2] == TREATY_NONE)) { v4 = 1; e1->diplo_type[p2] = 24; } } /*41ae2*/ /*41c23*/ if (1 && (e2->total_production_bc != 0) && ((v4 == 1) || (v4 == 2)) && (e2->trait1 > TRAIT1_RUTHLESS) && (rnd_1_n(100, &g->seed) <= ((e1->total_production_bc * 30) / e2->total_production_bc)) && (!rnd_0_nm1(8, &g->seed)) ) { if (rnd_0_nm1(4, &g->seed)) { e1->offer_bc[p2] = ((e2->total_production_bc / (rnd_1_n(3, &g->seed) + 1) + g->year) / 25) * 25; } else { struct spy_esp_s s[1]; s->spy = p1; s->target = p2; if (game_spy_esp_sub1(g, s, 0, 2) > 0) { e1->offer_field[p2] = s->tbl_field[0]; e1->offer_tech[p2] = s->tbl_tech2[0]; } } } } static void game_ai_classic_turn_diplo_p2_sub2(struct game_s *g, player_id_t p1, player_id_t p2) { empiretechorbit_t *e1 = &(g->eto[p1]); if ((e1->treaty[p2] == TREATY_ALLIANCE) && (!rnd_0_nm1(10, &g->seed))) { player_id_t pa = PLAYER_NONE; for (player_id_t p3 = PLAYER_0; p3 < g->players; ++p3) { empiretechorbit_t *e3 = &(g->eto[p3]); if (1 && (p3 != p1) && (p3 != p2) && (e3->treaty[p2] == TREATY_WAR) && BOOLVEC_IS1(e1->contact, p3) && (e1->treaty[p3] != TREATY_WAR) ) { pa = p3; } } e1->au_ally_attacker[p2] = pa; e1->diplo_type[p2] = (pa == PLAYER_NONE) ? 0 : 76; } else { e1->diplo_type[p2] = 0; } } static void game_ai_classic_turn_diplo_p2_sub3(struct game_s *g, player_id_t p1, player_id_t p2) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); int v; if (BOOLVEC_IS0(e1->contact, p2)) { /* WASBUG? MOO1 also tests for "|| (e1->diplo_val == 0)" ; note the missing [p2] */ e1->diplo_type[p2] = 0; return; } v = e1->trust[p2] + e1->relation1[p2] + ((e1->race == RACE_HUMAN) ? 50 : 0) + game_diplo_tbl_reldiff[e2->trait1]; if (e1->treaty[p2] < TREATY_WAR) { if (e1->relation1[p2] <= -95) { game_diplo_start_war(g, p2, p1); e1->diplo_type[p2] = 13; } else if ((v - rnd_1_n(100, &g->seed) + e1->mood_treaty[p2]) <= -100) { if (e1->hatred[p2] > 0) { ++e1->hatred[p2]; if ((e1->hatred[p2] > 2) || (e1->treaty[p2] == TREATY_NONE)) { if (rnd_1_n(100, &g->seed) < -(game_diplo_tbl_reldiff[e2->trait1] / 2 + e1->diplo_val[p2])) { game_diplo_start_war(g, p2, p1); e1->diplo_type[p2] = 13; e1->hatred[p2] = 1; } } else { e1->diplo_type[p2] += 46; game_diplo_break_treaty(g, p2, p1); } } else { e1->hatred[p2] = 1; if ((e1->treaty[p2] == TREATY_NONAGGRESSION) || (e1->treaty[p2] == TREATY_ALLIANCE) || (e1->trade_bc[p2] != 0)) { e1->diplo_type[p2] += 38; } } } } else if (((v + rnd_1_n(100, &g->seed) + e1->mood_peace[p2]) >= 50) && (!rnd_0_nm1(8, &g->seed))) { e1->diplo_type[p2] = 30; if (rnd_1_n(100, &g->seed) <= ((e2->total_production_bc * 30) / e1->total_production_bc)) { if (rnd_0_nm1(4, &g->seed)) { e1->offer_bc[p2] = ((e2->total_production_bc / (rnd_1_n(3, &g->seed) + 1) + g->year) / 25) * 25; } else { struct spy_esp_s s[1]; s->spy = p1; s->target = p2; if (game_spy_esp_sub1(g, s, 0, 2) > 0) { e1->offer_field[p2] = s->tbl_field[0]; e1->offer_tech[p2] = s->tbl_tech2[0]; } } } } } static void game_ai_classic_turn_diplo_p2(struct game_s *g) { game_diplo_limit_mood_treaty(g); for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); if (IS_AI(g, p1)) { continue; } if (!IS_ALIVE(g, p1)) { memset(e1->diplo_type, 0, sizeof(e1->diplo_type)); continue; } for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { empiretechorbit_t *e2 = &(g->eto[p2]); if (IS_HUMAN(g, p2)) { continue; } if (!IS_ALIVE(g, p2)) { e1->diplo_type[p2] = 0; continue; } if ((e1->treaty[p2] == TREATY_FINAL_WAR) || (e1->diplo_type[p2] == 59)) { if (e1->diplo_type[p2] != 59) { e1->diplo_type[p2] = 0; } } else if (e1->have_met[p2] == 1) { e1->have_met[p2] = 2; e1->diplo_type[p2] = e2->trait1 + 14; } else if (e1->bounty_collect[p2] != PLAYER_NONE) { e1->diplo_type[p2] = 58; } else if ((e1->diplo_type[p2] == 13) || (e1->diplo_type[p2] == 32) || (e1->diplo_type[p2] == 61) || (e1->diplo_type[p2] == 60)) { /*v8 = 0; unused */ } else { /*16441*/ int16_t v, v2, dv2; v = game_diplo_get_mood(g, p1, p2); v2 = v + e1->trust[p2] + game_diplo_tbl_reldiff[e2->trait1]; dv2 = e1->diplo_val[p2] * 2; if ((v2 <= -100) || (v <= -100)) { e1->diplo_type[p2] = 0; } else if (e1->diplo_val[p2] < 0) { if ((e1->hatred[p2] > 0) || (rnd_1_n(100, &g->seed) < abs(dv2))) { game_ai_classic_turn_diplo_p2_sub3(g, p1, p2); } else { e1->diplo_type[p2] = 0; } } else if ((e1->treaty[p2] == TREATY_WAR) && ((rnd_1_n(100, &g->seed) + 30) < e1->mood_peace[p2])) { game_ai_classic_turn_diplo_p2_sub3(g, p1, p2); } else if ((rnd_1_n(100, &g->seed) < (dv2 + ((e1->hatred[p2] == 0) ? 3 : 0))) && (!rnd_0_nm1(4, &g->seed))) { if (e1->hatred[p2] > 0) { e1->hatred[p2] = 0; } else { game_ai_classic_turn_diplo_p2_sub1(g, p1, p2); } } else { /*1656f*/ game_ai_classic_turn_diplo_p2_sub2(g, p1, p2); } } /*16576*/ if (e1->diplo_type[p2] == 0) { game_ai_classic_diplo_wage_war(g, p1, p2); } if ((e1->diplo_type[p2] == 2) && rnd_0_nm1(10, &g->seed)) { e1->diplo_type[p2] = 0; } } } } /* -------------------------------------------------------------------------- */ static int game_ai_classic_aud_check_mood(struct audience_s *au, int a0, int a2) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v; switch (a2) { default: case 0: v = eh->mood_treaty[pa]; break; case 1: v = eh->mood_trade[pa]; break; case 2: v = eh->mood_peace[pa]; break; case 3: v = eh->mood_tech[pa]; break; } v += eh->trust[pa] + eh->relation1[pa] + ((eh->race == RACE_HUMAN) ? 50 : 0) + game_diplo_tbl_reldiff[ea->trait1]; v += rnd_1_n(100, &g->seed); v -= a0; if (eh->treaty[pa] == TREATY_ALLIANCE) { v += 40; } game_diplo_annoy(g, ph, pa, 1); switch (a2) { default: case 0: eh->mood_treaty[pa] -= rnd_1_n(30, &g->seed) + 20; break; case 1: eh->mood_trade[pa] -= rnd_1_n(30, &g->seed) + 20; break; case 2: eh->mood_peace[pa] -= rnd_1_n(50, &g->seed) + 50; break; case 3: eh->mood_tech[pa] -= rnd_1_n(50, &g->seed) + 20; break; } if (v < -75) { return 0; } else if (v < -50) { return 1; } else if (v < 0) { return 2; } else { return 3; } } static void game_ai_classic_aud_start_human(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v; v = eh->trust[pa] + game_diplo_get_mood(g, ph, pa) + game_diplo_tbl_reldiff[ea->trait1]; if (v < -100) { au->dtype = (eh->treaty[pa] >= TREATY_WAR) ? 20 : 21; au->mode = 1; } else { v += eh->relation1[pa]; au->dtype = (v > -50) ? 22 : 23; au->mode = 0; } } static int game_ai_classic_aud_treaty_nap(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int si; if (eh->relation1[pa] > 10) { si = game_ai_classic_aud_check_mood(au, 50, 0); } else { si = 0; } return si; } static int game_ai_classic_aud_treaty_alliance(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int si; if (eh->relation1[pa] > 50) { si = game_ai_classic_aud_check_mood(au, 125, 0); } else { si = 0; } return si; } static int game_ai_classic_aud_treaty_peace(struct audience_s *au) { int si; int mi = (au->g->ai_id == GAME_AI_CLASSICPLUS) ? 2/*peace*/ : 0/*treaty*/; /* WASBUG? mood_peace makes sense */ si = game_ai_classic_aud_check_mood(au, 60, mi); return si; } static int game_ai_classic_aud_treaty_declare_war(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int si; if ((eh->treaty[pa] == TREATY_ALLIANCE) && (eh->treaty[au->pstartwar] == TREATY_WAR)) { si = (!rnd_0_nm1(8, &g->seed)) ? 2 : 3; } else { int v = ea->relation1[au->pstartwar] + 150; if (g->ai_id != GAME_AI_CLASSIC) { /* WASBUG? MOO1 contains the treaty * 30 code but the result is unused. OSG states that either NAP or alliance changes that 150 to 250 but there is no such code. */ v += ea->treaty[au->pstartwar] * 30; } si = game_ai_classic_aud_check_mood(au, v, 0); } return si; } static int game_ai_classic_aud_treaty_break_alliance(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int si; if (eh->relation1[pa] > 24) { si = game_ai_classic_aud_check_mood(au, ea->relation1[au->pwar] + 175, 0); } else { si = 0; } return si; } static int game_ai_classic_aud_trade(struct audience_s *au) { int si; si = game_ai_classic_aud_check_mood(au, 50, 1); return si; } static bool game_ai_classic_aud_sweeten(struct audience_s *au, int *bcptr, tech_field_t *fieldptr, uint8_t *techptr) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int bc; tech_field_t field = 0; uint8_t tech; bc = (((rnd_1_n(8, &g->seed) + rnd_1_n(8, &g->seed)) * g->year) / 25) * 25; if (bc > eh->reserve_bc) { bc = 0; } { struct spy_esp_s s[1]; s->spy = pa; s->target = ph; if (game_spy_esp_sub1(g, s, g->year, 1) > 0) { field = s->tbl_field[0]; tech = s->tbl_tech2[0]; } else { tech = 0; } } *bcptr = bc; *fieldptr = field; *techptr = tech; if ((bc == 0) && (tech == 0)) { return false; } return true; } static uint8_t game_ai_classic_aud_threaten(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v; uint8_t dtype; v = rnd_1_n(200, &g->seed) + eh->mood_treaty[pa] / 2; v += game_diplo_tbl_reldiff[ea->trait1] * 2; if (ea->total_production_bc > 0) { v += (eh->total_production_bc * 100) / ea->total_production_bc; } else { v += 100; } SUBSATT(eh->relation1[pa], rnd_1_n(15, &g->seed), -100); ea->relation1[ph] = eh->relation1[pa]; eh->mood_treaty[pa] = -120; if (v < 170) { if ((rnd_1_n(15, &g->seed) - game_diplo_tbl_reldiff[ea->trait1]) > rnd_1_n(100, &g->seed)) { game_diplo_start_war(g, ph, pa); dtype = 13; } else { dtype = 69; } } else { if (g->ai_id == GAME_AI_CLASSICPLUS) { ea->spymode_next[ph] = SPYMODE_HIDE; ea->spymode[ph] = SPYMODE_HIDE; } else { /* WASBUG MOO1 hides your spies */ eh->spymode_next[pa] = SPYMODE_HIDE; eh->spymode[pa] = SPYMODE_HIDE; } g->evn.ceasefire[ph][pa] = rnd_1_n(15, &g->seed) + 5; dtype = 70; if (v >= 275) { struct spy_esp_s s[1]; s->spy = ph; s->target = pa; if (game_spy_esp_sub1(g, s, 0, 1) > 0) { au->tribute_field = s->tbl_field[0]; au->tribute_tech = s->tbl_tech2[0]; game_tech_get_new(g, ph, au->tribute_field, au->tribute_tech, TECHSOURCE_TRADE, pa, PLAYER_NONE, false); /* WASBUG? pa was 0 */ } } else if (v >= 200) { int bc; bc = (((rnd_1_n(8, &g->seed) + 2) * g->year) / 25) * 25; if (bc != 0) { eh->reserve_bc += bc; au->tribute_bc = bc; dtype = 71; } } } return dtype; } static void game_ai_classic_aud_tribute_bc(struct audience_s *au, int selected, int bc) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v; if (ea->total_production_bc != 0) { /* WASBUG MOO1 uses the value (reserve * 12) / (0x786e + 0xdd4 * pa + 0x326b0000) == (reserve * 12) / ea->relation1 == 0 This makes money tributes quite useless. The formula below is according to OSG. */ if (g->ai_id == GAME_AI_CLASSICPLUS) { v = (bc * 12) / ea->total_production_bc; } else { v = 0; } } else { v = selected + 1; } if (eh->race == RACE_HUMAN) { v *= 2; } ADDSATT(eh->relation1[pa], v, 100); ea->relation1[ph] = eh->relation1[pa]; if (eh->treaty[pa] >= TREATY_WAR) { SETMIN(ea->relation1[ph], -25); } if (eh->treaty[pa] != TREATY_ALLIANCE) { SETMIN(ea->relation1[ph], 65); } /* BUG? eh->relation1[pa] = ea->relation1[ph]; is missing */ if (g->ai_id == GAME_AI_CLASSICPLUS) { eh->relation1[pa] = ea->relation1[ph]; } } static void game_ai_classic_aud_tribute_tech(struct audience_s *au, int selected, tech_field_t field, uint8_t tech) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v; if (eh->relation1[pa] < 0) { v = 20; } else { v = (100 - eh->relation1[pa]) / 10; } v = ((rnd_1_n(8, &g->seed) + rnd_1_n(8, &g->seed) + (tech / 4)) * v) / 10; if (eh->race == RACE_HUMAN) { v *= 2; } ADDSATT(eh->relation1[pa], v, 100); ea->relation1[ph] = eh->relation1[pa]; ADDSATT(eh->mood_peace[pa], v, 200); ADDSATT(eh->trust[pa], rnd_1_n(8, &g->seed) + 2, 30); if (eh->treaty[pa] >= TREATY_WAR) { SETMIN(ea->relation1[ph], -25); } if (eh->treaty[pa] != TREATY_ALLIANCE) { SETMIN(ea->relation1[ph], 70); } /* BUG? eh->relation1[pa] = ea->relation1[ph]; is missing */ if (g->ai_id == GAME_AI_CLASSICPLUS) { eh->relation1[pa] = ea->relation1[ph]; } } static int game_ai_classic_aud_tech_scale(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int v, di; di = eh->mood_tech[pa]; if (di > 0) { di /= 5; } SETMIN(di, 30); if (eh->treaty[pa] == TREATY_ALLIANCE) { di += 25; } v = eh->trust[pa] + eh->relation1[pa] / 2 + ((eh->race == RACE_HUMAN) ? 50 : 0); v += game_diplo_tbl_reldiff[ea->trait1] * 2 + di + rnd_1_n(100, &g->seed) - 125; if (v < 0) { v = abs(v) + 100; } else { v = 20000 / (v + 200); } v /= 4; SETMAX(v, 75); return v; } static uint8_t game_ai_classic_aud_get_dtype(struct audience_s *au, uint8_t dtype, int a2) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); if ((dtype == 31) || ((dtype >= 33) && (dtype <= 41)) || ((dtype >= 62) && (dtype <= 68))) { switch (a2) { case 0: case 1: case 2: if ((eh->blunder[pa] != 0) && (!rnd_0_nm1(2, &g->seed))) { dtype = eh->blunder[pa] + 30; eh->blunder[pa] = 0; } else if ((eh->broken_treaty[pa] != TREATY_NONE) && (!rnd_0_nm1(4, &g->seed))) { dtype = 33; eh->broken_treaty[pa] = TREATY_NONE; } else { dtype = 31; } break; case 3: if ((!rnd_0_nm1(4, &g->seed)) && (eh->tribute_tech[pa] != 0)) { au->tribute_field = eh->tribute_field[pa]; au->tribute_tech = eh->tribute_tech[pa]; eh->tribute_tech[pa] = 0; dtype = 66; } break; default: break; } } return dtype; } static bool game_ai_classic_aud_later(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; return (game_diplo_get_mood(g, ph, pa) < -100); } /* -------------------------------------------------------------------------- */ const struct game_ai_s game_ai_classic = { GAME_AI_CLASSIC, "Classic", game_ai_classic_new_game_init, game_ai_classic_new_game_tech, game_ai_classic_turn_p1, game_ai_classic_turn_p2, game_ai_classic_turn_p3, game_ai_classic_battle_ai_ai_resolve, game_ai_classic_battle_ai_turn, game_ai_classic_battle_ai_retreat, game_ai_classic_tech_next, game_ai_classic_bomb, game_ai_classic_ground, game_ai_classic_crank_tech, /* plague */ game_ai_classic_crank_tech, /* nova */ game_ai_classic_crank_ship, /* comet */ game_ai_classic_crank_ship, /* pirates */ game_ai_classic_vote, game_ai_classic_turn_diplo_p1, game_ai_classic_turn_diplo_p2, game_ai_classic_aud_start_human, game_ai_classic_aud_treaty_nap, game_ai_classic_aud_treaty_alliance, game_ai_classic_aud_treaty_peace, game_ai_classic_aud_treaty_declare_war, game_ai_classic_aud_treaty_break_alliance, game_ai_classic_aud_trade, game_ai_classic_aud_sweeten, game_ai_classic_aud_threaten, game_ai_classic_aud_tribute_bc, game_ai_classic_aud_tribute_tech, game_ai_classic_aud_tech_scale, game_ai_classic_aud_get_dtype, game_ai_classic_aud_later }; const struct game_ai_s game_ai_classicplus = { GAME_AI_CLASSICPLUS, "Classic+", game_ai_classic_new_game_init, game_ai_classic_new_game_tech, game_ai_classic_turn_p1, game_ai_classic_turn_p2, game_ai_classic_turn_p3, game_ai_classic_battle_ai_ai_resolve, game_ai_classic_battle_ai_turn, game_ai_classic_battle_ai_retreat, game_ai_classic_tech_next, game_ai_classic_bomb, game_ai_classic_ground, game_ai_classic_crank_tech, /* plague */ game_ai_classic_crank_tech, /* nova */ game_ai_classic_crank_ship, /* comet */ game_ai_classic_crank_ship, /* pirates */ game_ai_classic_vote, game_ai_classic_turn_diplo_p1, game_ai_classic_turn_diplo_p2, game_ai_classic_aud_start_human, game_ai_classic_aud_treaty_nap, game_ai_classic_aud_treaty_alliance, game_ai_classic_aud_treaty_peace, game_ai_classic_aud_treaty_declare_war, game_ai_classic_aud_treaty_break_alliance, game_ai_classic_aud_trade, game_ai_classic_aud_sweeten, game_ai_classic_aud_threaten, game_ai_classic_aud_tribute_bc, game_ai_classic_aud_tribute_tech, game_ai_classic_aud_tech_scale, game_ai_classic_aud_get_dtype, game_ai_classic_aud_later }; 1oom-1.11.2/src/game/game_ai_classic.h000066400000000000000000000003071476061725400174170ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_AI_CLASSIC_H #define INC_1OOM_GAME_AI_CLASSIC_H #include "game_ai.h" extern const struct game_ai_s game_ai_classic; extern const struct game_ai_s game_ai_classicplus; #endif 1oom-1.11.2/src/game/game_audience.c000066400000000000000000001160061476061725400171010ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include "game_audience.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_diplo.h" #include "game_misc.h" #include "game_num.h" #include "game_spy.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "ui.h" /* -------------------------------------------------------------------------- */ #define DEBUGLEVEL_AUDIENCE 3 static void game_audience_clear_strtbl(struct audience_s *au) { for (int i = 0; i < AUDIENCE_STR_MAX; ++i) { au->strtbl[i] = NULL; } } /* Prepare a menu with options for the player; condtbl indicates which options * are active. As a shortcut, if it is NULL, all options are active. The menu * can be presented to the player using the ui_audience_ask* functions. */ static void game_audience_choice(struct audience_s *au, const char *query, const char **options, const bool *condtbl, uint8_t num_entries) { int i; au->buf = query; if (num_entries >= AUDIENCE_STR_MAX) { log_fatal_and_die("Too many strings in au->strtbl\n"); } for (i = 0; i < num_entries; ++i) { au->strtbl[i] = options[i]; } au->strtbl[i] = NULL; au->condtbl = condtbl; } static void game_audience_tech_choice(struct audience_s *au, const char *query, tech_field_t *fields, uint8_t *techs, int num_techs, bool forget_it_opt) { struct strbuild_s strbuild = strbuild_init(au->strtbl_buf, AUDIENCE_STRTBL_BUFSIZE); int num_entries = forget_it_opt ? num_techs + 1 : num_techs; char tech_name[64]; au->buf = query; if (num_entries >= AUDIENCE_STR_MAX) { log_fatal_and_die("Too many strings in au->strtbl\n"); } int i; for (i = 0; i < num_techs; i++) { game_tech_get_name(au->g->gaux, fields[i], techs[i], tech_name, sizeof(tech_name)); strbuild_catf(&strbuild, "%s %s", game_str_au_bull, tech_name); au->strtbl[i] = strbuild_finish(&strbuild); } if (forget_it_opt) { au->strtbl[i++] = game_str_au_opts_agree[1]; /* "Forget It" */ } au->strtbl[i] = NULL; au->condtbl = NULL; } static void game_audience_prepare(struct audience_s *au, player_id_t ph, player_id_t pa) { au->buf = NULL; au->ph = ph; au->pa = pa; game_audience_clear_strtbl(au); au->gfxi = 0; au->musi = 0; au->dtype_next = 0; } static void game_audience_start_human(struct audience_s *au) { game_ai->aud_start_human(au); } static void game_audience_str_append_offer(struct strbuild_s *strbuild, const struct game_s *g, tech_field_t field, uint8_t tech, uint16_t bc) { strbuild_append_char(strbuild, ' '); if (tech != 0) { char tech_name[64]; game_tech_get_name(g->gaux, field, tech, tech_name, sizeof(tech_name)); strbuild_catf(strbuild, "%s", tech_name); strbuild_catf(strbuild, " %s", game_str_au_tech); } else if (bc != 0) { strbuild_catf(strbuild, "%u %s", bc, game_str_bc); } } static void game_audience_append_tech(struct strbuild_s *str, struct game_s *g, tech_field_t field, uint8_t tech) { char tech_name[64]; game_tech_get_name(g->gaux, field, tech, tech_name, sizeof(tech_name)); strbuild_catf(str, "%s", tech_name); } static void audience_build_diplo_msg(struct audience_s *au, bool framed) { struct game_s *g = au->g; uint8_t dtype = au->dtype; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); const char *msg; struct strbuild_s strbuild = strbuild_init(au->diplo_msg, AUDIENCE_DIPLO_MSG_SIZE); /* Randomly select a varation of the message type. */ int v = rnd_0_nm1(g->gaux->diplomat.d0[dtype], &g->seed); if (g->players == 2) { --v; SETMAX(v, 0); } g->evn.diplo_msg_subtype = v; msg = DIPLOMAT_MSG_PTR(g->gaux, v, dtype); /* Fill in placeholders in the message. */ for (int i = 0; (i < DIPLOMAT_MSG_LEN) && (msg[i] != 0); ++i) { char c; c = msg[i]; if (c & 0x80) { const char *s; const char *field; s = NULL; switch (c & 0x7f) { case 0: /* Player race */ s = game_str_tbl_race[eh->race]; break; case 1: /* AI race */ s = game_str_tbl_race[ea->race]; break; case 0x16: /* "a" or "an" */ s = (strchr("aeiou", tolower(game_str_tbl_race[ea->race][0])) != NULL) ? "n" : ""; break; case 2: /* "factories" or "bases" (sabotage) */ s = (!eh->diplo_p2[pa]) ? game_str_au_facts : game_str_au_bases; break; case 0xb: /* Current treaty */ if (eh->treaty[pa] == TREATY_ALLIANCE) { s = game_str_au_allian; } else if (eh->treaty[pa] == TREATY_NONAGGRESSION) { s = game_str_au_nonagg; } else if (eh->trade_bc[pa] != 0) { s = game_str_au_tradea; } else { s = game_str_au_treaty; } break; case 0x17: /* Broken treaty (by AI) */ if (ea->broken_treaty[ph] == TREATY_ALLIANCE) { s = game_str_au_allian; } else if (ea->broken_treaty[ph] == TREATY_NONAGGRESSION) { s = game_str_au_nonagg; } else if (ea->broken_treaty[ph] == TREATY_NONE) { s = game_str_au_tradea; } else { s = game_str_au_treaty; } break; case 3: /* Player name */ s = g->emperor_names[ph]; break; case 9: /* AI leader name */ s = g->emperor_names[pa]; break; case 4: field = game_str_tbl_te_field[eh->diplo_p2[pa]]; while (*field != '\0') { strbuild_append_char(&strbuild, tolower(*field++)); } /* WASBUG MOO1 printed "force Field" */ break; case 5: s = g->planet[eh->diplo_p1[pa]].name; break; case 6: s = game_str_tbl_race[g->eto[eh->diplo_p2[pa]].race]; break; case 8: s = game_str_tbl_race[g->eto[eh->attack_bounty[pa]].race]; break; case 0xc: s = game_str_tbl_race[g->eto[eh->au_ask_break_treaty[pa]].race]; break; case 0xf: strbuild_catf(&strbuild, "%i", g->year + YEAR_BASE); break; case 0x13: strbuild_catf(&strbuild, "%i", au->tribute_bc); break; case 7: strbuild_catf(&strbuild, "%u", eh->au_want_trade[pa]); break; case 0x15: strbuild_catf(&strbuild, "%u", eh->trade_bc[pa]); break; case 0xa: strbuild_catf(&strbuild, "\x02 %s\x01", game_str_au_amreca); break; case 0x11: s = game_str_tbl_race[g->eto[au->pstartwar].race]; break; case 0x12: s = game_str_tbl_race[g->eto[au->pwar].race]; break; case 0xd: if (eh->attack_gift_bc[pa] != 0) { strbuild_catf(&strbuild, "%i %s.", eh->attack_gift_bc[pa], game_str_bc); } else { game_audience_append_tech(&strbuild, g, eh->attack_gift_field[pa], eh->attack_gift_tech[pa]); strbuild_catf(&strbuild, " %s.", game_str_au_tech); } break; case 0xe: game_audience_append_tech(&strbuild, g, eh->au_want_field[pa], eh->au_want_tech[pa]); strbuild_catf(&strbuild, " %s.", game_str_au_tech); break; case 0x10: game_audience_append_tech(&strbuild, g, au->tribute_field, au->tribute_tech); break; case 0x14: game_audience_append_tech(&strbuild, g, au->tribute_field, au->tribute_tech); strbuild_catf(&strbuild, " %s.", game_str_au_tech); break; default: strbuild_append_char(&strbuild, c); break; } if (s) { strbuild_catf(&strbuild, "%s", s); } } else { strbuild_append_char(&strbuild, c); } } if (framed) { strbuild_catf(&strbuild, "\x02 %s\x01", game_str_au_framed); } au->gfxi = DIPLOMAT_MSG_GFX(msg); au->musi = DIPLOMAT_MSG_MUS(msg); } /* Build the diplomat message if necessary and set it to be displayed. */ static void game_audience_get_diplo_msg(struct audience_s *au) { struct game_s *g = au->g; uint8_t dtype = au->dtype; bool framed = false; if ((dtype == 5) || (dtype == 7) || (dtype == 35) || (dtype == 37) || (dtype == 43) || (dtype == 45) || (dtype == 51) || (dtype == 53)) { framed = true; au->dtype -= 1; } if (g->evn.diplo_msg_subtype == -1) { audience_build_diplo_msg(au, framed); /* Sets diplo_msg_subtype. */ } au->buf = au->diplo_msg; } static void game_audience_ai_offers_bounty(struct audience_s *au) { ui_audience_show2(au); } static void game_audience_ai_pays_bounty(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); ui_audience_show2(au); if (game_num_aud_bounty_give) { /* WASBUG MOO1 never gives the bounty */ eh->reserve_bc += eh->attack_gift_bc[pa]; if (eh->attack_gift_tech[pa] != 0) { game_tech_get_new(g, ph, eh->attack_gift_field[pa], eh->attack_gift_tech[pa], TECHSOURCE_TRADE, pa, PLAYER_NONE, false); } } } static void game_audience_set_dtype(struct audience_s *au, uint8_t dtype, int a2) { struct game_s *g = au->g; au->dtype = game_ai->aud_get_dtype(au, dtype, a2); g->evn.diplo_msg_subtype = -1; game_audience_get_diplo_msg(au); ui_audience_show3(au); } static void game_audience_ai_offers_tech_trade(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int num_techs = MIN(eh->au_tech_trade_num[pa], 4); int16_t selected = -1, default_selected = num_techs + 1; ui_audience_show2(au); game_audience_tech_choice(au, game_str_au_inxchng, eh->au_tech_trade_field[pa], eh->au_tech_trade_tech[pa], num_techs, true); selected = ui_audience_ask2a(au); selected = (selected != -1) ? selected : default_selected; game_tech_get_new(g, ph, eh->au_tech_trade_field[pa][selected], eh->au_tech_trade_tech[pa][selected], TECHSOURCE_TRADE, pa, PLAYER_NONE, false); /* WASBUG? 1oom v1.0 did not give a tech to the AI. Not sure if this bug * was present in MOO1 or introduced in 1oom. */ game_tech_get_new(g, pa, eh->au_want_field[pa], eh->au_want_tech[pa], TECHSOURCE_TRADE, pa, PLAYER_NONE, false); } static void game_audience_ai_breaks_alliance(struct audience_s *au) { game_diplo_break_treaty(au->g, au->pa, au->ph); au->mode = 6; game_audience_set_dtype(au, 77, 3); } static bool game_audience_ai_offers_treaty(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; uint8_t dtype = au->dtype; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int16_t selected = -1; game_audience_clear_strtbl(au); if (dtype == 27) { game_audience_choice(au, au->diplo_msg, game_str_au_opts_agree, NULL, 2); } else { game_audience_choice(au, au->diplo_msg, game_str_au_opts_accept, NULL, 2); } selected = ui_audience_ask2b(au); /* If the player refuses, the AI may offer to sweeten the deal. */ if (((selected == 1) || (selected == -1)) && ((eh->offer_tech[pa] != 0) || (eh->offer_bc[pa] != 0))) { struct strbuild_s strbuild = strbuild_init(au->diplo_msg, AUDIENCE_DIPLO_MSG_SIZE); bool flag_qtype = (!rnd_0_nm1(2, &g->seed)); strbuild_catf(&strbuild, "%s", flag_qtype ? game_str_au_whatif1 : game_str_au_perrec1); game_audience_str_append_offer(&strbuild, g, eh->offer_field[pa], eh->offer_tech[pa], eh->offer_bc[pa]); if (flag_qtype) { strbuild_catf(&strbuild, " %s", game_str_au_whatif2); } strbuild_catf(&strbuild, "%s", game_str_au_ques); au->buf = au->diplo_msg; /* We still have accept/reject or agree/forget-it in au->strtbl. */ selected = ui_audience_ask2b(au); } if (selected == 0) { /* Player accepted. */ switch (au->dtype) { case 24: game_diplo_set_treaty(g, ph, pa, TREATY_NONAGGRESSION); break; case 25: game_diplo_set_treaty(g, ph, pa, TREATY_ALLIANCE); break; case 26: game_diplo_set_trade(g, ph, pa, eh->au_want_trade[pa]); break; case 27: /* Player breaks alliance with the AI's enemy. */ game_diplo_break_treaty(g, ph, eh->au_ask_break_treaty[pa]); break; case 30: game_diplo_stop_war(g, ph, pa); if (eh->relation1[pa] < 80) { eh->relation1[pa] += 20; ea->relation1[ph] = eh->relation1[pa]; } game_diplo_annoy(g, ph, pa, 2); break; case 76: /* Player joins their ally's war. */ game_diplo_start_war(g, ph, au->pwar); au->mode = 6; game_audience_set_dtype(au, 78, 3); break; default: log_fatal_and_die("%s: BUG unhandled dtype %u\n", __func__, au->dtype); break; } /* BUG? Give the deal-sweetener. Note that this happens even if the * player didn't refuse at first and thus didn't see the sweetener. * This may silently add some money to the player's reserve. */ /* BUG? AI doesn't give a deal-sweetener for honoring your alliance. * That makes some sense, but can it ever happen that the AI offers * a sweetener and doesn't give it? */ if (dtype != 76) { eh->reserve_bc += eh->offer_bc[pa]; /* BUG? AI doesn't lose money? */ if (eh->offer_tech[pa] != 0) { game_tech_get_new(g, ph, eh->offer_field[pa], eh->offer_tech[pa], TECHSOURCE_TRADE, pa, PLAYER_NONE, false); } } } else { /* Player refused. */ switch (dtype) { case 27: /* Player didn't break alliance with the AI's enemy. */ /* ea->relation1[ph] -= rnd_1_n(6, &g->seed) + 6; SETMAX(ea->relation1[ph], -100); BUG? useless */ ea->relation1[ph] = -100; eh->relation1[pa] = -100; break; case 76: /* Player did not honor their alliance. */ game_audience_ai_breaks_alliance(au); break; default: break; } } return selected == 0; } /* If the AI wants to offer a deal to the player, but the player is * allied with one of its war enemies, it asks the player to break the * alliance and does not make the offer if they refuse. * * The function returns true if either * - the player is not allied with an enemy of the AI, or * - the player chose to break the alliance * and false otherwise. */ static bool game_audience_check_alliances(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa, pf = PLAYER_NONE; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); bool retval; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != ph) && (i != pa) && (ea->treaty[i] >= TREATY_WAR) && (eh->treaty[i] == TREATY_ALLIANCE)) { pf = i; } } if (pf == PLAYER_NONE) { return true; } au->dtype = 27; eh->au_ask_break_treaty[pa] = pf; g->evn.diplo_msg_subtype = -1; game_audience_get_diplo_msg(au); /* Note: The below game_audience_ai_offers_treaty call is for asking the * player to break the alliance. The main offer will be made in * game_audience_do. */ retval = game_audience_ai_offers_treaty(au); if ((au->dtype_next == 76) && !retval) { /* The AI is allied with the player and was going to ask them to join * a war against an enemy. But the player also has an alliance with one * of the AI's enemies and refused to break it, so the AI now cancels * the alliance with the player. In the grimdark future of the 23rd * century, you can't be friends with everyone. */ game_audience_ai_breaks_alliance(au); } return retval; } static int game_audience_sweeten(struct audience_s *au, int a0) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int bc = 0; tech_field_t field = 0; uint8_t tech = 0; bool flag_bc; int16_t selected = 0; char query[320]; struct strbuild_s strbuild; if (!game_ai->aud_sweeten(au, &bc, &field, &tech)) { return 0; } if ((bc == 0) && (tech == 0)) { return 0; } if (((tech != 0) && (a0 == 1)) || (bc == 0)) { flag_bc = false; } else { tech = 0; flag_bc = true; } strbuild = strbuild_init(query, sizeof(query)); if (!rnd_0_nm1(2, &g->seed)) { strbuild_catf(&strbuild, "%s", game_str_au_perthr1); game_audience_str_append_offer(&strbuild, g, field, tech, bc); strbuild_catf(&strbuild, " %s", game_str_au_perthr2); } else { strbuild_catf(&strbuild, "%s", game_str_au_alsoof1); game_audience_str_append_offer(&strbuild, g, field, tech, bc); strbuild_catf(&strbuild, " %s", game_str_au_alsoof2); } game_audience_choice(au, query, game_str_au_opts_agree, NULL, 2); selected = ui_audience_ask3(au); if ((selected == -1) || (selected == 1)) { return 1; } if (!flag_bc) { game_tech_get_new(g, pa, field, tech, TECHSOURCE_TRADE, ph, PLAYER_NONE, false); } else { eh->reserve_bc -= bc; ea->reserve_bc += bc; } return 3; } static player_id_t audience_menu_race(struct audience_s *au, player_id_t *rtbl, uint8_t rnum, const char *titlestr) { struct game_s *g = au->g; struct strbuild_s strtbl_build = strbuild_init(au->strtbl_buf, AUDIENCE_STRTBL_BUFSIZE); int16_t selected = 0; for (int i = 0; i < rnum; ++i) { empiretechorbit_t *e = &(g->eto[rtbl[i]]); strbuild_catf(&strtbl_build, "%s %s", game_str_au_bull, game_str_tbl_races[e->race]); au->strtbl[i] = strbuild_finish(&strtbl_build); } au->strtbl[rnum] = game_str_au_opts_agree[1]; /* "Forget It" */ au->strtbl[rnum + 1] = NULL; au->buf = titlestr; au->condtbl = NULL; selected = ui_audience_ask4(au); if ((selected >= 0) && (selected < rnum)) { return rtbl[selected]; } return PLAYER_NONE; } static void audience_menu_treaty(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int16_t selected = 0; bool condtbl[6]; uint8_t war_num, all_num, dtype; player_id_t war_tbl[PLAYER_NUM], all_tbl[PLAYER_NUM]; int si; for (int i = 0; i < TBLLEN(condtbl); ++i) { condtbl[i] = true; } if (eh->treaty[pa] != TREATY_NONE) { condtbl[0] = false; } if (eh->treaty[pa] >= TREATY_ALLIANCE) { condtbl[1] = false; } if (eh->treaty[pa] < TREATY_WAR) { condtbl[2] = false; } if (eh->treaty[pa] >= TREATY_WAR) { condtbl[3] = false; } war_num = 0; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != ph) && (i != pa) && (ea->treaty[i] < TREATY_WAR)) { war_tbl[war_num++] = i; } } if (war_num == 0) { condtbl[3] = false; } all_num = 0; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != ph) && (i != pa) && ((ea->treaty[i] == TREATY_ALLIANCE) || (game_num_aud_ask_break_nap && (ea->treaty[i] == TREATY_NONAGGRESSION)))) { all_tbl[all_num++] = i; } } if (all_num == 0) { condtbl[4] = false; } game_audience_choice(au, game_str_au_youprte, game_str_au_opts_treaty, condtbl, 6); selected = ui_audience_ask4(au); switch (selected) { case 0: /* Non-Aggression Pact */ si = game_ai->aud_treaty_nap(au); if ((si == 1) || (si == 2)) { si = game_audience_sweeten(au, si); } if (si == 3) { game_diplo_set_treaty(g, ph, pa, TREATY_NONAGGRESSION); } dtype = 62; break; case 1: /* Alliance */ si = game_ai->aud_treaty_alliance(au); if ((si == 1) || (si == 2)) { si = game_audience_sweeten(au, si); } if (si == 3) { game_diplo_set_treaty(g, ph, pa, TREATY_ALLIANCE); } dtype = 63; break; case 2: /* Peace Treaty */ si = game_ai->aud_treaty_peace(au); if ((si == 1) || (si == 2)) { si = game_audience_sweeten(au, si); } if (si == 3) { game_diplo_stop_war(g, ph, pa); } game_diplo_annoy(g, ph, pa, 2); dtype = 65; break; case 3: /* Declaration of War on Another Race */ dtype = 67; au->pstartwar = audience_menu_race(au, war_tbl, war_num, game_str_au_whowar); if (au->pstartwar != PLAYER_NONE) { si = game_ai->aud_treaty_declare_war(au); if ((si == 1) || (si == 2)) { si = game_audience_sweeten(au, si); } if (si == 3) { game_diplo_start_war(g, pa, au->pstartwar); } } else { selected = -1; } break; case 4: /* Break Alliance With Another Race */ dtype = 68; au->pwar = audience_menu_race(au, all_tbl, all_num, game_str_au_whobrk); if (au->pwar != PLAYER_NONE) { si = game_ai->aud_treaty_break_alliance(au); if ((si == 1) || (si == 2)) { si = game_audience_sweeten(au, si); } if (si == 3) { game_diplo_break_treaty(g, pa, au->pwar); } } else { selected = -1; } break; case 5: /* Forget It */ default: selected = -1; dtype = 0; si = 0; break; } if ((selected != -1) && (si != 1)) { game_audience_set_dtype(au, dtype, si); } } static void audience_menu_trade(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int16_t selected = 0; struct strbuild_s str = strbuild_init(au->strtbl_buf, AUDIENCE_STRTBL_BUFSIZE); au->buf = game_str_au_youprta; for (int i = 0; i < AUDIENCE_BC_MAX; ++i) { strbuild_catf(&str, "%s %i %s", game_str_au_bull, au->bctbl[i], game_str_au_bcpery); au->strtbl[i] = strbuild_finish(&str); } au->strtbl[au->num_bc] = game_str_au_opts_agree[1]; /* "Forget It" */ au->strtbl[au->num_bc + 1] = NULL; au->condtbl = NULL; selected = ui_audience_ask4(au); game_diplo_annoy(g, ph, pa, 1); eh->mood_trade[pa] -= rnd_1_n(30, &g->seed); if ((selected != -1) && (selected != au->num_bc)) { int si; au->new_trade_bc = au->bctbl[selected]; si = game_ai->aud_trade(au); if (si < 3) { si = 0; } else { game_diplo_set_trade(g, ph, pa, au->new_trade_bc); } game_audience_set_dtype(au, 64, si); } } static void audience_menu_threat(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int16_t selected = 0; bool condtbl[5]; uint8_t dtype = 0; for (int i = 0; i < TBLLEN(condtbl); ++i) { condtbl[i] = true; } if (eh->treaty[pa] != TREATY_NONAGGRESSION) { condtbl[0] = false; } if (eh->treaty[pa] != TREATY_ALLIANCE) { condtbl[1] = false; } if (eh->trade_bc[pa] == 0) { condtbl[2] = false; } game_audience_choice(au, game_str_au_youract, game_str_au_opts_threaten, condtbl, 5); au->condtbl = condtbl; selected = ui_audience_ask4(au); switch (selected) { case 0: /* Break Non-Aggression Pact */ case 1: /* Break Alliance */ game_diplo_break_treaty(g, ph, pa); dtype = 73; selected = 0; break; case 2: /* Break Trade Agreement */ game_diplo_break_trade(g, ph, pa); dtype = 73; selected = 0; break; case 3: /* Threaten To Attack */ selected = 0; dtype = game_ai->aud_threaten(au); break; default: break; } if ((g->ai_id == GAME_AI_CLASSIC) || ((selected != -1) && (selected != 4))) { game_diplo_annoy(g, ph, pa, 10); /* WASBUG MOO1 does this before the if, annoying by merely entering the menu */ } if ((selected != -1) && (selected != 4)) { game_audience_set_dtype(au, dtype, 3); } } static void audience_menu_tribute(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); empiretechorbit_t *ea = &(g->eto[pa]); int16_t selected = 0; uint8_t bcnum; uint32_t reserve = eh->reserve_bc; uint16_t bctbl[4]; struct strbuild_s strtbl_build = strbuild_init(au->strtbl_buf, AUDIENCE_STRTBL_BUFSIZE); au->buf = game_str_au_whattr; SETMIN(reserve, game_num_max_tribute_bc); reserve = ((reserve) / 25) * 25; if (reserve < 100) { bcnum = reserve / 25; bctbl[0] = 25; bctbl[1] = 50; bctbl[2] = 75; bctbl[3] = 100; } else { bcnum = 4; bctbl[0] = ((reserve / 4) / 25) * 25; bctbl[1] = ((reserve / 2) / 25) * 25; bctbl[2] = (((3 * reserve) / 4) / 25) * 25; bctbl[3] = reserve; } for (int i = 0; i < bcnum; ++i) { strbuild_catf(&strtbl_build, "%s %i %s", game_str_au_bull, bctbl[i], game_str_bc); au->strtbl[i] = strbuild_finish(&strtbl_build); } au->strtbl[bcnum] = game_str_au_techn; au->strtbl[bcnum + 1] = NULL; au->condtbl = NULL; selected = ui_audience_ask4(au); if (selected == -1) { return; } if (selected < bcnum) { eh->reserve_bc -= bctbl[selected]; ea->reserve_bc += bctbl[selected]; game_ai->aud_tribute_bc(au, selected, bctbl[selected]); game_audience_set_dtype(au, 1, 3); } else { struct spy_esp_s s[1]; s->spy = pa; s->target = ph; /* WASBUG MOO1 does game_spy_esp_sub1(g, s, tav[i], 0) where tav is a global table also used by audience_menu_tech and i is bcnum. If the tech menu is never visited or the table is not filled up to bcnum then the value is 0. Values larger than 0 only filter out tech of lesser worth, and who would not want to use those as bribes? */ if (game_spy_esp_sub1(g, s, 0, 0) > 0) { int num_techs = MIN(s->tnum, 4); game_audience_tech_choice(au, game_str_au_whattr, s->tbl_field, s->tbl_tech2, num_techs, true); selected = ui_audience_ask4(au); if ((selected != -1) && (selected < s->tnum) && (selected < 4)) { game_tech_get_new(g, pa, s->tbl_field[selected], s->tbl_tech2[selected], TECHSOURCE_TRADE, ph, PLAYER_NONE, false); game_ai->aud_tribute_tech(au, selected, s->tbl_field[selected], s->tbl_tech2[selected]); eh->tribute_field[pa] = s->tbl_field[selected]; eh->tribute_tech[pa] = s->tbl_tech2[selected]; game_audience_set_dtype(au, 1, 3); } } else { game_audience_set_dtype(au, 75, 3); } } } static void audience_menu_tech(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); int v = game_ai->aud_tech_scale(au); { struct spy_esp_s s[1]; tech_field_t taf[TECH_SPY_MAX]; /* diplo_p2_sub1_field */ uint8_t tat[TECH_SPY_MAX]; int tav[TECH_SPY_MAX]; tech_field_t thf[TECH_SPY_MAX][TECH_SPY_MAX]; uint8_t tht[TECH_SPY_MAX][TECH_SPY_MAX]; tech_field_t thaf[TECH_SPY_MAX * TECH_SPY_MAX]; uint8_t that[TECH_SPY_MAX * TECH_SPY_MAX]; int tanum, thnum[TECH_SPY_MAX], total_thnum; s->spy = ph; s->target = pa; if (game_spy_esp_sub1(g, s, 0, 1) > 0) { tanum = s->tnum; for (int i = 0; i < tanum; ++i) { taf[i] = s->tbl_field[i]; tat[i] = s->tbl_tech2[i]; tav[i] = (s->tbl_value[i] * v) / 100; } s->spy = pa; s->target = ph; total_thnum = 0; for (int i = 0; i < tanum; ++i) { if (game_spy_esp_sub1(g, s, tav[i], 0) > 0) { int n; n = s->tnum; thnum[total_thnum] = n; for (int j = 0; j < n; ++j) { thf[total_thnum][j] = s->tbl_field[j]; tht[total_thnum][j] = s->tbl_tech2[j]; } thaf[total_thnum] = taf[i]; that[total_thnum] = tat[i]; ++total_thnum; } } /*6568e*/ if (total_thnum > 0) { int16_t selected = 0; int num_techs = MIN(total_thnum, 5); game_diplo_annoy(g, ph, pa, 1); eh->mood_tech[pa] -= rnd_1_n(50, &g->seed) + 20; game_audience_tech_choice(au, game_str_au_whatech, thaf, that, num_techs, false); selected = ui_audience_ask4(au); /*65724*/ if (selected != -1) { tech_field_t gotf = thaf[selected]; uint8_t gott = that[selected]; int selected2 = selected; int num_techs = MIN(thnum[selected2], 4); game_audience_tech_choice(au, game_str_au_whatrad, thf[selected2], tht[selected2], num_techs, true); selected = ui_audience_ask4(au); if ((selected != -1) && (selected < num_techs)) { g->evn.newtech[ph].num = 0; g->evn.newtech[pa].num = 0; game_tech_get_new(g, ph, gotf, gott, TECHSOURCE_TRADE, pa, PLAYER_NONE, false); game_tech_get_new(g, pa, thf[selected2][selected], tht[selected2][selected], TECHSOURCE_TRADE, ph, PLAYER_NONE, false); /* WASBUG last ph was pa */ if (g->evn.newtech[ph].num != 0) { if (IS_HUMAN(g, pa) && (g->evn.newtech[pa].num != 0)) { game_tech_finish_new(au->g, pa); game_tech_finish_new(au->g, ph); ui_audience_newtech(au, PLAYER_NONE); } else { game_tech_finish_new(au->g, ph); ui_audience_newtech(au, ph); } } else if (IS_HUMAN(g, pa) && (g->evn.newtech[pa].num != 0)) { game_tech_finish_new(au->g, pa); ui_audience_newtech(au, pa); } } } } else { game_audience_set_dtype(au, 75, 3); } } else { game_audience_set_dtype(au, 75, 3); } } game_diplo_annoy(g, ph, pa, 3); SETMIN(eh->mood_tech[pa], 50); } static void audience_menu_main(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); bool flag_done = false; bool condtbl[6]; while (!flag_done) { int16_t selected; for (int i = 0; i < TBLLEN(condtbl); ++i) { condtbl[i] = true; } if (eh->treaty[pa] >= TREATY_WAR) { condtbl[1] = false; condtbl[2] = false; condtbl[4] = false; } { struct spy_esp_s s[1]; s->spy = pa; s->target = ph; if ((eh->reserve_bc < 25) && (game_spy_esp_sub1(g, s, 0, 0) == 0)) { condtbl[3] = false; } } { int prod, want_trade, cur_trade = eh->trade_bc[pa]; prod = MIN(eh->total_production_bc, g->eto[pa].total_production_bc) / 4; SETMIN(prod, 32000); want_trade = (prod / 25) * 25 - cur_trade; if (want_trade <= 0) { condtbl[1] = false; } else if (want_trade < 125) { au->num_bc = want_trade / 25; au->bctbl[0] = cur_trade + 25; au->bctbl[1] = cur_trade + 50; au->bctbl[2] = cur_trade + 75; au->bctbl[3] = cur_trade + 100; } else { au->num_bc = AUDIENCE_BC_MAX; au->bctbl[0] = want_trade / 5 + cur_trade; au->bctbl[1] = (((want_trade * 2) / 5) / 25) * 25 + cur_trade; au->bctbl[2] = (((want_trade * 3) / 5) / 25) * 25 + cur_trade; au->bctbl[3] = (((want_trade * 4) / 5) / 25) * 25 + cur_trade; au->bctbl[4] = want_trade + cur_trade; } } if (game_ai->aud_later(au)) { game_audience_set_dtype(au, 74, 3); break; } game_audience_choice(au, game_str_au_howmay, game_str_au_opts_main, condtbl, 6); selected = ui_audience_ask4(au); switch (selected) { case 0: /* Propose Treaty */ audience_menu_treaty(au); break; case 1: /* Form Trade Agreement */ audience_menu_trade(au); break; case 2: /* Threaten/Break Treaty and Trade */ audience_menu_threat(au); break; case 3: /* Offer Tribute */ audience_menu_tribute(au); break; case 4: /* Exchange Technology */ audience_menu_tech(au); break; default: case -1: case 5: /* Good Bye */ flag_done = true; break; } } } static void game_audience_do(struct audience_s *au) { struct game_s *g = au->g; player_id_t ph = au->ph, pa = au->pa; empiretechorbit_t *eh = &(g->eto[ph]); if ((au->mode >= 0) && (au->mode <= 2)) { /* Greeting */ g->evn.diplo_msg_subtype = -1; game_audience_get_diplo_msg(au); ui_audience_show1(au); } switch (au->mode) { case 2: /* AI initiated audience. */ if (game_audience_check_alliances(au)) { au->dtype = au->dtype_next; g->evn.diplo_msg_subtype = -1; game_audience_get_diplo_msg(au); switch (au->dtype) { case 28: game_audience_ai_offers_bounty(au); break; case 58: game_audience_ai_pays_bounty(au); break; case 29: game_audience_ai_offers_tech_trade(au); break; default: game_audience_ai_offers_treaty(au); break; } } /*607a9*/ /* After offering a deal, the AI becomes less likely to accept or * propose similar deals in the near future, independent of the * player's response. This even happens when the player didn't see * the actual offer because they're allied with one of the AI's * enemies, so we cannot do it in the game_audience_ai_offers_* * functions. */ game_diplo_annoy(g, ph, pa, 1); if ((au->dtype == 24) || (au->dtype == 25)) { eh->mood_treaty[pa] -= rnd_1_n(30, &g->seed) + 20; } if (au->dtype == 26) { eh->mood_trade[pa] -= rnd_1_n(30, &g->seed) + 20; } if (au->dtype == 30) { eh->mood_peace[pa] -= rnd_1_n(50, &g->seed) + 50; } if (au->dtype == 29) { eh->mood_tech[pa] -= rnd_1_n(30, &g->seed) + 20; } break; case 6: /* Single message from the AI, no player response. */ game_audience_set_dtype(au, au->dtype, 3); break; case 0: /* Player initiated audience. */ audience_menu_main(au); break; default: break; } } /* -------------------------------------------------------------------------- */ void game_audience(struct game_s *g, player_id_t ph, player_id_t pa) { struct audience_s au[1]; empiretechorbit_t *eh = &(g->eto[ph]); au->g = g; game_diplo_limit_mood_treaty(g); game_audience_prepare(au, ph, pa); ui_audience_start(au); au->mode = 6; au->dtype = eh->diplo_type[pa]; if ((au->dtype == 66) || (au->dtype == 1)) { /* FIXME BUG? no ui_audience_end call after _start */ ui_audience_end(au); return; } if (au->dtype == 0) { game_audience_start_human(au); } g->evn.diplo_msg_subtype = -1; if (((au->dtype >= 24) && (au->dtype <= 30)) || (au->dtype == 58) || (au->dtype == 76)) { au->dtype_next = au->dtype; au->dtype = 22; au->mode = 2; au->pwar = eh->au_ally_attacker[pa]; } game_audience_do(au); ui_audience_end(au); if (au->dtype == 32) { game_diplo_break_treaty(g, pa, ph); } if (game_num_aud_update_tech) { game_update_tech_util(g); game_update_within_range(g); game_update_visibility(g); } } 1oom-1.11.2/src/game/game_audience.h000066400000000000000000000017671476061725400171150ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_AUDIENCE_H #define INC_1OOM_GAME_AUDIENCE_H #include "game_types.h" struct game_s; #define AUDIENCE_STR_MAX 7 #define AUDIENCE_BC_MAX 5 #define AUDIENCE_DIPLO_MSG_SIZE 320 #define AUDIENCE_STRTBL_BUFSIZE 640 #define AUDIENCE_BUF2_POS 320 #define AUDIENCE_CBUF_POS 640 struct audience_s { struct game_s *g; void *uictx; const char *buf; char diplo_msg[AUDIENCE_DIPLO_MSG_SIZE]; player_id_t ph; player_id_t pa; player_id_t pwar; player_id_t pstartwar; uint8_t mode; /*0,1,2,6*/ uint8_t dtype; uint8_t dtype_next; uint8_t gfxi; /*0..2*/ uint8_t musi; /*0..2*/ uint8_t num_bc; /*0..5*/ int new_trade_bc; int16_t tribute_bc; tech_field_t tribute_field; uint8_t tribute_tech; char strtbl_buf[AUDIENCE_STRTBL_BUFSIZE]; const char *strtbl[AUDIENCE_STR_MAX]; const bool *condtbl; uint16_t bctbl[AUDIENCE_BC_MAX]; }; extern void game_audience(struct game_s *g, player_id_t ph, player_id_t pa); #endif 1oom-1.11.2/src/game/game_aux.c000066400000000000000000000126311476061725400161200ustar00rootroot00000000000000#include "config.h" #include "game_aux.h" #include "bits.h" #include "game.h" #include "lbx.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ static void init_star_dist(struct game_aux_s *gaux, struct game_s *g) { int stars = g->galaxy_stars; for (int i = 0; i < stars; ++i) { gaux->star_dist[i][i] = 0; for (int j = i + 1; j < stars; ++j) { uint8_t dist; dist = (uint8_t)util_math_dist_steps(g->planet[i].x, g->planet[i].y, g->planet[j].x, g->planet[j].y); gaux->star_dist[i][j] = dist; gaux->star_dist[j][i] = dist; #ifdef FEATURE_MODEBUG if (dist == 0) { LOG_DEBUG((0, "%s: dist %i (%i,%i -> %i, %i)\n", __func__, dist, g->planet[i].x, g->planet[i].y, g->planet[j].x, g->planet[j].y)); } #endif } } } static void check_lbx_t5(const uint8_t *t, const char *lbxname, uint16_t want_num, uint16_t want_size) { uint16_t num, size; num = GET_LE_16(t); t += 2; size = GET_LE_16(t); if (num != want_num) { log_fatal_and_die("%s.lbx: expected %i entries, got %i!\n", lbxname, want_num, num); } if (size != want_size) { log_fatal_and_die("%s.lbx: expected size %i, got %i!\n", lbxname, want_size, size); } } /* -------------------------------------------------------------------------- */ int game_aux_init(struct game_aux_s *gaux, struct game_s *g) { uint8_t *data, *t; memset(g, 0, sizeof(struct game_s)); g->gaux = gaux; t = lbxfile_item_get(LBXFILE_RESEARCH, 0); gaux->research.d0 = t + 4; t = lbxfile_item_get(LBXFILE_RESEARCH, 1); gaux->research.names = (char *)t + 4; t = lbxfile_item_get(LBXFILE_RESEARCH, 2); gaux->research.descr = (char *)t + 4; /* TODO check num/size*/ t = lbxfile_item_get(LBXFILE_DIPLOMAT, 1); check_lbx_t5(t, "diplomat", DIPLOMAT_MSG_NUM, DIPLOMAT_MSG_LEN); gaux->diplomat.msg = (const char *)(t + 4); data = t = lbxfile_item_get(LBXFILE_DIPLOMAT, 0); check_lbx_t5(data, "diplomat", DIPLOMAT_D0_NUM, 2); t += 4; for (int i = 0; i < DIPLOMAT_D0_NUM; ++i, t += 2) { gaux->diplomat.d0[i] = GET_LE_16(t); /* all values < 0x10 */ } lbxfile_item_release(LBXFILE_DIPLOMAT, data); data = t = lbxfile_item_get(LBXFILE_FIRING, 0); check_lbx_t5(data, "firing", NUM_SHIPLOOKS, 0x1c); t += 4; for (int j = 0; j < NUM_SHIPLOOKS; ++j) { for (int i = 0; i < 12; ++i, t += 2) { gaux->firing[j].d0[i] = GET_LE_16(t); /* all values < 0x20 */ } gaux->firing[j].target_x = GET_LE_16(t); /* all values < 0x20 */ t += 2; gaux->firing[j].target_y = GET_LE_16(t); /* all values < 0x20 */ t += 2; } lbxfile_item_release(LBXFILE_FIRING, data); t = lbxfile_item_get(LBXFILE_EVENTMSG, 0); check_lbx_t5(t, "eventmsg", EVENTMSG_NUM, EVENTMSG_LEN); gaux->eventmsg = (const char *)(t + 4); gaux->move_temp = 0; gaux->savenamebuflen = FSDEV_PATH_MAX; gaux->savenamebuf = lib_malloc(gaux->savenamebuflen); gaux->savebuflen = sizeof(struct game_s) + 64; gaux->savebuf = lib_malloc(gaux->savebuflen); gaux->flag_cheat_galaxy = false; gaux->flag_cheat_elections = false; gaux->flag_cheat_events = false; gaux->flag_cheat_spy_hint = false; gaux->flag_cheat_stars = false; gaux->flag_cheat_tech_hint = false; gaux->initialized = true; return 0; } void game_aux_shutdown(struct game_aux_s *gaux) { if (gaux->initialized) { lbxfile_item_release_file(LBXFILE_RESEARCH); lbxfile_item_release_file(LBXFILE_EVENTMSG); lbxfile_item_release_file(LBXFILE_DIPLOMAT); if (gaux->move_temp) { lib_free(gaux->move_temp); gaux->move_temp = 0; } lib_free(gaux->savenamebuf); gaux->savenamebuf = 0; lib_free(gaux->savebuf); gaux->savebuf = 0; } } uint8_t game_aux_get_firing_param_x(const struct game_aux_s *gaux, uint8_t look, uint8_t a2, bool dir) { const uint8_t *f = &(gaux->firing[look].d0[0]); if (!dir) { if (a2 == 1) { return f[2]; } else if (a2 == 2) { return f[4]; } else /*if (a2 == 3)*/ { return f[0]; } } else { if (a2 == 1) { return f[8]; } else if (a2 == 2) { return f[10]; } else /*if (a2 == 3)*/ { return f[6]; } } } uint8_t game_aux_get_firing_param_y(const struct game_aux_s *gaux, uint8_t look, uint8_t a2, bool dir) { const uint8_t *f = &(gaux->firing[look].d0[0]); if (!dir) { if (a2 == 1) { return f[3]; } else if (a2 == 2) { return f[5]; } else /*if (a2 == 3)*/ { return f[1]; } } else { if (a2 == 1) { return f[9]; } else if (a2 == 2) { return f[11]; } else /*if (a2 == 3)*/ { return f[7]; } } } void game_aux_start(struct game_aux_s *gaux, struct game_s *g) { int n = 0; g->gaux = gaux; init_star_dist(gaux, g); for (int i = 0; i < g->players; ++i) { if (BOOLVEC_IS0(g->is_ai, i)) { ++n; } } gaux->local_players = n; if ((n > 1) && !gaux->move_temp) { gaux->move_temp = lib_malloc(sizeof(*gaux->move_temp)); } } 1oom-1.11.2/src/game/game_aux.h000066400000000000000000000046121476061725400161250ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_AUX_H #define INC_1OOM_GAME_AUX_H #include "game.h" #include "game_planet.h" #include "types.h" #define NUM_SHIPLOOKS 0x93 #define DIPLOMAT_D0_NUM 0x51 #define DIPLOMAT_MSG_NUM 1215 #define DIPLOMAT_MSG_LEN 0xc8 #define DIPLOMAT_MSG_PTR(ga_, r_, t_) (&((ga_)->diplomat.msg[((t_) * 15 + (r_)) * DIPLOMAT_MSG_LEN])) #define DIPLOMAT_MSG_GFX(p_) ((p_)[0xc4]) #define DIPLOMAT_MSG_MUS(p_) ((p_)[0xc6]) #define RESEARCH_DESCR_LEN 0xc3 #define EVENTMSG_TYPE_NUM 22 #define EVENTMSG_SUB_NUM 7 #define EVENTMSG_NUM (EVENTMSG_TYPE_NUM * EVENTMSG_SUB_NUM) #define EVENTMSG_LEN 0xc8 #define EVENTMSG_PTR(ga_, t_, s_) (&((ga_)->eventmsg[((t_ - 1) * 7 + (s_)) * EVENTMSG_LEN])) /* Storage for repeated movement in local multiplayer */ struct game_move_aux_s { fleet_enroute_t enroute[FLEET_ENROUTE_MAX]; transport_t transport[TRANSPORT_MAX]; monster_t crystal; monster_t amoeba; }; struct firing_s { uint8_t d0[12]; /* uint16_t in lbx */ uint8_t target_x; uint8_t target_y; }; /* Aux game data, not stored in saves. */ struct game_aux_s { struct { const uint8_t *d0; /*[TECH_FIELD_NUM * 50 * 6]*/ const char *names; /* tech names, "foo\0bar\0" etc */ const char *descr; /*[TECH_FIELD_NUM * 50 * RESEARCH_DESCR_LEN] tech descriptions */ } research; struct { uint8_t d0[DIPLOMAT_D0_NUM]; /* uint16_t in lbx */ const char *msg; } diplomat; struct firing_s firing[NUM_SHIPLOOKS]; const char *eventmsg; uint8_t star_dist[PLANETS_MAX][PLANETS_MAX]; struct game_move_aux_s *move_temp; player_id_t human_killer; /* used for funeral ending */ int local_players; bool flag_cheat_galaxy; bool flag_cheat_elections; bool flag_cheat_events; bool flag_cheat_spy_hint; bool flag_cheat_stars; bool flag_cheat_tech_hint; bool initialized; int savenamebuflen; int savebuflen; char *savenamebuf; uint8_t *savebuf; }; extern int game_aux_init(struct game_aux_s *gaux, struct game_s *g); extern void game_aux_shutdown(struct game_aux_s *gaux); extern uint8_t game_aux_get_firing_param_x(const struct game_aux_s *gaux, uint8_t look, uint8_t a2, bool dir); extern uint8_t game_aux_get_firing_param_y(const struct game_aux_s *gaux, uint8_t look, uint8_t a2, bool dir); struct game_s; extern void game_aux_start(struct game_aux_s *gaux, struct game_s *g); #endif 1oom-1.11.2/src/game/game_battle.c000066400000000000000000000407661476061725400166100ustar00rootroot00000000000000#include "config.h" #include #include "game_battle.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_battle_human.h" #include "game_diplo.h" #include "game_fleet.h" #include "game_num.h" #include "game_parsed.h" #include "game_str.h" #include "lib.h" #include "log.h" #include "types.h" #include "ui.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ #define PARTY_NUM ((int)PLAYER_NUM + (int)MONSTER_NUM) #define COPY_PROP(bi_, sp_, xyz_) bi_->xyz_ = sp->xyz_ #define COPY_BOOL_TO_INT(b_, i_, f_) b_->i_ = (b_->sbmask & (1 << SHIP_SPECIAL_BOOL_##f_)) ? 1 : 0 /* -------------------------------------------------------------------------- */ static void game_battle_item_from_parsed(struct battle_item_s *b, const shipparsed_t *sp) { memset(b, 0, sizeof(*b)); COPY_PROP(b, sp, look); lib_strcpy(b->name, sp->name, SHIP_NAME_LEN); COPY_PROP(b, sp, hull); for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { b->special[i] = sp->special[i]; } COPY_PROP(b, sp, repair); COPY_PROP(b, sp, misshield); COPY_PROP(b, sp, look); COPY_PROP(b, sp, pulsar); COPY_PROP(b, sp, stream); COPY_PROP(b, sp, pshield); COPY_PROP(b, sp, sbmask); COPY_PROP(b, sp, extrarange); COPY_PROP(b, sp, num); COPY_PROP(b, sp, complevel); COPY_PROP(b, sp, defense); COPY_PROP(b, sp, misdefense); b->hp1 = sp->hp; b->hp2 = sp->hp; COPY_PROP(b, sp, absorb); COPY_PROP(b, sp, man); for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { b->wpn[i].t = sp->wpnt[i]; b->wpn[i].n = sp->wpnn[i]; } COPY_BOOL_TO_INT(b, stasis, STASIS); COPY_BOOL_TO_INT(b, subspace, SUBSPACE); COPY_BOOL_TO_INT(b, blackhole, BLACKHOLE); COPY_BOOL_TO_INT(b, warpdis, WARPDIS); COPY_BOOL_TO_INT(b, technull, TECHNULL); COPY_BOOL_TO_INT(b, repulsor, REPULSOR); COPY_BOOL_TO_INT(b, cloak, CLOAK); } static void game_battle_item_add(struct battle_s *bt, const shipparsed_t *sp, battle_side_i_t side) { struct battle_item_s *b; int itemi, shiptbli; switch (side) { default: case SIDE_NONE/*planet*/: itemi = shiptbli = 0; b = &(bt->item[itemi]); game_battle_item_from_parsed(b, sp); b->absorb += b->pshield; b->wpn[0].numshots = -1; b->wpn[1].numshots = -1; if (bt->bases == 0) { b->wpn[0].t = 0; b->wpn[0].n = 0; } b->gfx = ui_gfx_get_planet(b->look); break; case SIDE_L: itemi = ++bt->s[SIDE_L].items; b = &(bt->item[itemi]); shiptbli = itemi - 1; break; case SIDE_R: itemi = ++bt->s[SIDE_R].items + bt->s[SIDE_L].items; b = &(bt->item[itemi]); shiptbli = bt->s[SIDE_R].items - 1; break; } if (side != SIDE_NONE/*planet*/) { game_battle_item_from_parsed(b, sp); if (b->sbmask & (1 << SHIP_SPECIAL_BOOL_SCANNER)) { bt->s[side].flag_have_scan = true; } b->side = side; b->gfx = ui_gfx_get_ship(b->look); b->shiptbli = shiptbli; } } static void game_battle_post(struct game_s *g, int loser, int winner, uint8_t from) { if (loser >= PLAYER_NUM) { monster_id_t mi; mi = loser - PLAYER_NUM; switch (mi) { case MONSTER_CRYSTAL: g->evn.crystal.killer = winner; break; case MONSTER_AMOEBA: g->evn.amoeba.killer = winner; break; case MONSTER_GUARDIAN: g->evn.have_guardian = false; g->guardian_killer = winner; break; default: break; } } else { empiretechorbit_t *e = &(g->eto[loser]); fleet_orbit_t *o = &(e->orbit[from]); const planet_t *pf = &g->planet[from]; uint8_t dest = PLANET_NONE; int mindist = 10000; shipcount_t ships[NUM_SHIPDESIGNS]; uint8_t shiptypes[NUM_SHIPDESIGNS]; uint8_t numtypes = e->shipdesigns_num; for (int i = 0; i < numtypes; ++i) { shiptypes[i] = i; ships[i] = o->ships[i]; } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *pt = &g->planet[i]; if ((i != from) && (pt->owner == loser)) { int dist; dist = util_math_dist_fast(pf->x, pf->y, pt->x, pt->y); if (dist < mindist) { mindist = dist; dest = i; } } } if ((dest != PLANET_NONE) /*&& (numtypes > 0)*/) { game_send_fleet_retreat(g, loser, from, dest, ships, shiptypes, numtypes); } for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { o->ships[i] = 0; } } } static void game_battle_prepare_p1(struct battle_s *bt, battle_side_i_t side, uint8_t planet_i) { const struct game_s *g = bt->g; const empiretechorbit_t *e = &(g->eto[bt->s[side].party]); const shipdesign_t *sd = &(g->srd[bt->s[side].party].design[0]); bt->s[side].apparent_force = 0; for (int i = 0; i < e->shipdesigns_num; ++i) { bt->s[side].apparent_force += (sd[i].hull + 1) * e->orbit[planet_i].ships[i]; } bt->s[side].race = e->race; } static void game_battle_prepare_add_ships(struct battle_s *bt, battle_side_i_t side, uint8_t planet_i) { const struct game_s *g = bt->g; const empiretechorbit_t *e = &(g->eto[bt->s[side].party]); const shipdesign_t *sd = &(g->srd[bt->s[side].party].design[0]); bool flag_shield_disable = (g->planet[planet_i].battlebg == 0); shipparsed_t sp[1]; int num_types = 0; for (int i = 0; i < e->shipdesigns_num; ++i) { shipcount_t s; s = e->orbit[planet_i].ships[i]; if (s > 0) { bt->s[side].tbl_ships[num_types] = s; bt->s[side].tbl_shiptype[num_types] = i; game_parsed_from_design(sp, &sd[i], s); if (bt->s[side].race == RACE_MRRSHAN) { sp->complevel += 4; } if (bt->s[side].race == RACE_ALKARI) { sp->defense += 3; sp->misdefense += 3; } if (flag_shield_disable) { sp->pshield = 0; sp->absorb = 0; sp->shield = 0; } game_battle_item_add(bt, sp, side); ++num_types; } } bt->s[side].num_types = num_types; bt->s[side].flag_human = IS_HUMAN(g, bt->s[side].party); bt->s[side].flag_auto = !bt->s[side].flag_human; } /* -------------------------------------------------------------------------- */ void game_battle_prepare(struct battle_s *bt, int party_r, int party_l, uint8_t planet_i) { struct game_s *g = bt->g; const planet_t *p = &(g->planet[planet_i]); shipparsed_t sp[1]; { bool t = bt->flag_human_att; memset(bt, 0, sizeof(*bt)); bt->flag_human_att = t; } bt->g = g; bt->s[SIDE_R].party = party_r; bt->s[SIDE_L].party = party_l; bt->planet_i = planet_i; bt->pop = p->pop; bt->fact = p->factories; game_battle_prepare_p1(bt, SIDE_L, planet_i); if (party_r < PLAYER_NUM) { game_battle_prepare_p1(bt, SIDE_R, planet_i); } else { bt->s[SIDE_R].apparent_force = 1; bt->s[SIDE_R].race = RACE_NUM/*monster*/; bt->s[SIDE_R].flag_human = false; bt->s[SIDE_R].flag_auto = 1; } { player_id_t owner; owner = p->owner; if ((owner != PLAYER_NONE) && ((owner == party_l) || (owner == party_r))) { bt->planet_side = (owner == party_l) ? SIDE_L : SIDE_R; bt->bases = p->missile_bases; game_parsed_from_planet(sp, g, p); game_battle_item_add(bt, sp, SIDE_NONE/*planet*/); } else { bt->planet_side = SIDE_NONE; } } game_battle_prepare_add_ships(bt, SIDE_L, planet_i); if (party_r >= PLAYER_NUM) { monster_id_t mi; mi = party_r - PLAYER_NUM; memcpy(sp, &tbl_monster[mi][g->difficulty], sizeof(*sp)); strncpy(sp->name, game_str_tbl_monsh_names[mi], SHIP_NAME_LEN); sp->name[SHIP_NAME_LEN - 1] = 0; game_battle_item_add(bt, sp, SIDE_R); bt->s[SIDE_R].num_types = 1; /* BUG? these were uninitialized */ bt->s[SIDE_R].tbl_ships[0] = 1; bt->s[SIDE_R].tbl_shiptype[0] = 0; } else { game_battle_prepare_add_ships(bt, SIDE_R, planet_i); } } void game_battle_handle_all(struct game_s *g) { struct battle_s bt[1]; uint8_t monster_planet[MONSTER_NUM]; bt->g = g; for (monster_id_t i = 0; i < MONSTER_NUM; ++i) { monster_planet[i] = PLANET_NONE; } for (monster_id_t i = MONSTER_CRYSTAL; i <= MONSTER_AMOEBA; ++i) { const monster_t *m; m = (i == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists) { const planet_t *p; p = &(g->planet[m->dest]); if ((m->x == p->x) && (m->y == p->y)) { monster_planet[i] = m->dest; } } } if (g->evn.have_guardian) { monster_planet[MONSTER_GUARDIAN] = g->evn.planet_orion_i; } /* FIXME refactor this so that human/AI conflicts can be resolved in parallel in (non-local) multiplayer */ for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); player_id_t owner; int sum_forces; BOOLVEC_DECLARE(tbl_have_force, PARTY_NUM); BOOLVEC_CLEAR(tbl_have_force, PARTY_NUM); owner = p->owner; for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); if ((owner == i) && (p->missile_bases > 0)) { BOOLVEC_SET1(tbl_have_force, i); } else { for (int j = 0; j < e->shipdesigns_num; ++j) { if (e->orbit[pli].ships[j] > 0) { BOOLVEC_SET1(tbl_have_force, i); break; } } } } for (monster_id_t i = MONSTER_CRYSTAL; i < MONSTER_NUM; ++i) { if (pli == monster_planet[i]) { BOOLVEC_SET1(tbl_have_force, (int)PLAYER_NUM + i); } else if (game_num_monster_rest_att && (i != MONSTER_GUARDIAN)) { /* 1oom option: allow fighting resting monsters */ const monster_t *m; m = (i == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if ((m->counter >= 0) && (m->x == p->x) && (m->y == p->y)) { BOOLVEC_SET1(tbl_have_force, (int)PLAYER_NUM + i); } } } sum_forces = 0; for (int i = 0; i < PARTY_NUM; ++i) { if (BOOLVEC_IS1(tbl_have_force, i)) { ++sum_forces; } } while (sum_forces > 1) { int tbl_party[PARTY_NUM]; int num_party, party_def, party_att; empiretechorbit_t *e; num_party = 0; tbl_party[0] = -1; if ((owner != PLAYER_NONE) && BOOLVEC_IS1(tbl_have_force, owner)) { tbl_party[0] = owner; num_party = 1; } for (int i = 0; i < PARTY_NUM; ++i) { if ((i != tbl_party[0]) && BOOLVEC_IS1(tbl_have_force, i)) { tbl_party[num_party++] = i; } } party_def = tbl_party[0]; if ((num_party < 2) || (party_def >= PLAYER_NUM)) { break; } e = &(g->eto[party_def]); party_att = tbl_party[1]; if ((party_att < PLAYER_NUM) && ((e->treaty[party_att] == TREATY_ALLIANCE) || ((e->treaty[party_att] == TREATY_NONAGGRESSION) && (party_def != owner))) ) { /* TODO BUG? the scenario of owner dying to attacker and an alliance partner not doing anything afterwards on the same turn could be fixed */ BOOLVEC_SET0(tbl_have_force, party_att); } else { if (!IS_HUMAN(g, party_def) && !IS_HUMAN(g, party_att)) { game_battle_prepare(bt, party_att, party_def, pli); if (game_ai->battle_ai_ai_resolve(bt)) { /* HACK _att won, swap variables */ int t = party_def; party_def = party_att; party_att = t; } /* _def won */ BOOLVEC_SET0(tbl_have_force, party_att); game_battle_post(g, party_att, party_def, pli); } else { /*11926*/ /* BUG? first check not in MOO1, reads past table if monster */ if ((party_att < PLAYER_NUM) && IS_AI(g, party_att) && (g->evn.ceasefire[party_def][party_att] > 0)) { BOOLVEC_SET0(tbl_have_force, party_att); game_battle_post(g, party_att, party_def, pli); } else { /*1195f*/ int party_l, party_r; if (IS_HUMAN(g, party_def)) { party_l = party_def; party_r = party_att; bt->flag_human_att = false; } else { party_l = party_att; party_r = party_def; bt->flag_human_att = true; } game_battle_prepare(bt, party_r, party_l, pli); if (game_battle_with_human(bt)) { /* HACK _r won, swap variables */ int t = party_r; party_r = party_l; party_l = t; } /* _l won */ BOOLVEC_SET0(tbl_have_force, party_r); game_battle_post(g, party_r, party_l, pli); /*v14 = 1;*/ } } } /*119eb*/ sum_forces = 0; for (int i = 0; i < PARTY_NUM; ++i) { if (BOOLVEC_IS1(tbl_have_force, i)) { ++sum_forces; } } } } } void game_battle_finish(struct battle_s *bt) { struct game_s *g = bt->g; planet_t *p = &(g->planet[bt->planet_i]); if (bt->planet_side != SIDE_NONE) { p->max_pop3 -= bt->biodamage; SETMAX(p->max_pop3, 10); p->missile_bases = bt->bases; if ((p->pop == 0) && (bt->s[SIDE_R].party < PLAYER_NUM)) { game_planet_destroy(g, bt->planet_i, bt->s[SIDE_R].party); } } for (battle_side_i_t side = SIDE_L; side <= SIDE_R; ++side) { if (bt->s[side].party < PLAYER_NUM) { empiretechorbit_t *e = &(g->eto[bt->s[side].party]); const shipdesign_t *sd = &(g->srd[bt->s[side].party].design[0]); shipcount_t *os = &(e->orbit[bt->planet_i].ships[0]); for (int i = 0; i < bt->s[side].num_types; ++i) { uint8_t st; shipcount_t n; st = bt->s[side].tbl_shiptype[i]; n = bt->s[side].tbl_ships[i]; os[st] = n; bt->s[side].apparent_force -= (sd[st].hull + 1) * n; } } } game_diplo_battle_finish(g, bt->s[SIDE_L].party, bt->s[SIDE_R].party, bt->pop - p->pop, bt->s[SIDE_L].apparent_force, bt->biodamage, bt->s[SIDE_R].apparent_force, bt->planet_i); } void game_battle_count_hulls(const struct battle_s *bt, shipsum_t force[2][SHIP_HULL_NUM]) { const struct game_s *g = bt->g; for (int s = 0; s < 2; ++s) { int party = bt->s[s].party; for (ship_hull_t h = 0; h < SHIP_HULL_NUM; ++h) { force[s][h] = 0; } if (party < PLAYER_NUM) { const shipcount_t *ships; const shipdesign_t *sd; sd = &(g->srd[party].design[0]); ships = &(g->eto[party].orbit[bt->planet_i].ships[0]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { shipcount_t n; n = ships[i]; if (n) { force[s][sd[i].hull] += n; } } } else { const struct battle_item_s *b = &(bt->item[bt->s[SIDE_L].items + 1]); force[s][b->hull] += b->num; } } } 1oom-1.11.2/src/game/game_battle.h000066400000000000000000000077071476061725400166130ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_BATTLE_H #define INC_1OOM_GAME_BATTLE_H #include "game_design.h" #include "game_shiptech.h" #include "game_types.h" #include "types.h" struct game_s; struct game_aux_s; #define BATTLE_AREA_W 10 #define BATTLE_AREA_H 8 typedef enum { SIDE_L, SIDE_R, SIDE_NONE } battle_side_i_t; struct battle_item_s { uint8_t *gfx; char name[SHIP_NAME_LEN]; uint8_t shiptbli; int8_t complevel; ship_special_t special[SPECIAL_SLOT_NUM]; uint16_t hp1; uint16_t hp2; ship_hull_t hull; uint8_t man; int8_t defense; int8_t misdefense; uint8_t absorb; uint8_t repair; uint8_t misshield; uint8_t pshield; uint8_t extrarange; shipcount_t num; uint8_t look; int8_t pulsar; /* temporarily used as antidote for planets */ int8_t stream; int8_t stasis; int8_t cloak; int8_t subspace; int8_t warpdis; int8_t blackhole; int8_t technull; int8_t repulsor; uint16_t sbmask; uint8_t retreat; int8_t sx; /* -1, 0..BATTLE_AREA_W - 1 */ int8_t sy; /* -1, 0..BATTLE_AREA_H - 1 */ uint8_t selected; /* 0, 1, 2=moving */ uint8_t stasisby; uint8_t unman; bool can_retaliate; battle_side_i_t side; int8_t actman; uint16_t hploss; int8_t maxrange; int8_t missile; /* -1=none, 0=disabled, 1=enabled */ struct { weapon_t t; uint8_t n; int8_t numfire; int8_t numshots; } wpn[WEAPON_SLOT_NUM]; }; #define BATTLE_ROCK_MAX 7 struct battle_rock_s { int8_t sx; /* -1, 0..9 */ int8_t sy; /* -1, 0..9 */ uint8_t *gfx; }; #define BATTLE_MISSILE_MAX 30 #define MISSILE_TARGET_NONE -1 struct battle_missile_s { weapon_t wpnt; uint16_t nummissiles; uint16_t damagemul2; int16_t x; int16_t y; int8_t source; /* item index */ int8_t target; /* item index or MISSILE_TARGET_NONE */ uint8_t fuel; uint8_t speed; }; struct battle_side_s { int party; race_t race; shipcount_t tbl_ships[NUM_SHIPDESIGNS]; uint8_t tbl_shiptype[NUM_SHIPDESIGNS]; uint8_t num_types; uint8_t items; /* not counting planet */ uint32_t apparent_force; bool flag_have_scan; bool flag_base_missile; bool flag_human; int16_t flag_auto; /* HACK type is for uiobj */ }; #define BATTLE_ITEM_MAX (NUM_SHIPDESIGNS * 2 + 1/*planet*/) struct battle_s { struct game_s *g; void *uictx; uint8_t planet_i; battle_side_i_t planet_side; int16_t pop; uint16_t fact; uint16_t bases; uint16_t biodamage; struct battle_side_s s[2]; bool autoresolve; bool autoretreat; bool has_attacked; bool bases_using_mirv; bool turn_done; uint8_t num_repulsed; bool flag_human_att; bool flag_cur_item_destroyed; uint8_t items_num; /* in item table, not counting planet at 0 */ uint8_t items_num2; /* in item table, not counting planet at 0 */ uint8_t cur_item; /* in item table */ int8_t special_button; uint32_t popdamage; uint32_t factdamage; uint16_t num_turn; bool have_subspace_int; uint8_t antidote; struct battle_item_s item[BATTLE_ITEM_MAX]; uint8_t prio_i; int16_t priority[BATTLE_ITEM_MAX]; uint8_t num_rocks; struct battle_rock_s rock[BATTLE_ROCK_MAX]; uint8_t num_missile; struct battle_missile_s missile[BATTLE_MISSILE_MAX]; /* -100 : rock -30 : enemy planet, out of weapon range -itemi : enemy item, out of weapon range 0 : empty, too far or friendly planet 1 : empty, can move to 10 + itemi : friendly item 30 + itemi : enemy item, in weapon range */ int8_t area[BATTLE_AREA_H][BATTLE_AREA_W]; }; extern void game_battle_prepare(struct battle_s *bt, int party_r, int party_l, uint8_t planet_i); extern void game_battle_finish(struct battle_s *bt); extern void game_battle_handle_all(struct game_s *g); extern void game_battle_count_hulls(const struct battle_s *bt, shipsum_t force[2][SHIP_HULL_NUM]); #endif 1oom-1.11.2/src/game/game_battle_human.c000066400000000000000000002247461476061725400200020ustar00rootroot00000000000000#include "config.h" #include #include "game_battle_human.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_battle.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ #define BATTLE_ROUTE_LEN 20 /* -------------------------------------------------------------------------- */ static void game_battle_with_human_init_sub1(struct battle_s *bt) { /* from ui_battle_do_sub1 */ bt->items_num = bt->s[SIDE_L].items + bt->s[SIDE_R].items; for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *b = &(bt->item[i]); bool flag_no_missiles; flag_no_missiles = true; for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { weapon_t w; w = b->wpn[j].t; if ((tbl_shiptech_weap[w].numshots > 0) && (!tbl_shiptech_weap[w].is_bomb)) { flag_no_missiles = false; } } b->missile = flag_no_missiles ? -1 : 1; } bt->antidote = bt->item[0].pulsar; /* HACK */ bt->item[0].pulsar = 0; if (bt->item[0].subspace > 0) { bool flag_att_have_teleporter = false; int att_from, att_to, def_from, def_to; bt->have_subspace_int = true; if (bt->item[0].side == SIDE_L) { def_to = att_from = bt->s[SIDE_L].items + 1; att_to = bt->items_num; def_from = 1; } else { att_from = 1; def_from = att_to = bt->s[SIDE_L].items + 1; def_to = bt->items_num; } for (int i = att_from; i < att_to; ++i) { if (bt->item[i].subspace > 0) { bt->item[i].subspace = -1; flag_att_have_teleporter = true; } } if (flag_att_have_teleporter) { for (int i = def_from; i < def_to; ++i) { if (bt->item[i].subspace > 0) { bt->item[i].subspace = -1; } } } } for (int i = 0; i <= bt->items_num; ++i) { bt->item[i].hp1 = bt->item[i].hp2; } for (int i = 0; i < BATTLE_ROCK_MAX; ++i) { /* BUG? this is done only up to 6 */ bt->rock[i].sx = -1; bt->rock[i].sy = -1; } } static void game_battle_place_items(struct battle_s *bt) { const int8_t tbl_starty[NUM_SHIPDESIGNS] = { 3, 4, 2, 5, 1, 6 }; { int x = 1, y = 3; switch (bt->item[0].side) { case SIDE_NONE: x = -1; y = -1; break; case SIDE_L: break; case SIDE_R: x = 8; break; } bt->item[0].sx = x; bt->item[0].sy = y; } for (int i = 1; i <= bt->s[SIDE_L].items; ++i) { bt->item[i].sx = 0; bt->item[i].sy = tbl_starty[i - 1]; } for (int i = 1; i <= bt->s[SIDE_R].items; ++i) { bt->item[i + bt->s[SIDE_L].items].sx = 9; bt->item[i + bt->s[SIDE_L].items].sy = tbl_starty[i - 1]; } for (int i = 0; i < bt->num_rocks; ++i) { struct battle_rock_s *r = &(bt->rock[i]); bool flag_ok; r->gfx = ui_gfx_get_rock(rnd_0_nm1(4, &bt->g->seed)); flag_ok = false; while (!flag_ok) { int8_t x, y; flag_ok = true; x = rnd_0_nm1(7, &bt->g->seed) + 2; y = rnd_0_nm1(8, &bt->g->seed); { const struct battle_item_s *b; b = &(bt->item[0]); if ((b->side != SIDE_NONE) && (abs(b->sx - x) <= 1) && (abs(b->sy - y) <= 1)) { flag_ok = false; } } for (int j = 0; j < i; ++j) { struct battle_rock_s *t = &(bt->rock[j]); if (0 /* FIXME BUG? overlap not checked */ || ((t->sy == y) && ((t->sx == (x - 1)) || (t->sx == (x + 1)))) || ((t->sx == x) && ((t->sy == (y - 1)) || (t->sy == (y + 1)))) ) { flag_ok = false; } } if (flag_ok) { r->sx = x; r->sy = y; } } } } static void game_battle_damage_planet(struct battle_s *bt, uint32_t damage) { int v; if (bt->item[0].num > 0) { damage /= 2; } bt->popdamage += damage; v = bt->popdamage / game_num_pop_hp; bt->popdamage = bt->popdamage % game_num_pop_hp; v = bt->pop - v; SETMAX(v, 0); bt->pop = v; bt->factdamage += damage; v = bt->factdamage / game_num_fact_hp; bt->factdamage = bt->factdamage % game_num_fact_hp; v = bt->fact - v; SETMAX(v, 0); bt->fact = v; } static void game_battle_missile_remove_unused(struct battle_s *bt) { for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if (m->target == MISSILE_TARGET_NONE) { util_table_remove_item_any_order(i, bt->missile, sizeof(struct battle_missile_s), bt->num_missile); --bt->num_missile; } } } static void game_battle_item_destroy(struct battle_s *bt, int item_i) { struct battle_item_s *b = &(bt->item[item_i]); battle_side_i_t side = b->side; b->selected = 0; if (item_i != 0) { if (bt->cur_item > item_i) { --bt->cur_item; } for (int i = 0; i <= bt->items_num2; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if (bt->priority[i] == item_i) { bt->priority[i] = 50; } if ((bt->priority[i] > item_i) && (bt->priority[i] < 50)) { --bt->priority[i]; } if (b2->stasisby == item_i) { b2->stasisby = 0; } if (b2->stasisby > item_i) { --b2->stasisby; } } for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if ((m->source == item_i) || (m->target == item_i)) { m->target = MISSILE_TARGET_NONE; } if (m->source > item_i) { --m->source; } if (m->target > item_i) { --m->target; } } --bt->s[side].items; util_table_remove_item_keep_order_zero(item_i, bt->item, sizeof(bt->item[0]), bt->items_num + 1); --bt->items_num; } else { b->wpn[0].t = WEAPON_NONE; for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if (m->source == item_i) { m->target = MISSILE_TARGET_NONE; } } if (bt->have_subspace_int) { bt->have_subspace_int = false; for (int i = 0; i <= bt->items_num2; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if (b2->subspace == -1) { b2->subspace = 1; } } } } game_battle_missile_remove_unused(bt); } static void game_battle_missile_spawn(struct battle_s *bt, int attacker_i, int target_i, int nummissiles, weapon_t wpnt, int damagemul2) { struct battle_missile_s *m; struct shiptech_weap_s *w = &(tbl_shiptech_weap[wpnt]); if (bt->num_missile == BATTLE_MISSILE_MAX) { bt->missile[0].target = MISSILE_TARGET_NONE; game_battle_missile_remove_unused(bt); } m = &(bt->missile[bt->num_missile]); m->target = target_i; m->damagemul2 = damagemul2; m->source = attacker_i; { struct battle_item_s *b = &(bt->item[attacker_i]); struct firing_s *fr = &(bt->g->gaux->firing[b->look]); m->x = b->sx * 32 + fr->target_x + (32 - fr->target_x * 2) * b->side; m->y = b->sy * 24 + fr->target_y; } m->fuel = w->v24; if (attacker_i == 0/*planet*/) { m->fuel += 12; } m->wpnt = wpnt; m->nummissiles = nummissiles * w->nummiss; m->speed = w->dtbl[0]; ++bt->num_missile; } static void game_battle_missile_hit(struct battle_s *bt, int missile_i, int target_x, int target_y) { struct game_s *g = bt->g; struct battle_missile_s *m = &(bt->missile[missile_i]); int target_i = m->target, damage; struct battle_item_s *b = &(bt->item[target_i]); struct shiptech_weap_s *w = &(tbl_shiptech_weap[m->wpnt]); if (target_i == MISSILE_TARGET_NONE) { return; } { int damagediv = 1; if (1 && ((target_i == 0) && (!w->is_bomb)) && ((w->misstype > 0) || (w->damagemin != w->damagemax)) ) { damagediv = 2; } if (w->damagefade) { damage = w->damagemax - ((w->v24 - m->fuel) * w->dtbl[0] + (w->dtbl[0] - m->speed)) / 2; } else { damage = w->damagemax; } damage /= damagediv; damage -= b->absorb / (w->halveshield ? 2 : 1); damage *= w->damagemul; if ((b->sbmask & (1 << SHIP_SPECIAL_BOOL_DISP)) && (rnd_1_n(100, &g->seed) < 35)) { damage = 0; } } if (damage < 0) { m->target = MISSILE_TARGET_NONE; } else { struct battle_item_s *bs = &(bt->item[m->source]); int v1c = m->damagemul2, misschance, hploss = b->hploss, totaldamage = 0, num_destroyed = 0; bool flag_hit_misshield = false; uint32_t totalhp = b->hp1 * b->num - hploss; misschance = 50 - (bs->complevel - b->misdefense) * 10; if (b->cloak == 1) { misschance += 50; } if (!game_num_bt_precap_tohit) { SETMIN(misschance, 95); } for (int i = 0; i < m->nummissiles; ++i) { int chance; chance = misschance - w->extraacc * 10; if (game_num_bt_precap_tohit) { SETMIN(chance, 95); } if (chance <= rnd_1_n(100, &g->seed)) { if ((b->misshield - w->tech_i) < rnd_1_n(100, &g->seed)) { int v; v = MIN(damage, b->hp1); v *= v1c; totaldamage += v; hploss += v; } else { flag_hit_misshield = true; } } for (int j = 0; (j < v1c) && (b->hp1 <= hploss); ++j) { if (b->num >= num_destroyed) { ++num_destroyed; } hploss -= b->hp1; } hploss = hploss % b->hp1; } hploss = (totaldamage + b->hploss) % b->hp1; /* FIXME should be hploss + b->hploss % hp1 ? */ b->hploss = hploss; if (flag_hit_misshield && (!bt->autoresolve)) { ui_battle_draw_misshield(bt, target_i, target_x, target_y, missile_i); } m->target = MISSILE_TARGET_NONE; if (target_i == 0) { game_battle_damage_planet(bt, totaldamage); } SETMIN(totaldamage, totalhp); if (b->hploss >= b->hp1) { /* FIXME never true to the % above? */ ++num_destroyed; b->hploss = 0; } { int num = b->num - num_destroyed; SETMAX(num, 0); b->num = num; if ((totaldamage > 0) && (!bt->autoresolve)) { ui_battle_draw_damage(bt, target_i, target_x, target_y, totaldamage); } if (num == 0) { if (target_i == bt->cur_item) { bt->flag_cur_item_destroyed = true; } game_battle_item_destroy(bt, target_i); } } } } static int game_battle_missile_rock_collide(struct battle_s *bt, struct battle_missile_s *m) { const int tbl_chance[] = { 10, 9, 8, 7, 7, 6, 5, 4, 3, 3 }; int collisions = 0; for (int i = 0; i < m->nummissiles; ++i) { int r; r = rnd_1_n(100, &bt->g->seed); if (r <= tbl_chance[tbl_shiptech_weap[m->wpnt].extraacc]) { ++collisions; } } return collisions; } static void game_battle_missile_move(struct battle_s *bt, int missile_i, int target_x, int target_y, int step) { struct battle_missile_s *m = &(bt->missile[missile_i]); int mx = m->x, my = m->y, target_i = m->target, target_x_hit, target_y_hit; struct battle_item_s *b = &(bt->item[target_i]); { struct firing_s *fr = &(bt->g->gaux->firing[b->look]); if (b->side == SIDE_R) { target_x_hit = target_x + 32 - fr->target_x; } else { target_x_hit = target_x + fr->target_x; } target_y_hit = target_y + fr->target_y; } { int dx = target_x_hit - mx, dy = target_y_hit - my; if (abs(dx) > abs(dy)) { SETMIN(step, abs(dx)); if (dx == 0) { dx = 1; } mx += (dx / abs(dx)) * step; my += ((dy * step * 3 + 3) / (abs(dx) * 4)); } else { SETMIN(step, abs(dy)); if (dy == 0) { dy = 1; } mx += (dx * step) / abs(dy); my += ((dy / abs(dy)) * step * 3 + 3) / 4; } } if (bt->num_rocks > 0) { int collisions = 0; for (int dist = 1; dist <= step; dist += 4) { int mx0, my0; mx0 = m->x; my0 = m->y; util_math_go_line_dist(&mx0, &my0, mx, my, dist); for (int i = 0; i < bt->num_rocks; ++i) { struct battle_rock_s *r = &(bt->rock[i]); if (1 && ((r->sx * 32 + 2) <= mx0) && ((r->sx * 32 + 30) >= mx0) && ((r->sy * 24 + 2) <= my0) && ((r->sy * 24 + 22) >= my0) ) { collisions += game_battle_missile_rock_collide(bt, m); } } } if (collisions > 0) { int n = m->nummissiles - collisions; SETMAX(n, 0); m->nummissiles = n; if (n == 0) { m->target = -1; } if (!bt->autoresolve) { ui_battle_draw_explos_small(bt, mx - 4, my - 4); } } } if (m->nummissiles > 0) { if (!bt->autoresolve) { ui_battle_draw_missile(bt, missile_i, mx, my, target_x_hit, target_y_hit); } { /* from ui_battle_draw_missile */ const struct shiptech_weap_s *w = &(tbl_shiptech_weap[m->wpnt]); if (w->misstype == 4) { int v; v = w->damagemax - (((w->v24 - m->fuel) * w->dtbl[0] + (w->dtbl[0] - m->speed))) / 2; /* FIXME check this calc */ if (v < 0) { m->target = MISSILE_TARGET_NONE; } } } } if (1 && ((target_x_hit - 10) <= mx) && ((target_x_hit + 10) >= mx) && ((target_y_hit - 10) <= my) && ((target_y_hit + 10) >= my) ) { game_battle_missile_hit(bt, missile_i, target_x, target_y); } else { int v; m->x = mx; m->y = my; v = m->speed - step; SETMAX(v, 0); m->speed = v; } } static void game_battle_item_finish(struct battle_s *bt, bool flag_quick) { bool flag_done = false; uint8_t itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); int delay = flag_quick ? 5 : 10; if (b->side == SIDE_NONE) { return; } while (!flag_done) { flag_done = true; for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if ((m->target == itemi) && (m->speed > 0)) { int step; step = tbl_shiptech_weap[m->wpnt].dtbl[0] / delay; SETMIN(step, m->speed); game_battle_missile_move(bt, i, b->sx * 32, b->sy * 24, step); flag_done = false; } } if (!bt->autoresolve) { ui_battle_draw_basic(bt); } } game_battle_missile_remove_unused(bt); } static void game_battle_with_human_init(struct battle_s *bt) { /* from ui_battle_do */ struct game_s *g = bt->g; planet_t *p = &(g->planet[bt->planet_i]); switch (p->rocks) { case PLANET_ROCKS_SOME: bt->num_rocks = rnd_1_n(4, &bt->g->seed); break; case PLANET_ROCKS_MANY: bt->num_rocks = rnd_0_nm1(3, &bt->g->seed) + 5; break; case PLANET_ROCKS_NONE: /* already zeroed */ break; } for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { bt->s[SIDE_L].tbl_ships[i] = 0; bt->s[SIDE_R].tbl_ships[i] = 0; } if ((bt->planet_side != SIDE_NONE) && (bt->bases > 0)) { bt->s[bt->planet_side].flag_have_scan = true; } bt->item[0].side = bt->planet_side; game_battle_with_human_init_sub1(bt); game_battle_place_items(bt); for (int i = 1; i <= bt->items_num; ++i) { struct battle_item_s *b = &(bt->item[i]); for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { if (b->wpn[j].n > 0) { weapon_t w; w = b->wpn[j].t; b->wpn[j].numshots = tbl_shiptech_weap[w].numshots; } } } } static int game_battle_get_priority(const struct battle_item_s *b, race_t race) { int prio = b->complevel + b->man - b->unman; if (b->sbmask & (1 << SHIP_SPECIAL_BOOL_SCANNER)) { prio += 3; } if (b->subspace != 0) { prio += b->subspace * 1000; } if (race == RACE_ALKARI) { prio += 3; } return prio; } static void game_battle_build_priority(struct battle_s *bt) { for (int i = 0; i <= bt->items_num; ++i) { bt->priority[i] = bt->items_num - i; } for (int i = 1; i <= bt->items_num; ++i) { const struct battle_item_s *b; int j, prio_j, prio_i, itemi; j = i - 1; itemi = bt->priority[i]; b = &(bt->item[itemi]); prio_i = game_battle_get_priority(b, bt->s[b->side].race); b = &(bt->item[bt->priority[j]]); prio_j = game_battle_get_priority(b, bt->s[b->side].race); while ((j >= 0) && (prio_j < prio_i)) { bt->priority[j + 1] = bt->priority[j]; --j; if (j >= 0) { b = &(bt->item[bt->priority[j]]); prio_j = game_battle_get_priority(b, bt->s[b->side].race); } } bt->priority[j + 1] = itemi; } } static void game_battle_item_done(struct battle_s *bt) { struct battle_item_s *b = &(bt->item[bt->cur_item]); b->selected = 0; do { bt->priority[bt->prio_i] = -1; bt->prio_i = (bt->prio_i + 1) % (bt->items_num2 + 1); } while (bt->priority[bt->prio_i] == 50); } static void game_battle_missile_turn_done(struct battle_s *bt) { for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if (m->speed <= 0) { m->speed = tbl_shiptech_weap[m->wpnt].dtbl[0]; if (--m->fuel == 0) { m->target = MISSILE_TARGET_NONE; } } } game_battle_missile_remove_unused(bt); } static void game_battle_reset_specials(struct battle_s *bt) { struct battle_item_s *b; int itemi = bt->cur_item; for (int i = 0; i <= bt->items_num; ++i) { b = &(bt->item[i]); if (b->repulsor > 0) { b->repulsor = 1; } } b = &(bt->item[itemi]); if ((b->stasis > 0) || (b->pulsar > 0)) { bt->special_button = 1; } else { bt->special_button = -1; } if (itemi == 0) { bt->special_button = -1; } { bool flag_no_missiles = true; for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { if ((b->wpn[i].numshots > 0) && (!tbl_shiptech_weap[b->wpn[i].t].is_bomb)) { flag_no_missiles = false; } } if (flag_no_missiles) { b->missile = -1; } if (itemi == 0) { b->missile = 1; } } if (game_num_bt_wait_no_reload && b->can_retaliate) { /* WASBUG MOO1 reloads specials on Wait */ return; } b->can_retaliate = true; for (int i = 0; i <= bt->items_num; ++i) { b = &(bt->item[i]); if (b->stasisby == itemi) { b->stasisby = 0; } } b = &(bt->item[itemi]); if (b->warpdis == 2) { b->warpdis = 1; } if (b->stasis == 3) { b->stasis = 1; } if (b->pulsar > 2) { b->pulsar -= 2; } if (b->stream > 2) { b->stream -= 2; } if (b->subspace == 2) { b->subspace = 1; } if (b->blackhole == 2) { b->blackhole = 1; } if (b->technull == 2) { b->technull = 1; } if (b->repair > 0) { int repair = (b->hp2 * b->repair) / 100; if (b->hp1 < b->hp2) { b->hp1 += repair; SETMIN(b->hp1, b->hp2); } else { int v = b->hploss - repair; SETMAX(v, 0); b->hploss = v; } } if (b->cloak > 1) { b->cloak = 2; } } static int game_battle_get_weap_maxrange(struct battle_s *bt) { struct battle_item_s *b = &(bt->item[bt->cur_item]); bool is_planet = (bt->cur_item == 0); int maxrange = 0, num_weap = is_planet ? 1 : 4; if (is_planet && (b->num > 0) && (b->wpn[0].numfire > 0)) { return 12; } if (b->blackhole == 1) { maxrange = 1; } if (1 && (bt->special_button == 1) && ((b->stasis == 1) || (b->pulsar == 1) || (b->pulsar == 2)) ) { maxrange = 1; } if ((b->stream == 1) || (b->stream == 2)) { maxrange = 2; } if (b->warpdis == 1) { maxrange = 3; } if (b->technull == 1) { maxrange = 4; } for (int i = 0; i < num_weap; ++i) { struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[i].t]); if ((b->wpn[i].n > 0) && (b->wpn[i].numfire > 0) && (b->wpn[i].numshots != 0) && (!w->is_bomb)) { int range; if ((b->wpn[i].numshots == -1) && (w->misstype == 0)) { range = w->range + b->extrarange; } else { range = w->range; if ((b->missile == 0) && (range > 1) && (w->misstype == 0)) { range = 0; } } SETMAX(maxrange, range); } } if ((maxrange == 0) && ((b->side + bt->item[0].side) == 1)) { for (int i = 0; i < num_weap; ++i) { struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[i].t]); if ((b->wpn[i].n > 0) && (b->wpn[i].numfire > 0) && (b->wpn[i].numshots != 0) && w->is_bomb) { bt->has_attacked = false; } } } return maxrange; } static void game_battle_set_route_from_tbl(uint8_t *route, int *tblx, int *tbly, int len) { for (int i = 0; i < BATTLE_ROUTE_LEN; ++i) { int x, y; if (i < len) { x = tblx[i]; y = tbly[i]; route[i] = BATTLE_XY_SET(x, y); } else { route[i] = BATTLE_XY_INVALID; } } } static void game_battle_extend_route_from_tbl(uint8_t *route, int *tblx, int *tbly, int len) { int pos; for (pos = 0; route[pos] != BATTLE_XY_INVALID; ++pos) { /*nop*/ } for (int i = pos; i < (pos + len); ++i) { int j; j = i - pos; route[i] = BATTLE_XY_SET(tblx[j], tbly[j]); } } static void game_battle_item_move_find_route(struct battle_s *bt, uint8_t *route, int itemi, int sx, int sy) { struct battle_item_s *b = &(bt->item[itemi]); int len, tblx[BATTLE_ROUTE_LEN], tbly[BATTLE_ROUTE_LEN]; for (int i = 0; i < BATTLE_ROUTE_LEN; ++i) { route[i] = BATTLE_XY_INVALID; } len = util_math_line_plot(b->sx, b->sy, sx, sy, tblx, tbly); if (game_battle_area_check_line_ok(bt, tblx, tbly, len) == 1) { game_battle_set_route_from_tbl(route, tblx, tbly, len); } else { int minrlen = 999, minlen = 999; for (int sx2 = 0; sx2 < BATTLE_AREA_W; ++sx2) { for (int sy2 = 0; sy2 < BATTLE_AREA_H; ++sy2) { if ((b->sx == sx2) && (b->sy == sy2)) { continue; /* WASBUG? MOO1 does not check, may use -1 as index below */ } len = util_math_line_plot(b->sx, b->sy, sx2, sy2, tblx, tbly); if ((game_battle_area_check_line_ok(bt, tblx, tbly, len) == 1) && (b->man >= len)) { int tblx2[BATTLE_ROUTE_LEN], tbly2[BATTLE_ROUTE_LEN], rlen1; rlen1 = util_math_get_route_len(b->sx, b->sy, tblx, tbly, len); if (rlen1 <= minrlen) { int len2; len2 = util_math_line_plot(sx2, sy2, sx, sy, tblx2, tbly2); if ((game_battle_area_check_line_ok(bt, tblx2, tbly2, len2) == 1) && (b->man >= (len + len2))) { int rlen2; rlen2 = util_math_get_route_len(tblx[len - 1], tbly[len - 1], tblx2, tbly2, len2); if (((len2 + len) <= minlen) && ((rlen2 + rlen1) < minrlen)) { minlen = len2 + len; minrlen = rlen2 + rlen1; game_battle_set_route_from_tbl(route, tblx, tbly, len); game_battle_extend_route_from_tbl(route, tblx2, tbly2, len2); } } else { for (int sx3 = 0; sx3 < BATTLE_AREA_W; ++sx3) { for (int sy3 = 0; sy3 < BATTLE_AREA_H; ++sy3) { if ((sx3 == sx2) && (sy3 == sy2)) { break; /* BUG? not continue */ } { int len2; len2 = util_math_line_plot(sx2, sy2, sx3, sy3, tblx2, tbly2); if ((game_battle_area_check_line_ok(bt, tblx2, tbly2, len2) == 1) && (b->man >= (len + len2))) { int tblx3[BATTLE_ROUTE_LEN], tbly3[BATTLE_ROUTE_LEN], rlen3, rlen2; rlen2 = util_math_get_route_len(tblx[len - 1], tbly[len - 1], tblx2, tbly2, len2); if ((rlen2 + rlen1) < minrlen) { int len3; len3 = util_math_line_plot(sx3, sy3, sx, sy, tblx3, tbly3); if ((game_battle_area_check_line_ok(bt, tblx3, tbly3, len3) == 1) && (b->man >= (len + len2 + len3))) { rlen3 = util_math_get_route_len(tblx2[len2 - 1], tbly2[len2 - 1], tblx3, tbly3, len3); if (((len3 + len + len2) <= minlen) && (rlen3 + rlen1 + rlen2) < minrlen) { minlen = len3 + len + len2; minrlen = rlen3 + rlen1 + rlen2; game_battle_set_route_from_tbl(route, tblx, tbly, len); game_battle_extend_route_from_tbl(route, tblx2, tbly2, len2); game_battle_extend_route_from_tbl(route, tblx3, tbly3, len3); } } } } } } } } } } } } } } static uint32_t game_battle_pulsar_get_dmg(struct battle_s *bt, int target_i, int v) { struct battle_item_s *b = &(bt->item[target_i]); uint32_t dmg = 0, totalhp = b->num * b->hp1; if (target_i == 0/*planet*/) { v /= 2; } v -= b->absorb; if (v > 0) { if (b->hp1 <= v) { b->num = 0; /* MOO1 uses -1 */ dmg = totalhp; } else { b->hp1 -= v; dmg = b->num * v; } /*4c967*/ if (b->hploss > b->hp1) { /* FIXME should be >= ? */ if (b->num) { /* MOO1 does not check this */ --b->num; } /* FIXME should reset hploss ? */ } } return dmg; } static void game_battle_pulsar(struct battle_s *bt, int attacker_i, int ptype) { struct battle_item_s *b = &(bt->item[attacker_i]); int ndiv, rbase; uint32_t dmgtbl[NUM_SHIPDESIGNS * 2 + 1/*planet*/]; memset(dmgtbl, 0, sizeof(dmgtbl)); if (ptype == 0) { ndiv = 2; rbase = 5; } else { ndiv = 1; rbase = 10; } for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *bd = &(bt->item[i]); if (1 && (bd->stasisby == 0) && (util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy) == 1) ) { int v; v = rnd_1_n(b->num / ndiv + rbase, &bt->g->seed); dmgtbl[i] = game_battle_pulsar_get_dmg(bt, i, v); } } if (!bt->autoresolve) { ui_battle_draw_pulsar(bt, attacker_i, ptype, dmgtbl); } } static bool game_battle_special(struct battle_s *bt, int attacker_i, int target_i, int dist, int *killedbelowtargetptr) { /*di*/struct battle_item_s *b = &(bt->item[attacker_i]); /*si*/struct battle_item_s *bd = &(bt->item[target_i]); bool flag_use_stasis = true; if (b->cloak != 0) { if ((b->cloak == 1) && (!bt->autoresolve)) { ui_battle_draw_cloaking(bt, 20, 100, -1, -1); } b->cloak = 3; } /*5599e*/ if (!bt->s[b->side].flag_human) { int n = 0, num = bt->s[SIDE_L].items; /* AI is always on SIDE_R */ flag_use_stasis = false; for (int i = 1; i <= num; ++i) { if (bt->item[i].stasisby > 0) { ++n; } } if ((num - 2) >= n) { flag_use_stasis = true; } } /*559f5*/ if ((b->stasis == 1) && (dist == 1) && (target_i != 0/*planet*/) && flag_use_stasis && (bd->cloak != 1) && (bt->special_button == 1)) { b->stasis = 3; if ((bd->side == SIDE_L) || (bt->s[SIDE_R].race != RACE_NUM/*monster*/)) { bt->special_button = 0; if (!bt->autoresolve) { ui_sound_play_sfx(0x15); ui_battle_draw_stasis(bt, attacker_i, target_i); } /* FIXME BUG? shooting target with stasis removes missiles coming for it? */ for (int i = 0; i < bt->num_missile; ++i) { struct battle_missile_s *m = &(bt->missile[i]); if (m->target == target_i) { m->target = MISSILE_TARGET_NONE; } } bd->stasisby = attacker_i; return true; } else { /*55ae9*/ return false; /* FIXME BUG? returns attacker item offset */ } } /*55afe*/ if (((b->stream == 1) || (b->stream == 2)) && (dist <= 2)) { uint32_t damage = 0, v; if ((bd->side == SIDE_L) || (bt->s[SIDE_R].race != RACE_NUM/*monster*/)) { switch (b->stream) { case 1: v = b->num / 2 + 20; SETMIN(v, 50); v = (bd->hp1 * v + 99) / 100; SUBSAT0(bd->hp1, v); damage = bd->num * v; if (!bt->autoresolve) { ui_sound_play_sfx(0x16); ui_battle_draw_stream1(bt, attacker_i, target_i); if (damage > 0) { ui_battle_draw_damage(bt, target_i, bd->sx * 32, bd->sy * 24, damage); } } b->stream = 3; break; case 2: v = b->num / 2 + 40; SETMIN(v, 75); v = (bd->hp1 * v + 99) / 100; SUBSAT0(bd->hp1, v); damage = bd->num * v; if (!bt->autoresolve) { ui_sound_play_sfx(0x18); ui_battle_draw_stream2(bt, attacker_i, target_i); if (damage > 0) { ui_battle_draw_damage(bt, target_i, bd->sx * 32, bd->sy * 24, damage); } } b->stream = 4; break; default: break; } if (bd->hp1 <= bd->hploss) { if (bd->num > 0) { --bd->num; } bd->hploss = 0; } if ((bd->num <= 0) || (bd->hp1 <= 0)) { bd->num = 0; bd->hp1 = 50; game_battle_item_destroy(bt, target_i); if (target_i != 0/*planet*/) { return true; } } } else { /*55fa9*/ b->stream += 2; } } /*55fce*/ if ((b->pulsar >= 1) && (dist <= 1) && (bt->special_button != 0)) { int n, belowtarget; bt->special_button = 0; switch (b->pulsar) { case 1: case 2: if (!bt->autoresolve) { ui_sound_play_sfx(0x20); } game_battle_pulsar(bt, attacker_i, b->pulsar - 1); b->pulsar += 2; break; default: break; } n = bt->items_num; belowtarget = 0; while (n > -1) { /* FIXME nothing is done on n == 0 loop */ if ((bt->item[n].num <= 0) && (n != 0/*planet*/)) { game_battle_item_destroy(bt, n); if (target_i > n) { ++belowtarget; } if ((target_i == n) && (target_i != 0/*planet*/)) { /* FIXME redundant check */ dist = 100; } } --n; } *killedbelowtargetptr = belowtarget; if ((dist == 100) && (target_i != 0/*planet*/)) { /* FIXME redundant check */ return true; } } /*560d4*/ if (b->warpdis == 1) { struct battle_item_s *bi; int t; if ((bd->unman >= bd->man) || (dist > 3) || (target_i == 0/*planet*/)) { t = -1; for (int i = 1; i <= bt->items_num; ++i) { bi = &(bt->item[i]); if (1 && ((b->side + bi->side) == 1) && (util_math_dist_maxabs(b->sx, b->sy, bi->sx, bi->sy) <= 3) && (bi->unman < bi->man) ) { t = i; } } } else { /*561de*/ t = target_i; } if (t > 0) { bi = &(bt->item[t]); if ((bi->side == SIDE_L) || (bt->s[SIDE_R].race != RACE_NUM/*monster*/)) { int v; if (!bt->autoresolve) { ui_sound_play_sfx(0x09); ui_battle_draw_bomb_attack(bt, attacker_i, t, UI_BATTLE_BOMB_WARPDIS); } b->warpdis = 2; v = rnd_0_nm1(2, &bt->g->seed); bi->unman += v; if ((v > 0) && (bi->man > bi->unman)) { SUBSAT0(bi->defense, 2); SUBSAT0(bi->misdefense, 2); } /*56318*/ SETMIN(bi->unman, bi->man); SUBSAT0(bi->actman, bi->unman); /* FIXME unman sub'd earlier? */ } else { /*563af*/ b->warpdis = 2; } } else { /*563c3*/ b->warpdis = 2; } } /*563d5*/ if ((b->blackhole == 1) && (dist <= 1)) { if ((bd->side == SIDE_L) || (bt->s[SIDE_R].race != RACE_NUM/*monster*/)) { int v; if (!bt->autoresolve) { ui_sound_play_sfx(0x1d); ui_battle_draw_blackhole(bt, attacker_i, target_i); } v = rnd_1_n(75, &bt->g->seed) + 25; v -= bd->absorb * 2; if (v > 0) { if (bd->num > 1) { bd->num = ((100 - v) * bd->num) / 100; } else { if (rnd_1_n(100, &bt->g->seed) > v) { bd->num = 0; } } } /*5672f*/ if (bd->num <= 0) { game_battle_item_destroy(bt, target_i); if (target_i != 0/*planet*/) { return true; } } b->blackhole = 2; } else { /*56750*/ b->blackhole = 2; } } /*56762*/ if ((b->technull == 1) && (dist <= 4)) { if ((bd->side == SIDE_L) || (bt->s[SIDE_R].race != RACE_NUM/*monster*/)) { int v; v = bd->complevel - rnd_1_n(3, &bt->g->seed) - rnd_1_n(3, &bt->g->seed); bd->complevel = v; v = bd->misdefense - rnd_1_n(3, &bt->g->seed) - rnd_1_n(3, &bt->g->seed); SETMAX(v, bd->defense); bd->misdefense = v; if (!bt->autoresolve) { ui_sound_play_sfx(0x0e); ui_battle_draw_technull(bt, attacker_i, target_i); } b->technull = 2; } else { /*5687f*/ b->technull = 2; } } return false; } static void game_battle_repulse_do(struct battle_s *bt, int target_i, int sx, int sy, int attacker_i) { struct battle_item_s *b = &(bt->item[attacker_i]); struct battle_item_s *bd = &(bt->item[target_i]); if (!bt->autoresolve) { ui_battle_draw_repulse(bt, attacker_i, target_i, sx, sy); } b->repulsor = 2; bd->sx = sx; bd->sy = sy; ++bt->num_repulsed; } static void game_battle_repulse(struct battle_s *bt, int attacker_i, int target_i) { struct battle_item_s *b = &(bt->item[attacker_i]); struct battle_item_s *bd = &(bt->item[target_i]); int sx, sy; int8_t a; sx = bd->sx * 2 - b->sx; sy = bd->sy * 2 - b->sy; if (1 && (sx >= 0) && (sx < BATTLE_AREA_W) && (sy >= 0) && (sy < BATTLE_AREA_H) && (((a = bt->area[sy][sx]) == 0) || (a == 1) || (a == (target_i + 10))) ) { game_battle_repulse_do(bt, target_i, sx, sy, attacker_i); } else { for (int xo = -1; xo < 2; ++xo) { int x, y; x = sx + xo; if ((x < 0) || (x >= BATTLE_AREA_W)) { continue; } for (int yo = -1; yo < 2; ++yo) { y = sy + yo; if ((y < 0) || (y >= BATTLE_AREA_H)) { continue; } a = bt->area[y][x]; if (1 && ((a == 1) || (a == 0) || (a == (target_i + 10))) && (util_math_dist_maxabs(x, y, b->sx, b->sy) == 2) ) { game_battle_repulse_do(bt, target_i, x, y, attacker_i); return; } } } } } static void game_battle_move_retaliate(struct battle_s *bt, int itemi) { struct battle_item_s *b = &(bt->item[itemi]); uint8_t num_repulsed = 0; bool destroyed = false; for (int i = 1; i <= bt->items_num; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if (b2->repulsor > 1) { b2->repulsor = 1; } } for (int i = 1; i <= bt->items_num; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if ((b->side + b2->side) == 1) { if ((b2->stasisby == 0) && (b2->cloak != 1)) { if (b2->can_retaliate) { destroyed = game_battle_attack(bt, i, itemi, true); } else if ((b2->repulsor == 1) && (util_math_dist_maxabs(b->sx, b->sy, b2->sx, b2->sy) == 1)) { game_battle_repulse(bt, i, itemi); if (bt->num_repulsed > num_repulsed) { i = 0; } } } } num_repulsed = bt->num_repulsed; if (destroyed) { break; } } } static void game_battle_with_human_do_turn_ai(struct battle_s *bt) { int itemi = bt->cur_item; struct battle_item_s *b = &(bt->item[itemi]); if (!bt->autoresolve) { ui_battle_ai_pre(bt); } b->maxrange = game_battle_get_weap_maxrange(bt); if (b->retreat >= 2) { bt->s[b->side].tbl_ships[b->shiptbli] = b->num; if (!bt->autoresolve) { ui_battle_draw_retreat(bt); } game_battle_item_destroy(bt, itemi); } else { /*5a547*/ bt->flag_cur_item_destroyed = false; /* FIXME already done by caller */ bt->num_repulsed = 0; /* FIXME already done by caller */ if ((b->stasisby == 0) && (b->num > 0)) { game_ai->battle_ai_turn(bt); } else { /*5a936*/ b->retreat = 0; } /*5a949*/ if (b->retreat == 1) { b->retreat = 2; } } /*5a96e*/ if ((!bt->autoresolve) && ui_battle_ai_post(bt)) { for (battle_side_i_t i = SIDE_L; i <= SIDE_R; ++i) { if (bt->s[i].flag_human) { bt->s[i].flag_auto = 0; } } } if ((b->cloak == 2) && (b->stasisby == 0)) { if (!bt->autoresolve) { ui_battle_draw_cloaking(bt, 100, 20, -1, -1); } b->cloak = 1; } } static void game_battle_with_human_do_sub3(struct battle_s *bt) { int vc = 0; bool flag_round_done; for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *b = &(bt->item[i]); b->actman = b->man - b->unman; b->can_retaliate = false; for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { int n, m; n = tbl_shiptech_weap[b->wpn[j].t].numfire; m = b->wpn[j].numfire; m += n; SETMIN(m, n); b->wpn[j].numfire = m; } } ++bt->num_turn; game_battle_build_priority(bt); bt->items_num2 = bt->items_num; flag_round_done = false; for (bt->prio_i = 0; (bt->priority[bt->prio_i] >= 0) && (!flag_round_done);) { struct battle_item_s *b; int itemi; bt->cur_item = itemi = bt->priority[bt->prio_i]; b = &(bt->item[itemi]); if (itemi == 0) { b->retreat = 0; bt->bases_using_mirv = bt->s[b->side].flag_base_missile; } if ((itemi == 0) && (b->num <= 0)) { bt->special_button = -1; game_battle_item_finish(bt, bt->s[0].flag_auto && bt->s[1].flag_auto); game_battle_item_done(bt); } else { /*4eb6b*/ bool flag_turn_done; bt->has_attacked = false; game_battle_reset_specials(bt); game_battle_area_setup(bt); if (/*(b->num > 0) &&*/ (b->side != -1) && (!bt->autoresolve)) { ui_battle_draw_basic(bt); } /*4ebbf*/ flag_turn_done = false; while (!flag_turn_done) { ui_battle_action_t act; if (!bt->autoresolve) { ui_battle_turn_pre(bt); } { bool flag_no_missiles; flag_no_missiles = true; /* BUG? uninitialized in MOO1 if b->missile == -1 */ if ((b->missile == 1) || (b->missile == 0)) { for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { if ((b->wpn[i].numshots > 0) && (!tbl_shiptech_weap[b->wpn[i].t].is_bomb)) { flag_no_missiles = false; } } } if (flag_no_missiles) { b->missile = -1; } } if (itemi == 0) { b->missile = 1; } /*4ec80*/ b->selected = 1; bt->flag_cur_item_destroyed = false; bt->num_repulsed = 0; if (bt->s[b->side].flag_auto || (b->retreat > 0)) { if (bt->s[b->side].flag_human && bt->autoretreat && (b->retreat == 0)) { b->retreat = 1; } else { game_battle_with_human_do_turn_ai(bt); flag_turn_done = true; game_battle_item_done(bt); } } else { /*4ece2*/ act = ui_battle_turn(bt); if ((b->stasisby > 0) || ((itemi == 0) && (b->num <= 0))) { act = UI_BATTLE_ACT_DONE; } if (0 || (act == UI_BATTLE_ACT_DONE) || (bt->turn_done) || ((b->missile != 0) && (b->maxrange == 0) && bt->has_attacked) ) { flag_turn_done = true; if ((b->cloak == 2) && (b->stasisby == 0)) { ui_battle_draw_cloaking(bt, 100, 20, -1, -1); b->cloak = 1; } game_battle_item_done(bt); } /*4eddd*/ if (act == UI_BATTLE_ACT_WAIT) { flag_turn_done = true; b->selected = 0; b->can_retaliate = true; /* XXX redundant, set by game_battle_reset_specials */ bt->priority[vc] = itemi; if (vc != bt->prio_i) { bt->priority[bt->prio_i] = -1; } vc = (vc + 1) % (bt->items_num2 + 1); while (bt->prio_i = (bt->prio_i + 1) % (bt->items_num2 + 1), bt->priority[bt->prio_i] == 50) { bt->priority[bt->prio_i] = -1; } } /*4ee70*/ if (act == UI_BATTLE_ACT_AUTO) { bt->s[b->side].flag_auto = 1; if (b->missile == 0) { b->missile = 1; } } /*4eeb8*/ if (act == UI_BATTLE_ACT_MISSILE) { if (itemi == 0) { weapon_t t; bt->bases_using_mirv = !bt->bases_using_mirv; bt->s[b->side].flag_base_missile = !bt->s[b->side].flag_base_missile; t = bt->item[0].wpn[0].t; bt->item[0].wpn[0].t = bt->item[0].wpn[1].t; bt->item[0].wpn[1].t = t; } else { b->missile = !b->missile; } } /*4ef23*/ if (act == UI_BATTLE_ACT_PLANET) { ui_battle_draw_planetinfo(bt, b->side == SIDE_R); } /*4ef45*/ if (act == UI_BATTLE_ACT_SCAN) { if (bt->s[b->side ^ 1].items == 0) { if ((bt->item[0].side + b->side) == 1) { ui_battle_draw_planetinfo(bt, b->side == SIDE_R); } } else { ui_battle_draw_scan(bt, b->side != SIDE_R); } } /*4ef92*/ if (act == UI_BATTLE_ACT_SPECIAL) { bt->special_button = !bt->special_button; } if (act == UI_BATTLE_ACT_RETREAT) { b->retreat = 1; } if (act < (BATTLE_AREA_W * BATTLE_AREA_H)) { int sx, sy, sa; sx = UI_BATTLE_ACT_GET_X(act); sy = UI_BATTLE_ACT_GET_Y(act); if (sx < BATTLE_AREA_W) { sa = bt->area[sy][sx]; switch (sa) { case 1: game_battle_item_move(bt, itemi, sx, sy); break; case 10: ui_battle_draw_planetinfo(bt, b->side); break; case 11: case 12: case 13: case 14: case 15: case 16: ui_battle_draw_scan(bt, bt->item[sa - 10].side); break; case 30: case 31: case 32: case 33: case 34: case 35: case 36: case 37: /* FIXME >36 ??? */ case 38: case 39: case 40: case 41: case 42: case 43: game_battle_attack(bt, itemi, sa - 30, false); break; default: break; } } } /*4f0b6*/ itemi = bt->cur_item; b = &(bt->item[itemi]); if (!bt->flag_cur_item_destroyed) { game_battle_area_setup(bt); if (bt->turn_done || (bt->has_attacked && (b->maxrange == 0) && (b->missile != 0))) { b->selected = 0; } if ((b->num > 0) && (b->side != SIDE_NONE)) { ui_battle_draw_basic_copy(bt); } } else { /*4f15a*/ flag_turn_done = true; } } /*4f15f*/ if (!bt->autoresolve) { ui_battle_turn_post(bt); } } /*4f172*/ if (!bt->flag_cur_item_destroyed) { game_battle_item_finish(bt, bt->s[0].flag_auto && bt->s[1].flag_auto); } if (bt->flag_cur_item_destroyed) { game_battle_item_done(bt); } } /*4f189*/ b = &(bt->item[0/*planet*/]); if (((b->side != SIDE_R) || (b->num <= 0)) && (bt->s[SIDE_R].items == 0)) { flag_round_done = true; } if (((b->side != SIDE_L) || (b->num <= 0)) && (bt->s[SIDE_L].items == 0)) { flag_round_done = true; } } game_battle_missile_turn_done(bt); } typedef enum { BATTLE_TURN_CONTINUE, /*-1,1*/ BATTLE_TURN_RETREAT, /*0*/ BATTLE_TURN_TIMEOUT, /*-50*/ BATTLE_TURN_WIN_L, /*10*/ BATTLE_TURN_WIN_R /*11*/ } battle_turn_start_t; static battle_turn_start_t game_battle_with_human_do_sub2(struct battle_s *bt) { struct battle_item_s *b = &(bt->item[0/*planet*/]); int items[2]; items[SIDE_L] = bt->s[SIDE_L].items; items[SIDE_R] = bt->s[SIDE_R].items; if (b->num > 0) { ++items[b->side]; } if (items[SIDE_L] == 0) { return BATTLE_TURN_WIN_R; } if (items[SIDE_R] == 0) { return BATTLE_TURN_WIN_L; } if (bt->num_turn > game_num_bt_turn_max) { return BATTLE_TURN_TIMEOUT; } if (bt->s[SIDE_R].race == RACE_NUM/*monster*/) { return BATTLE_TURN_CONTINUE; } if (!bt->s[SIDE_R].flag_auto) { return BATTLE_TURN_CONTINUE; } if (game_ai->battle_ai_retreat(bt)) { return BATTLE_TURN_RETREAT; } return BATTLE_TURN_CONTINUE; } static battle_side_i_t game_battle_with_human_do(struct battle_s *bt) { battle_side_i_t winner = SIDE_NONE; while (winner == SIDE_NONE) { switch (game_battle_with_human_do_sub2(bt)) { case BATTLE_TURN_RETREAT: for (int i = bt->s[SIDE_L].items + 1; i <= bt->items_num; ++i) { struct battle_item_s *b = &(bt->item[i]); ++b->retreat; } break; case BATTLE_TURN_WIN_L: winner = SIDE_L; break; case BATTLE_TURN_WIN_R: winner = SIDE_R; break; case BATTLE_TURN_TIMEOUT: if (bt->item[0].side == SIDE_NONE) { winner = SIDE_R; } else { winner = bt->item[0].side; } break; default: break; } if (winner == SIDE_NONE) { game_battle_with_human_do_sub3(bt); } } /*SETMAX(bt->item[0].num, 0);*/ for (int i = 1; i <= bt->items_num; ++i) { struct battle_item_s *b = &(bt->item[i]); bt->s[b->side].tbl_ships[b->shiptbli] = b->num; } return winner; } /* -------------------------------------------------------------------------- */ int game_battle_area_check_line_ok(struct battle_s *bt, int *tblx, int *tbly, int len) { int r = 1; for (int i = 0; i < len; ++i) { int8_t v; v = bt->area[tbly[i]][tblx[i]]; if (v == -100) { r = 0; } if ((v == 10) || (v == 30) || (v == -30)) { r = -1; } } return r; } bool game_battle_attack(struct battle_s *bt, int attacker_i, int target_i, bool retaliate) { /*di*/struct battle_item_s *b = &(bt->item[attacker_i]); /*si*/struct battle_item_s *bd = &(bt->item[target_i]); int num_weap, hploss, numkill = 0, dist, miss_chance_beam, miss_chance_missile; uint32_t planetdamage = 0, totalhp; bool destroyed = false; if (attacker_i == 0) { if (1 && (!bt->s[b->side].flag_auto) && (b->wpn[1].t != WEAPON_NONE) && (bt->s[b->side].flag_base_missile == (tbl_shiptech_weap[b->wpn[0].t].nummiss > 1)) ) { weapon_t t = b->wpn[1].t; b->wpn[1].t = b->wpn[0].t; b->wpn[0].t = t; } num_weap = 1; } else { num_weap = 4; } /*571a9*/ hploss = bd->hploss; if (target_i != 0) { totalhp = bd->hp1 * bd->num - hploss; } else { totalhp = 2000000000; /* FIXME uint32_t max */ } dist = util_math_dist_maxabs(b->sx, b->sy, bd->sx, bd->sy); if (!retaliate) { bt->has_attacked = true; } miss_chance_beam = 50 - (b->complevel - bd->defense) * 10; miss_chance_missile = 50 - (b->complevel - bd->misdefense) * 10; { int tblx[20], tbly[20], len; len = util_math_line_plot(b->sx, b->sy, bd->sx, bd->sy, tblx, tbly); if (game_battle_area_check_line_ok(bt, tblx, tbly, len) == 0) { miss_chance_beam += 30; } } if (bd->cloak == 1) { miss_chance_beam += 50; miss_chance_missile += 50; } if (!game_num_bt_precap_tohit) { SETMIN(miss_chance_beam, 95); SETMIN(miss_chance_missile, 95); } { bool flag_done1 = false; int killedbelowtarget = 0; if (!(retaliate && (bd->cloak != 1))) { flag_done1 = game_battle_special(bt, attacker_i, target_i, dist, &killedbelowtarget); } if (killedbelowtarget > 0) { bt->flag_cur_item_destroyed = false; target_i -= killedbelowtarget; bd = &(bt->item[target_i]); /* FIXME BUG? what about attacker_i ? */ } if (flag_done1) { return destroyed; } } /*573bf*/ for (int i = 0; i < num_weap; ++i) { uint32_t damage2; damage2 = 0; if ((b->wpn[i].n > 0) && (b->wpn[i].numfire > 0) && (b->wpn[i].numshots != 0)) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[i].t]); int damagerange, range; uint32_t damagemul1, damagemul2; uint8_t damagediv; damagerange = w->damagemax - w->damagemin; range = (attacker_i == 0) ? 40 : 0; if ((!w->is_bomb) && (damagerange != 0)) { range += b->extrarange; } else { if (bt->item[bt->cur_item].maxrange < 0) { /* FIXME BUG? should be [attacker_i] */ range += bt->item[bt->cur_item].maxrange; } } range += w->range; if ((range >= dist) && ((!w->is_bomb) || (target_i == 0/*planet*/))) { if (!game_num_bt_no_tohit_acc) { /* BUG? each weapon reduces miss chance */ miss_chance_beam -= w->extraacc * 10; miss_chance_missile -= w->extraacc * 10; } if ((damagerange != 0) || w->is_bio) { /*5755a*/ int absorbdiv; if (!bt->autoresolve) { ui_sound_play_sfx(w->sound); } if (w->is_bomb) { absorbdiv = (w->halveshield ? 2 : 1); } else { absorbdiv = game_battle_get_absorbdiv(b, w, false); } if (w->is_bomb) { if (w->is_bio) { int dmgsum; dmgsum = 0; for (int j = 0; j < (b->wpn[i].n * b->num); ++j) { int dmg; dmg = rnd_0_nm1(w->damagemax + 1, &bt->g->seed) - bt->antidote; SETMAX(dmg, 0); dmgsum += dmg; } if (bt->pop > dmgsum) { bt->pop -= dmgsum; } else { bt->pop = 0; /* FIXME not limited here in MOO1 */ } bt->biodamage += dmgsum; } if (!bt->autoresolve) { ui_battle_draw_bomb_attack(bt, attacker_i, target_i, w->is_bio ? UI_BATTLE_BOMB_BIO : UI_BATTLE_BOMB_BOMB); } } /*5761d*/ damagediv = 1; if ((target_i == 0/*planet*/) && (!w->is_bomb) && ((w->misstype > 0) || (w->damagemin != w->damagemax))) { damagediv = 2; } damagemul2 = 1; damagemul1 = b->num * b->wpn[i].n; while (damagemul1 > 1000) { damagemul1 /= 2; damagemul2 *= 2; } /*576d0*/ while ((b->wpn[i].numfire > 0) && ((bd->num > 0) || (target_i == 0/*planet*/))) { int miss_chance; if ((!w->is_bomb) && (!bt->autoresolve)) { ui_battle_draw_beam_attack(bt, attacker_i, target_i, i); } /*576f1*/ if (w->misstype >= 1) { --b->wpn[i].numfire; } --b->wpn[i].numfire; if (b->wpn[i].numshots > 0) { /* BUG always dec'd on MOO1 */ --b->wpn[i].numshots; } miss_chance = w->is_bomb ? miss_chance_missile : miss_chance_beam; if (game_num_bt_no_tohit_acc) { miss_chance -= w->extraacc * 10; } if (game_num_bt_precap_tohit) { SETMIN(miss_chance, 95); } for (uint32_t j = 0; j < damagemul1; ++j) { /*57755*/ int r, dmg; r = rnd_1_n(100, &bt->g->seed); dmg = 0; if (r >= miss_chance) { dmg = ((r - miss_chance) * 2 * damagerange) / (100 - miss_chance); dmg = (dmg + 1) / 2; dmg += w->damagemin; dmg /= damagediv; dmg -= bd->absorb / absorbdiv; dmg *= w->damagemul; dmg *= damagemul2; if ((bd->sbmask & (1 << SHIP_SPECIAL_BOOL_DISP)) && (rnd_1_n(100, &bt->g->seed) < 35)) { dmg = 0; } } /*57893*/ if (dmg > 0) { if ((bd->hp1 < dmg) && (w->nummiss/*streaming*/ == 0)) { planetdamage += bd->hp1; damage2 += bd->hp1; } else { planetdamage += dmg; damage2 += dmg; } hploss += dmg; } /*57902*/ for (uint32_t k = 0; ((w->nummiss/*streaming*/ == 1) || (k < damagemul2)) && (bd->hp1 <= hploss); ++k) { if (bd->hp1 <= hploss) { if (numkill < bd->num) { /* WASBUG? <= in MOO1 */ ++numkill; } hploss -= bd->hp1; } } /*5797a*/ hploss = hploss % bd->hp1; } /*579aa*/ bd->num -= numkill; numkill = 0; SETMIN(damage2, totalhp); /*579e0*/ } /*57a19*/ if ((damage2 > 0) && (!bt->autoresolve)) { ui_battle_draw_damage(bt, target_i, bd->sx * 32, bd->sy * 24, damage2); } } else if ((!retaliate) && (bt->item[bt->cur_item].missile != 0)) { /* FIXME BUG? should be [attacker_i] */ /*57a85*/ if (!bt->autoresolve) { ui_sound_play_sfx(w->sound); } if (w->misstype >= 1) { --b->wpn[i].numfire; } if (attacker_i == 0/*planet*/) { --b->wpn[1].numfire; } --b->wpn[i].numfire; --b->wpn[i].numshots; damagemul2 = 1; damagemul1 = b->num * b->wpn[i].n; while (damagemul1 > 1000) { damagemul1 /= 2; damagemul2 *= 2; } if ((damagemul1 > 0) && !w->is_bomb) { game_battle_missile_spawn(bt, attacker_i, target_i, damagemul1, b->wpn[i].t, damagemul2); } } /*57ba7*/ numkill = 0; } /*57bac*/ if (bd->num <= 0) { if (target_i == bt->cur_item) { bt->flag_cur_item_destroyed = true; } game_battle_item_destroy(bt, target_i); destroyed = true; if (target_i != 0/*planet*/) { break; } } } } /*57bef*/ if (!destroyed) { bd->hploss = hploss; } if (target_i == 0/*planet*/) { game_battle_damage_planet(bt, planetdamage); } { struct battle_item_s *bc = &(bt->item[bt->cur_item]); /* FIXME ??? */ if (!bt->s[bc->side].flag_auto) { bc->maxrange = game_battle_get_weap_maxrange(bt); } } if ((!destroyed) && (dist == 1) && (target_i != 0/*planet*/) && (b->repulsor == 1)) { game_battle_repulse(bt, attacker_i, target_i); } return destroyed; } void game_battle_item_move(struct battle_s *bt, int itemi, int sx, int sy) { struct battle_item_s *b = &(bt->item[itemi]); bt->num_repulsed = false; if (b->subspace == 1) { if (((b->sx != sx) || (b->sy != sy)) && (!bt->autoresolve)) { ui_battle_draw_cloaking(bt, (b->cloak == 1) ? 30 : 100, 0, sx, sy); } b->sx = sx; b->sy = sy; b->actman = 0; b->subspace = 2; } else { bool flag_quick = bt->s[SIDE_L].flag_auto && bt->s[SIDE_R].flag_auto; int x, y, stepdiv = flag_quick ? 2 : 8; uint8_t route[BATTLE_ROUTE_LEN]; x = b->sx * 32; y = b->sy * 24; game_battle_item_move_find_route(bt, route, itemi, sx, sy); for (int i = 0; route[i] != BATTLE_XY_INVALID; ++i) { int vx, vy, dz; sx = BATTLE_XY_GET_X(route[i]); sy = BATTLE_XY_GET_Y(route[i]); if (bt->flag_cur_item_destroyed || bt->num_repulsed) { break; } /*50a89*/ --b->actman; dz = sx - b->sx; vx = dz ? ((dz * (32 / stepdiv)) / abs(dz)) : 0; dz = sy - b->sy; vy = dz ? ((dz * (24 / stepdiv)) / abs(dz)) : 0; b->sx = sx; b->sy = sy; for (int f = 0; f < stepdiv; ++f) { x += vx; y += vy; if (!bt->autoresolve) { ui_battle_draw_arena(bt, itemi, 2); ui_battle_draw_bottom(bt); b->selected = 2/*moving*/; ui_battle_draw_item(bt, itemi, x, y); } b->selected = 1; for (int j = 0; j < bt->num_missile; ++j) { struct battle_missile_s *m = &(bt->missile[j]); if (m->target == itemi) { int v; v = tbl_shiptech_weap[m->wpnt].dtbl[0]; if ((b->man - b->unman) != 0) { v /= (b->man - b->unman); } v = (v + stepdiv - 1) / stepdiv; SETMIN(v, m->speed); game_battle_missile_move(bt, j, x, y, v); if (bt->flag_cur_item_destroyed || bt->num_repulsed) { break; } } } if (!bt->autoresolve) { ui_battle_draw_finish(bt); } if (bt->flag_cur_item_destroyed || bt->num_repulsed) { break; } } game_battle_missile_remove_unused(bt); if ((!bt->flag_cur_item_destroyed) && (!bt->num_repulsed) && (b->cloak != 1)) { game_battle_move_retaliate(bt, itemi); } if (bt->flag_cur_item_destroyed || bt->num_repulsed) { break; } } } } int game_battle_get_xy_notsame(const struct battle_s *bt, int item1, int item2, int *x_notsame) { const struct battle_item_s *b1 = &(bt->item[item1]); const struct battle_item_s *b2 = &(bt->item[item2]); int dx, dy, x_ns = 1, y_ns = 1; dx = b1->sx - b2->sx; dy = b1->sy - b2->sy; if (dx == 0) { x_ns = 0; } if (dy == 0) { y_ns = false; } if ((dx - dy) == 0) { x_ns = -1; } *x_notsame = x_ns; return y_ns; } void game_battle_area_setup(struct battle_s *bt) { struct battle_item_s *b = &(bt->item[bt->cur_item]); int num_weap = (bt->cur_item == 0/*planet*/) ? 1 : 4; if (!bt->s[b->side].flag_auto) { b->maxrange = game_battle_get_weap_maxrange(bt); } bt->turn_done = true; for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { bt->area[sy][sx] = 0; } } if (b->actman > 0) { bt->turn_done = false; for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { if ((b->subspace == 1) || (b->actman >= util_math_dist_maxabs(b->sx, b->sy, sx, sy))) { bt->area[sy][sx] = 1; } } } } for (int i = 0; i < bt->num_rocks; ++i) { struct battle_rock_s *r = &(bt->rock[i]); bt->area[r->sy][r->sx] = -100; } for (int i = 0; i <= bt->items_num; ++i) { struct battle_item_s *b2 = &(bt->item[i]); if (b2->side != SIDE_NONE) { int8_t v; if (b->side == b2->side) { v = 10 + i; } else { int dist, range; dist = util_math_dist_maxabs(b->sx, b->sy, b2->sx, b2->sy); if (i == 0) { v = -30; for (int j = 0; j < num_weap; ++j) { bool is_missile; const struct shiptech_weap_s *w; w = &(tbl_shiptech_weap[b->wpn[j].t]); is_missile = ((w->damagemax == w->damagemin) && (!w->is_bomb) && (w->misstype == 0)); if ((b->actman > 0) || ((w->range >= dist) && (b->wpn[j].numfire > 0) && (b->wpn[j].numshots != 0))) { bt->turn_done = false; } if ((b->wpn[j].numshots == -1) && (w->misstype == 0)) { range = w->range + b->extrarange; } else { range = w->range; } if ((range >= dist) && ((b->missile == 1) || (!is_missile)) && (b->wpn[j].numfire > 0) && (b->wpn[j].numshots != 0)) { v = 30; } } if (0 || ((b->blackhole == 1) && (dist == 1)) || (((b->pulsar == 1) || (b->pulsar == 2)) && (bt->special_button == 1) && (dist == 1)) || (((b->stream == 1) || (b->stream == 2)) && (dist <= 2)) || ((b->technull == 1) && (dist <= 4)) ) { bt->turn_done = false; v = 30; } } else { v = -i; if ((b->maxrange >= dist) && (b2->stasisby == 0)) { bt->turn_done = false; v = 30 + i; } } } bt->area[b2->sy][b2->sx] = v; } } { int tblx[20], tbly[20]; int zx, zy, len; zx = b->sx - b->actman; zy = b->sy - b->actman; while (zx < 0) { ++zx; ++zy; } while (zy < 0) { ++zx; ++zy; } len = util_math_line_plot(b->sx, b->sy, zx, zy, tblx, tbly); if ((game_battle_area_check_line_ok(bt, tblx, tbly, len) < 1) && (bt->area[zy][zx] == 1)) { bt->area[zy][zx] = 0; } zx = b->sx + b->actman; zy = b->sy - b->actman; while (zx >= BATTLE_AREA_W) { --zx; ++zy; } while (zy < 0) { --zx; ++zy; } len = util_math_line_plot(b->sx, b->sy, zx, zy, tblx, tbly); if ((game_battle_area_check_line_ok(bt, tblx, tbly, len) < 1) && (bt->area[zy][zx] == 1)) { bt->area[zy][zx] = 0; } zx = b->sx + b->actman; zy = b->sy + b->actman; while (zx >= BATTLE_AREA_W) { --zx; --zy; } while (zy >= BATTLE_AREA_H) { /* WASBUG? check y >= _W */ --zx; --zy; } len = util_math_line_plot(b->sx, b->sy, zx, zy, tblx, tbly); if ((game_battle_area_check_line_ok(bt, tblx, tbly, len) < 1) && (bt->area[zy][zx] == 1)) { bt->area[zy][zx] = 0; } zx = b->sx - b->actman; zy = b->sy + b->actman; while (zx < 0) { ++zx; --zy; } while (zy >= BATTLE_AREA_H) { /* WASBUG? check y >= _W */ ++zx; --zy; } len = util_math_line_plot(b->sx, b->sy, zx, zy, tblx, tbly); if ((game_battle_area_check_line_ok(bt, tblx, tbly, len) < 1) && (bt->area[zy][zx] == 1)) { bt->area[zy][zx] = 0; } } if (b->missile == 0) { bt->turn_done = false; } if (!bt->autoresolve) { ui_battle_area_setup(bt); } } int game_battle_get_absorbdiv(const struct battle_item_s *b, const struct shiptech_weap_s *w, bool force_oracle_check) { int v = 1; if ((force_oracle_check || game_num_bt_oracle_fix) && (b->sbmask & (1 << SHIP_SPECIAL_BOOL_ORACLE))) { /* XXX we do not check if w is a beam weapon as this is called by buggy-like-v1.3 AI code for missiles */ v = 2; } v += w->halveshield ? 1 : 0; if (v == 3) { v = 4; } return v; } bool game_battle_with_human(struct battle_s *bt) { planet_t *p = &(bt->g->planet[bt->planet_i]); battle_side_i_t winner; ui_battle_autoresolve_t ar; game_battle_with_human_init(bt); game_update_visibility(bt->g); ar = ui_battle_init(bt); if (ar == UI_BATTLE_AUTORESOLVE_OFF) { bt->autoresolve = false; bt->autoretreat = false; } else { bt->autoresolve = true; bt->autoretreat = (ar == UI_BATTLE_AUTORESOLVE_RETREAT); bt->s[SIDE_L].flag_auto = true; bt->s[SIDE_R].flag_auto = true; } winner = game_battle_with_human_do(bt); p->pop = bt->pop; p->factories = bt->fact; bt->bases = bt->item[0/*planet*/].num; game_battle_finish(bt); ui_battle_shutdown(bt, (bt->planet_side != SIDE_NONE) && (p->owner == PLAYER_NONE), winner); return winner == SIDE_R; } 1oom-1.11.2/src/game/game_battle_human.h000066400000000000000000000017611476061725400177750ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_BATTLE_HUMAN_H #define INC_1OOM_GAME_BATTLE_HUMAN_H #include "types.h" #define BATTLE_XY_SET(_x_, _y_) (((_x_) << 3) + (_y_)) #define BATTLE_XY_GET_X(_v_) (((_v_) >> 3) & 0xf) #define BATTLE_XY_GET_Y(_v_) ((_v_) & 7) #define BATTLE_XY_INVALID 0xff struct battle_s; struct battle_item_s; struct shiptech_weap_s; extern void game_battle_area_setup(struct battle_s *bt); extern int game_battle_area_check_line_ok(struct battle_s *bt, int *tblx, int *tbly, int len); extern void game_battle_item_move(struct battle_s *bt, int itemi, int sx, int sy); extern int game_battle_get_xy_notsame(const struct battle_s *bt, int item1, int item2, int *x_notsame); extern bool game_battle_attack(struct battle_s *bt, int attacker_i, int target_i, bool retaliate); extern int game_battle_get_absorbdiv(const struct battle_item_s *b, const struct shiptech_weap_s *w, bool force_oracle_check); extern bool game_battle_with_human(struct battle_s *bt); /* true if right side won */ #endif 1oom-1.11.2/src/game/game_bomb.c000066400000000000000000000205131476061725400162400ustar00rootroot00000000000000#include "config.h" #include "game_bomb.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_diplo.h" #include "game_num.h" #include "game_shiptech.h" #include "game_tech.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" /* -------------------------------------------------------------------------- */ static void game_turn_bomb_damage(struct game_s *g, uint8_t pli, player_id_t attacker, int *popdmgptr, int *factdmgptr, int *biodmgptr) { const planet_t *p = &(g->planet[pli]); const empiretechorbit_t *ea = &(g->eto[attacker]); const empiretechorbit_t *ed = &(g->eto[p->owner]); uint32_t tbl[WEAPON_NUM]; uint8_t pshield = p->shield, antidote = ed->antidote; int totaldmg = 0, totalbio = 0, maxcomp = 0, complevel; memset(tbl, 0, sizeof(tbl)); for (int i = 0; i < ea->shipdesigns_num; ++i) { const shipdesign_t *sd = &(g->srd[attacker].design[i]); if ((!game_num_orbital_comp_fix) || (ea->orbit[pli].ships[i] != 0)) { /* WASBUG bonus from non-existing ships */ SETMAX(maxcomp, sd->comp); } for (int j = 0; j < (game_num_orbital_weap_4 ? WEAPON_SLOT_NUM : (WEAPON_SLOT_NUM - 1)); ++j) { /* WASBUG? last weapon not used */ weapon_t wpnt = sd->wpnt[j]; uint32_t v; v = ea->orbit[pli].ships[i] * sd->wpnn[j]; if (v != 0) { int ns; ns = tbl_shiptech_weap[wpnt].numshots; if (ns == -1) { ns = 30; } v *= ns; tbl[wpnt] += v; } } } complevel = (maxcomp - 1) * 2 + 6; SETRANGE(complevel, 1, 20); for (int i = 0; i < (game_num_orbital_weap_any ? WEAPON_NUM : WEAPON_CRYSTAL_RAY); ++i) { /* WASBUG? excludes death ray and amoeba stream too */ uint32_t vcur = tbl[i]; if (vcur != 0) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[i]); uint32_t v; int dmgmin, dmgmax; SETMIN(vcur, game_num_max_bomb_dmg); if (vcur < 10) { v = 1; } else { v = vcur / 10; vcur = 10; } dmgmin = w->damagemin; dmgmax = w->damagemax; if (dmgmin == dmgmax) { if (w->is_bio) { for (uint32_t n = 0; n < vcur; ++n) { if (rnd_1_n(20, &g->seed) <= complevel) { int dmg; dmg = rnd_0_nm1(dmgmin + 1, &g->seed) - antidote; SETMAX(dmg, 0); totalbio += v * dmg; SETMIN(totalbio, game_num_max_bio_dmg); } } } else { if (game_num_orbital_torpedo == (w->misstype != 0)) { /* WASBUG damage halving for torpedo affected missiles instead */ dmgmax /= 2; } dmgmax *= w->nummiss; if (dmgmax > pshield) { for (uint32_t n = 0; n < vcur; ++n) { if (rnd_1_n(20, &g->seed) <= complevel) { int dmg; dmg = dmgmax - pshield; totaldmg += v * dmg; } } } } } else { /*dd3d*/ if (!w->is_bomb) { dmgmin /= 2; dmgmax /= 2; } if (dmgmax > pshield) { int dmgrange; dmgrange = dmgmax - dmgmin + 1; dmgmin = dmgmin - 1 - pshield; vcur = (complevel * vcur * v) / 20; for (uint32_t n = 0; n < vcur; ++n) { int dmg; dmg = rnd_1_n(dmgrange, &g->seed) + dmgmin; if (dmg > 0) { totaldmg += dmg; } } } } } } /*de00*/ { int v, h, hr, hb; h = game_num_fact_hp / 5; hr = h * 2; hb = game_num_fact_hp - h; v = totaldmg / (rnd_1_n(hr, &g->seed) + hb); SETMIN(v, p->factories); *factdmgptr = v; } { int v, h, hr, hb; h = game_num_pop_hp / 5; hr = h * 2; hb = game_num_pop_hp - h; v = totaldmg / (rnd_1_n(hr, &g->seed) + hb); v += totalbio; SETMIN(v, p->pop); *popdmgptr = v; } { *biodmgptr = totalbio; } } /* -------------------------------------------------------------------------- */ void game_turn_bomb(struct game_s *g) { for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); player_id_t owner; owner = p->owner; if (owner == PLAYER_NONE) { continue; } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *ea = &(g->eto[i]); bool flag_treaty; int v4; if (i == owner) { continue; } v4 = 0; for (int j = 0; j < ea->shipdesigns_num; ++j) { if (ea->orbit[pli].ships[j] > 0) { v4 += 2; } } flag_treaty = false; if ((ea->treaty[owner] == TREATY_ALLIANCE) || ((ea->treaty[owner] == TREATY_NONAGGRESSION) && IS_AI(g, i))) { flag_treaty = true; } if ((v4 > 0) && (!flag_treaty)) { int pop_inbound, popdmg, factdmg, biodmg; bool flag_do_bomb, flag_play_music; pop_inbound = 0; for (int j = 0; j < g->transport_num; ++j) { transport_t *r = &(g->transport[j]); if ((r->owner == i) && (r->dest == pli)) { pop_inbound += r->pop; } } /*cf52*/ flag_play_music = true; game_turn_bomb_damage(g, pli, i, &popdmg, &factdmg, &biodmg); if ((popdmg == 0) && (factdmg == 0)) { flag_do_bomb = false; } else if (IS_HUMAN(g, i)) { flag_do_bomb = ui_bomb_ask(g, i, pli, pop_inbound); flag_play_music = false; } else { flag_do_bomb = game_ai->bomb(g, i, pli, pop_inbound); } /*d004*/ if (flag_do_bomb || !game_num_orbital_bio_fix) { if (biodmg) { int v; v = p->max_pop3 - biodmg; SETMAX(v, 10); p->max_pop3 = v; } } if (flag_do_bomb && ((popdmg > 0) || (factdmg > 0))) { p->pop -= popdmg; p->factories -= factdmg; SUBSAT0(p->rebels, popdmg / 2 + 1); if (p->pop == 0) { game_planet_destroy(g, pli, i); } if (IS_HUMAN(g, i) || IS_HUMAN(g, owner)) { player_id_t human; bool hide_other; human = IS_HUMAN(g, i) ? i : owner; hide_other = (IS_HUMAN(g, i) && IS_HUMAN(g, owner)); ui_bomb_show(g, human, i, owner, pli, popdmg, factdmg, flag_play_music, hide_other); } if ((p->pop == 0) && IS_HUMAN(g, i)) { int dv; if (ea->treaty[owner] < TREATY_WAR) { game_diplo_start_war_swap(g, owner, i); dv = 13; } else { dv = 10; } game_diplo_act(g, -50 - rnd_1_n(50, &g->seed), i, owner, dv, pli, 0); } else { /*d118*/ game_diplo_battle_finish(g, owner, i, popdmg, 0, biodmg, 0, pli); } } } } } } 1oom-1.11.2/src/game/game_bomb.h000066400000000000000000000002011476061725400162350ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_BOMB_H #define INC_1OOM_GAME_BOMB_H struct game_s; extern void game_turn_bomb(struct game_s *g); #endif 1oom-1.11.2/src/game/game_cheat.c000066400000000000000000000034171476061725400164110ustar00rootroot00000000000000#include "config.h" #include "game_cheat.h" #include "boolvec.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_tech.h" #include "rnd.h" /* -------------------------------------------------------------------------- */ /* TODO disable for multiplayer and return false */ bool game_cheat_galaxy(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_galaxy = !g->gaux->flag_cheat_galaxy; game_update_tech_util(g); game_update_within_range(g); game_update_visibility(g); for (int i = 0; i < g->galaxy_stars; ++i) { BOOLVEC_SET1(g->planet[i].explored, pi); } return true; } bool game_cheat_elections(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_elections = !g->gaux->flag_cheat_elections; return true; } bool game_cheat_events(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_events = !g->gaux->flag_cheat_events; return true; } bool game_cheat_spy_hint(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_spy_hint = !g->gaux->flag_cheat_spy_hint; return true; } bool game_cheat_stars(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_stars = !g->gaux->flag_cheat_stars; return true; } bool game_cheat_tech_hint(struct game_s *g, player_id_t pi) { g->gaux->flag_cheat_tech_hint = !g->gaux->flag_cheat_tech_hint; return true; } bool game_cheat_moola(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); e->reserve_bc += 100; game_update_production(g); return true; } bool game_cheat_traits(struct game_s *g, player_id_t pi) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { g->eto[i].trait2 = rnd_0_nm1(TRAIT2_NUM, &g->seed); g->eto[i].trait1 = rnd_0_nm1(TRAIT1_NUM, &g->seed); } return true; } 1oom-1.11.2/src/game/game_cheat.h000066400000000000000000000012171476061725400164120ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_CHEAT_H #define INC_1OOM_GAME_CHEAT_H #include "game_types.h" #include "types.h" struct game_s; extern bool game_cheat_galaxy(struct game_s *g, player_id_t pi); extern bool game_cheat_elections(struct game_s *g, player_id_t pi); extern bool game_cheat_events(struct game_s *g, player_id_t pi); extern bool game_cheat_spy_hint(struct game_s *g, player_id_t pi); extern bool game_cheat_stars(struct game_s *g, player_id_t pi); extern bool game_cheat_tech_hint(struct game_s *g, player_id_t pi); extern bool game_cheat_moola(struct game_s *g, player_id_t pi); extern bool game_cheat_traits(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/game/game_design.c000066400000000000000000001043251476061725400165760ustar00rootroot00000000000000#include "config.h" #include #include "game_design.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_shipdesign.h" #include "game_shiptech.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ static void game_get_random_shipnames(struct game_s *g, player_id_t player, char shipnames[SHIP_HULL_NUM][SHIP_NAME_LEN + 1]) { BOOLVEC_DECLARE(name_unused, SHIP_NAME_NUM); const empiretechorbit_t *e = &(g->eto[player]); const shipresearch_t *srd = &(g->srd[player]); char const * const *names = &game_str_tbl_ship_names[e->race * SHIP_NAME_NUM]; for (int n = 0; n < SHIP_NAME_NUM; ++n) { BOOLVEC_SET1(name_unused, n); for (int sdi = 0; sdi < e->shipdesigns_num; ++sdi) { if (strcmp(srd->design[sdi].name, names[n]) == 0) { BOOLVEC_SET0(name_unused, n); break; } } } /* game_get_random_unused_shipnames */ for (int i = 0; i < SHIP_HULL_NUM; ++i) { shipnames[i][0] = '\0'; } for (int i = SHIP_HULL_NUM - 1; i >= 0; --i) { int namei; bool flag_unused; flag_unused = false; namei = i * 3 + rnd_0_nm1(3, &g->seed); if (BOOLVEC_IS1(name_unused, namei)) { flag_unused = true; } else { while ((!flag_unused) && (namei < SHIP_NAME_NUM)) { if (BOOLVEC_IS1(name_unused, namei)) { flag_unused = true; } else { ++namei; } } if (!flag_unused) { --namei; while ((!flag_unused) && (namei >= 0)) { if (BOOLVEC_IS1(name_unused, namei)) { flag_unused = true; } else { --namei; } } } if (!flag_unused) { namei = 0; } } if ((namei >= 0) && (namei < SHIP_NAME_NUM)) { BOOLVEC_SET0(name_unused, namei); } lib_strcpy(shipnames[i], names[namei], SHIP_NAME_LEN + 1); /* TODO weird that the strcpy is not inside the previous if */ } } static void game_design_look_add(struct game_design_s *gd, int ld) { shipdesign_t *sd = &(gd->sd); ship_hull_t hull = sd->hull; int numlook = 0, look = sd->look + ld; int lookbase = SHIP_LOOK_PER_HULL * hull + gd->lookbase; for (int i = 0; i < gd->sd_num; ++i) { int l; l = gd->tbl_shiplook[i]; if ((l >= lookbase) && (l < (lookbase + SHIP_LOOK_PER_HULL))) { ++numlook; } } if (look < lookbase) { look = lookbase + SHIP_LOOK_PER_HULL - 1; } else if (look >= (lookbase + SHIP_LOOK_PER_HULL)) { look = lookbase; } if (numlook < SHIP_LOOK_PER_HULL) { for (int i = 0; i < gd->sd_num; ++i) { if (look == gd->tbl_shiplook[i]) { look += ld; if (look < lookbase) { look = lookbase + SHIP_LOOK_PER_HULL - 1; } else if (look >= (lookbase + SHIP_LOOK_PER_HULL)) { look = lookbase; } i = -1; } } } sd->look = look; gd->tbl_shiplook_hull[hull] = look; } static int game_design_calc_cost_item_do(struct game_design_s *gd, design_slot_t slot, int i) { const shipdesign_t *sd = &(gd->sd); int tm, cost = 0; switch (slot) { case DESIGN_SLOT_WEAPON1: case DESIGN_SLOT_WEAPON2: case DESIGN_SLOT_WEAPON3: case DESIGN_SLOT_WEAPON4: tm = tbl_shiptech_weap[i].is_bio ? gd->percent[TECH_FIELD_PLANETOLOGY] : gd->percent[TECH_FIELD_WEAPON]; tm -= tbl_shiptech_weap[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_weap[i].cost * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_ENGINE: tm = gd->percent[TECH_FIELD_PROPULSION] - tbl_shiptech_engine[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_engine[i].cost * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_COMP: tm = gd->percent[TECH_FIELD_COMPUTER] - tbl_shiptech_comp[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_comp[i].cost[sd->hull] * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_JAMMER: tm = gd->percent[TECH_FIELD_COMPUTER] - tbl_shiptech_jammer[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_jammer[i].cost[sd->hull] * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_SHIELD: tm = gd->percent[TECH_FIELD_FORCE_FIELD] - tbl_shiptech_shield[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_shield[i].cost[sd->hull] * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_ARMOR: tm = gd->percent[TECH_FIELD_CONSTRUCTION] - tbl_shiptech_armor[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_armor[i].cost[sd->hull] * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_SPECIAL1: case DESIGN_SLOT_SPECIAL2: case DESIGN_SLOT_SPECIAL3: { tech_field_t fi; fi = tbl_shiptech_special[i].field; tm = gd->percent[fi] - tbl_shiptech_special[i].tech_i; SETRANGE(tm, 0, 50); cost = (tbl_shiptech_special[i].cost[sd->hull] * tech_reduce_50percent_per_10pts[tm]) / 100; } break; default: break; } return cost; } static void game_design_prepare_do(struct game_s *g, struct game_design_s *gd, player_id_t player, shipdesign_t *sd) { const empiretechorbit_t *e = &(g->eto[player]); gd->player_i = player; gd->sd_num = e->shipdesigns_num; game_get_random_shipnames(g, gd->player_i, gd->names); if (sd) { gd->sd = *sd; } else { memset(&gd->sd, 0, sizeof(shipdesign_t)); } memcpy(gd->percent, e->tech.percent, sizeof(gd->percent)); } static weapon_group_t game_design_get_weapon_group(const struct game_s *g, const struct shiptech_weap_s *w) { tech_field_t field; tech_group_t group; if (w->tech_i > 50) { return WEAPON_GROUP_SPECIAL; } field = w->is_bio ? TECH_FIELD_PLANETOLOGY : TECH_FIELD_WEAPON; group = game_tech_get_group(g->gaux, field, w->tech_i); if (group == TECH_GROUP_SINGULAR) { if (w->is_bio) { return WEAPON_GROUP_BIOLOGICAL; } if (w->is_bomb) { return WEAPON_GROUP_BOMBS; } if (w->halveshield) { return WEAPON_GROUP_KINETIC; } if (w->damagemin != w->damagemax) { return WEAPON_GROUP_BEAMS; } return WEAPON_GROUP_MISSILES; } switch (group) { case TECH_GROUP_BEAMS: return WEAPON_GROUP_BEAMS; case TECH_GROUP_PENETRATING_BEAMS: return WEAPON_GROUP_KINETIC; case TECH_GROUP_BIO_WEAPONS: return WEAPON_GROUP_BIOLOGICAL; case TECH_GROUP_BOMBS: return WEAPON_GROUP_BOMBS; case TECH_GROUP_ROCKETS: return WEAPON_GROUP_MISSILES; default: break; } return WEAPON_GROUP_NUM; } /* -------------------------------------------------------------------------- */ void game_design_prepare(struct game_s *g, struct game_design_s *gd, player_id_t player, shipdesign_t *sd) { const empiretechorbit_t *e = &(g->eto[player]); BOOLVEC_DECLARE(lookused, SHIP_LOOK_PER_BANNER); BOOLVEC_CLEAR(lookused, SHIP_LOOK_PER_BANNER); game_design_prepare_do(g, gd, player, sd); gd->lookbase = e->banner * SHIP_LOOK_PER_BANNER; for (int i = 0; i < gd->sd_num; ++i) { uint8_t look; look = g->srd[player].design[i].look; gd->tbl_shiplook[i] = look; BOOLVEC_SET1(lookused, look - gd->lookbase); } /* from ui_design */ for (ship_hull_t hull = SHIP_HULL_SMALL; hull < SHIP_HULL_NUM; ++hull) { uint8_t look, lookbase; look = lookbase = SHIP_LOOK_PER_HULL * hull; for (int i = 0; i < SHIP_LOOK_PER_HULL; ++i) { if (BOOLVEC_IS0(lookused, look + i)) { look += i; break; } } gd->tbl_shiplook_hull[hull] = look + gd->lookbase; } } void game_design_prepare_ai(struct game_s *g, struct game_design_s *gd, player_id_t player, ship_hull_t hull, uint8_t look) { shipdesign_t *sd = &(gd->sd); game_design_prepare_do(g, gd, player, 0); sd->hull = hull; sd->look = look; lib_strcpy(sd->name, gd->names[hull], SHIP_NAME_LEN); game_design_update_engines(sd); sd->space = game_design_calc_space(gd); sd->cost = game_design_calc_cost(gd); } void game_design_update_engines(shipdesign_t *sd) { uint32_t engines, power = 0; for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { if (sd->wpnt[i]) { power += sd->wpnn[i] * tbl_shiptech_weap[sd->wpnt[i]].power; } } power += tbl_shiptech_hull[sd->hull].power * (sd->man + 1); for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { power += tbl_shiptech_special[sd->special[i]].power[sd->hull]; } power += tbl_shiptech_comp[sd->comp].power[sd->hull]; power += tbl_shiptech_jammer[sd->jammer].power[sd->hull]; power += tbl_shiptech_shield[sd->shield].power[sd->hull]; engines = power / (tbl_shiptech_engine[sd->engine].power / 10); SETMAX(engines, 1); sd->engines = engines; } int game_design_get_hull_space(const struct game_design_s *gd) { /* MOO1 also has some additional variable here, but it is always 0 */ int space = tbl_shiptech_hull[gd->sd.hull].space; return space + (space * gd->percent[TECH_FIELD_CONSTRUCTION]) / 50; } int game_design_calc_space_item(struct game_design_s *gd, design_slot_t slot, int i) { const shipdesign_t *sd = &(gd->sd); int tm, space = 0; switch (slot) { case DESIGN_SLOT_WEAPON1: case DESIGN_SLOT_WEAPON2: case DESIGN_SLOT_WEAPON3: case DESIGN_SLOT_WEAPON4: tm = tbl_shiptech_weap[i].is_bio ? gd->percent[TECH_FIELD_PLANETOLOGY] : gd->percent[TECH_FIELD_WEAPON]; tm -= tbl_shiptech_weap[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_weap[i].space * tech_reduce_50percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_ENGINE: tm = gd->percent[TECH_FIELD_PROPULSION] - tbl_shiptech_engine[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_engine[i].space * tech_reduce_25percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_COMP: tm = gd->percent[TECH_FIELD_COMPUTER] - tbl_shiptech_comp[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_comp[i].space[sd->hull] * tech_reduce_25percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_JAMMER: tm = gd->percent[TECH_FIELD_COMPUTER] - tbl_shiptech_jammer[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_jammer[i].space[sd->hull] * tech_reduce_25percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_SHIELD: tm = gd->percent[TECH_FIELD_FORCE_FIELD] - tbl_shiptech_shield[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_shield[i].space[sd->hull] * tech_reduce_25percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_ARMOR: tm = gd->percent[TECH_FIELD_CONSTRUCTION] - tbl_shiptech_armor[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_armor[i].space[sd->hull] * tech_reduce_25percent_per_10pts[tm]) / 100; break; case DESIGN_SLOT_SPECIAL1: case DESIGN_SLOT_SPECIAL2: case DESIGN_SLOT_SPECIAL3: { tech_field_t fi; fi = tbl_shiptech_special[i].field; tm = gd->percent[fi] - tbl_shiptech_special[i].tech_i; SETRANGE(tm, 0, 50); space = (tbl_shiptech_special[i].space[sd->hull] * tech_reduce_25percent_per_10pts[tm]) / 100; } break; default: break; } if (i) { SETMAX(space, 1); } return space; } int game_design_calc_space(struct game_design_s *gd) { const shipdesign_t *sd = &(gd->sd); int s, space; space = game_design_get_hull_space(gd); for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi; wi = sd->wpnt[i]; if ((wi != WEAPON_NONE) && sd->wpnn[i]) { s = game_design_calc_space_item(gd, DESIGN_SLOT_WEAPON1, wi); s *= sd->wpnn[i]; space -= s; } } if (sd->engines) { s = game_design_calc_space_item(gd, DESIGN_SLOT_ENGINE, sd->engine); s = (s * sd->engines) / 10; space -= s; } if (sd->comp) { s = game_design_calc_space_item(gd, DESIGN_SLOT_COMP, sd->comp); space -= s; } if (sd->jammer) { s = game_design_calc_space_item(gd, DESIGN_SLOT_JAMMER, sd->jammer); space -= s; } if (sd->shield) { s = game_design_calc_space_item(gd, DESIGN_SLOT_SHIELD, sd->shield); space -= s; } if (sd->armor) { s = game_design_calc_space_item(gd, DESIGN_SLOT_ARMOR, sd->armor); space -= s; } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t si = sd->special[i]; if (si) { s = game_design_calc_space_item(gd, DESIGN_SLOT_SPECIAL1, si); space -= s; } } return space; } int game_design_calc_cost_item(struct game_design_s *gd, design_slot_t slot, int i) { int cost = game_design_calc_cost_item_do(gd, slot, i); if ((cost < 5) && (i != 0)) { cost = 5; } cost = (cost + 5) / 10; if ((cost < 1) && (i != 0)) { cost = 1; } return cost; } int game_design_calc_cost(struct game_design_s *gd) { const shipdesign_t *sd = &(gd->sd); uint32_t s, cost = tbl_shiptech_hull[sd->hull].cost; for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi; wi = sd->wpnt[i]; if ((wi != WEAPON_NONE) && sd->wpnn[i]) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_WEAPON1, wi); SETMAX(s, 5); s *= sd->wpnn[i]; cost += s; } } if (sd->engines) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_ENGINE, sd->engine); SETMAX(s, 5); cost += (s * sd->engines) / 10; } if (sd->comp) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_COMP, sd->comp); SETMAX(s, 1); cost += s; } if (sd->jammer) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_JAMMER, sd->jammer); SETMAX(s, 1); cost += s; } if (sd->shield) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_SHIELD, sd->shield); SETMAX(s, 5); cost += s; } if (sd->armor) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_ARMOR, sd->armor); SETMAX(s, 5); cost += s; } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t si = sd->special[i]; if (si) { s = game_design_calc_cost_item_do(gd, DESIGN_SLOT_SPECIAL1, si); SETMAX(s, 5); cost += s; } } cost = (cost + 5) / 10; SETMAX(cost, 1); return cost; } void game_design_clear(struct game_design_s *gd) { shipdesign_t *sd = &(gd->sd); char name[SHIP_NAME_LEN + 1]; uint8_t look = sd->look; ship_hull_t hull = sd->hull; lib_strcpy(name, sd->name, sizeof(name)); memset(sd, 0, sizeof(shipdesign_t)); sd->look = look; sd->hull = hull; lib_strcpy(sd->name, name, SHIP_NAME_LEN); game_design_update_engines(sd); sd->space = game_design_calc_space(gd); sd->cost = game_design_calc_cost(gd); } void game_design_look_next(struct game_design_s *gd) { game_design_look_add(gd, 1); } void game_design_look_prev(struct game_design_s *gd) { game_design_look_add(gd, -1); } void game_design_look_fix(const struct game_s *g, player_id_t pi, shipdesign_t *sd) { const empiretechorbit_t *e = &(g->eto[pi]); bool need_fix = false; int look = sd->look; int lookbase = SHIP_LOOK_PER_HULL * sd->hull + e->banner * SHIP_LOOK_PER_BANNER; BOOLVEC_DECLARE(lookused, SHIP_LOOK_PER_HULL); BOOLVEC_CLEAR(lookused, SHIP_LOOK_PER_HULL); for (int i = 0; i < e->shipdesigns_num; ++i) { int l; l = g->srd[pi].design[i].look; if ((l >= lookbase) && (l < (lookbase + SHIP_LOOK_PER_HULL))) { BOOLVEC_SET1(lookused, l - lookbase); if (l == look) { need_fix = true; } } } if (need_fix) { for (int i = 0; i < SHIP_LOOK_PER_HULL; ++i) { if (BOOLVEC_IS0(lookused, i)) { look = lookbase + i; break; } } sd->look = look; } } int game_design_build_tbl_fit_comp(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_comp_t actcomp = sd->comp; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 1; i < SHIP_COMP_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_COMPUTER, tbl_shiptech_comp[i].tech_i, gd->player_i)) { sd->comp = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->comp = actcomp; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_shield(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_shield_t actshield = sd->shield; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 1; i < SHIP_SHIELD_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_FORCE_FIELD, tbl_shiptech_shield[i].tech_i, gd->player_i)) { sd->shield = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->shield = actshield; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_jammer(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_jammer_t actjammer = sd->jammer; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 1; i < SHIP_JAMMER_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_COMPUTER, tbl_shiptech_jammer[i].tech_i, gd->player_i)) { sd->jammer = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->jammer = actjammer; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_armor(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_armor_t actarmor = sd->armor; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 1; i < SHIP_ARMOR_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_CONSTRUCTION, tbl_shiptech_armor[i].tech_i, gd->player_i)) { sd->armor = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->armor = actarmor; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_engine(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_engine_t actengine = sd->engine; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 0; i < SHIP_ENGINE_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_PROPULSION, tbl_shiptech_engine[i].tech_i, gd->player_i)) { sd->engine = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->engine = actengine; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_man(struct game_s *g, struct game_design_s *gd, int8_t *buf) { shipdesign_t *sd = &(gd->sd); ship_engine_t actman = sd->man; for (int i = 0; i <= sd->engine; ++i) { sd->man = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; } sd->man = actman; game_design_update_engines(sd); return sd->engine; } int game_design_build_tbl_fit_weapon(struct game_s *g, struct game_design_s *gd, int8_t *buf, int wslot, weapon_group_t wgroup) { shipdesign_t *sd = &(gd->sd); weapon_t actwpnt = sd->wpnt[wslot]; uint8_t actwpnn = sd->wpnn[wslot]; int last = 0; buf[0] = 1/*HAVE*/; for (int i = 1; i < WEAPON_NUM; ++i) { tech_field_t fi; weapon_group_t group; bool match; fi = tbl_shiptech_weap[i].is_bio ? TECH_FIELD_PLANETOLOGY : TECH_FIELD_WEAPON; group = game_design_get_weapon_group(g, &(tbl_shiptech_weap[i])); match = (wgroup == WEAPON_GROUP_ALL) || (wgroup == group); if (game_tech_player_has_tech(g, fi, tbl_shiptech_weap[i].tech_i, gd->player_i) && match) { uint8_t n; sd->wpnt[wslot] = i; /* TODO use binary search */ for (n = 1; n < 100; ++n) { sd->wpnn[wslot] = n; game_design_update_engines(sd); if (game_design_calc_space(gd) < 0) { break; } } buf[i] = n - 1; last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->wpnt[wslot] = actwpnt; sd->wpnn[wslot] = actwpnn; game_design_update_engines(sd); return last; } int game_design_build_tbl_fit_special(struct game_s *g, struct game_design_s *gd, int8_t *buf, int sslot) { shipdesign_t *sd = &(gd->sd); ship_special_t actspec = sd->special[sslot]; int last = 0; uint8_t othertype[SPECIAL_SLOT_NUM - 1]; { int j, n; for (j = 0, n = 0; j < SPECIAL_SLOT_NUM; ++j) { if (j != sslot) { othertype[n++] = tbl_shiptech_special[sd->special[j]].type; } } } buf[0] = 1/*HAVE*/; for (int i = 1; i < SHIP_SPECIAL_NUM; ++i) { if (game_tech_player_has_tech(g, tbl_shiptech_special[i].field, tbl_shiptech_special[i].tech_i, gd->player_i)) { bool flag_check; uint8_t thistype; flag_check = true; thistype = tbl_shiptech_special[i].type; for (int j = 0; j < SPECIAL_SLOT_NUM - 1; ++j) { if (thistype == othertype[j]) { flag_check = false; buf[i] = 0/*NOPE*/; break; } } if (flag_check) { sd->special[sslot] = i; game_design_update_engines(sd); buf[i] = (game_design_calc_space(gd) >= 0) ? 1/*HAVE*/ : 0/*NOPE*/; } last = i; } else { buf[i] = -1/*NO_TECH*/; } } sd->special[sslot] = actspec; game_design_update_engines(sd); return last; } void game_design_compact_slots(shipdesign_t *sd) { for (int loops = 0; loops < SPECIAL_SLOT_NUM; ++loops) { for (int i = 0; i < SPECIAL_SLOT_NUM - 1; ++i) { if (sd->special[i] == 0) { sd->special[i] = sd->special[i + 1]; sd->special[i + 1] = 0; } } } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { if ((sd->wpnt[i] == 0) || (sd->wpnn[i] == 0)) { sd->wpnt[i] = 0; sd->wpnn[i] = 0; } } for (int loops = 0; loops < WEAPON_SLOT_NUM; ++loops) { for (int i = 0; i < WEAPON_SLOT_NUM - 1; ++i) { if (sd->wpnt[i] == 0) { sd->wpnt[i] = sd->wpnt[i + 1]; sd->wpnn[i] = sd->wpnn[i + 1]; sd->wpnt[i + 1] = 0; sd->wpnn[i + 1] = 0; } } } } void game_design_scrap(struct game_s *g, player_id_t player, int shipi, bool flag_for_new) { empiretechorbit_t *e = &(g->eto[player]); shipresearch_t *srd = &(g->srd[player]); game_update_maint_costs(g); if ((e->shipdesigns_num <= 1) || (shipi >= e->shipdesigns_num)) { return; } for (int i = shipi; i < (NUM_SHIPDESIGNS - 1); ++i) { srd->year[i] = srd->year[i + 1]; } for (int i = 0; i < g->galaxy_stars; ++i) { fleet_orbit_t *r = &(e->orbit[i]); for (int j = shipi; j < (NUM_SHIPDESIGNS - 1); ++j) { r->ships[j] = r->ships[j + 1]; } r->ships[NUM_SHIPDESIGNS - 1] = 0; } for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); if (r->owner == player) { for (int j = shipi; j < (NUM_SHIPDESIGNS - 1); ++j) { r->ships[j] = r->ships[j + 1]; } r->ships[NUM_SHIPDESIGNS - 1] = 0; } } e->reserve_bc += (srd->shipcount[shipi] * srd->design[shipi].cost) / 4; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); int bs; bs = p->buildship; if ((p->owner == player) && (bs != BUILDSHIP_STARGATE)) { if (bs == shipi) { if (!IS_HUMAN(g, player) || (!flag_for_new)) { p->buildship = 0; } else { p->buildship = e->shipdesigns_num - 1; } } else if (bs > shipi) { p->buildship = --bs; } } } util_table_remove_item_keep_order(shipi, srd->design, sizeof(shipdesign_t), NUM_SHIPDESIGNS); game_remove_empty_fleets(g); game_update_visibility(g); --e->shipdesigns_num; game_update_maint_costs(g); game_update_have_reserve_fuel(g); } bool game_design_add(struct game_s *g, player_id_t player, const shipdesign_t *sd, bool update_reserve_fuel) { empiretechorbit_t *e = &(g->eto[player]); int num = e->shipdesigns_num; if (num < NUM_SHIPDESIGNS) { shipresearch_t *srd = &(g->srd[player]); srd->design[num] = *sd; srd->year[num] = g->year; e->shipdesigns_num = ++num; if (update_reserve_fuel) { game_update_have_reserve_fuel(g); } return true; } else { return false; } } void game_design_set_hp(shipdesign_t *sd) { sd->hp = (tbl_shiptech_hull[sd->hull].hits * tbl_shiptech_armor[sd->armor].armor) / 100; } void game_design_update_haveflags(struct design_data_s *d) { shipdesign_t *sd = &(d->gd->sd); SETRANGE(sd->man, 0, sd->engine); game_design_update_engines(sd); sd->cost = game_design_calc_cost(d->gd); sd->space = game_design_calc_space(d->gd); game_design_set_hp(sd); d->flag_disable_cspeed = true; if (sd->man < sd->engine) { ++sd->man; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_cspeed = false; } --sd->man; } d->flag_disable_comp = true; { ship_comp_t actcomp = sd->comp; ship_comp_t comp = actcomp; while (++comp < SHIP_COMP_NUM) { if (game_tech_player_has_tech(d->g, TECH_FIELD_COMPUTER, tbl_shiptech_comp[comp].tech_i, d->gd->player_i)) { sd->comp = comp; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_comp = false; break; } } } sd->comp = actcomp; } d->flag_disable_jammer = true; { ship_jammer_t actjammer = sd->jammer; ship_jammer_t jammer = actjammer; while (++jammer < SHIP_JAMMER_NUM) { if (game_tech_player_has_tech(d->g, TECH_FIELD_COMPUTER, tbl_shiptech_jammer[jammer].tech_i, d->gd->player_i)) { sd->jammer = jammer; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_jammer = false; break; } } } sd->jammer = actjammer; } d->flag_disable_shield = true; { ship_shield_t actshield = sd->shield; ship_shield_t shield = actshield; while (++shield < SHIP_SHIELD_NUM) { if (game_tech_player_has_tech(d->g, TECH_FIELD_FORCE_FIELD, tbl_shiptech_shield[shield].tech_i, d->gd->player_i)) { sd->shield = shield; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_shield = false; break; } } } sd->shield = actshield; } d->flag_disable_armor = true; { ship_armor_t actarmor = sd->armor; ship_armor_t armor = actarmor; while (++armor < SHIP_ARMOR_NUM) { if (game_tech_player_has_tech(d->g, TECH_FIELD_CONSTRUCTION, tbl_shiptech_armor[armor].tech_i, d->gd->player_i)) { sd->armor = armor; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_armor = false; break; } } } sd->armor = actarmor; } d->flag_disable_engine = true; { ship_engine_t actengine = sd->engine; ship_engine_t engine = actengine; while (++engine < SHIP_ENGINE_NUM) { if (game_tech_player_has_tech(d->g, TECH_FIELD_PROPULSION, tbl_shiptech_engine[engine].tech_i, d->gd->player_i)) { sd->engine = engine; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_disable_engine = false; break; } } } sd->engine = actengine; } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi, actwi; int wn; wi = actwi = sd->wpnt[i]; wn = sd->wpnn[i]; d->flag_tbl_weap_dn[i] = ((wn == 0) || (wi == WEAPON_NONE)) ? 1 : 0; d->flag_tbl_weap_up[i] = 1; if ((wi != WEAPON_NONE) && (wn < 99)) { sd->wpnn[i] = wn + 1; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_tbl_weap_up[i] = 0; } sd->wpnn[i] = wn; } d->flag_tbl_weapon[i] = true; while (++wi <= d->last_avail_tech_weap) { tech_field_t fi; fi = tbl_shiptech_weap[wi].is_bio ? TECH_FIELD_PLANETOLOGY : TECH_FIELD_WEAPON; if (game_tech_player_has_tech(d->g, fi, tbl_shiptech_weap[wi].tech_i, d->gd->player_i)) { sd->wpnt[i] = wi; sd->wpnn[i] = 1; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_tbl_weapon[i] = false; break; } } } sd->wpnt[i] = actwi; sd->wpnn[i] = wn; } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t otherspecial[SPECIAL_SLOT_NUM - 1]; ship_special_t actsi, si; si = actsi = sd->special[i]; { int j, n; for (j = 0, n = 0; j < SPECIAL_SLOT_NUM; ++j) { if (i != j) { otherspecial[n++] = sd->special[j]; } } } d->flag_tbl_special[i] = true; while (++si <= d->last_avail_tech_special) { bool flag_check; flag_check = true; for (int j = 0; j < SPECIAL_SLOT_NUM - 1; ++j) { ship_special_t osi; osi = otherspecial[j]; if ((si == osi) || (tbl_shiptech_special[si].type == tbl_shiptech_special[osi].type)) { flag_check = false; break; } } if (flag_check && game_tech_player_has_tech(d->g, tbl_shiptech_special[si].field, tbl_shiptech_special[si].tech_i, d->gd->player_i)) { sd->special[i] = si; game_design_update_engines(sd); if (game_design_calc_space(d->gd) >= 0) { d->flag_tbl_special[i] = false; break; } } } sd->special[i] = actsi; } { ship_hull_t acthull; acthull = sd->hull; for (ship_hull_t i = SHIP_HULL_SMALL; i < SHIP_HULL_NUM; ++i) { sd->hull = i; game_design_update_engines(sd); d->flag_tbl_hull[i] = (game_design_calc_space(d->gd) < 0); } sd->hull = acthull; } game_design_update_engines(sd); } void game_design_init_maxtech_haveflags(struct design_data_s *d) { { weapon_t j = 0; for (weapon_t wi = WEAPON_NUCLEAR_BOMB; wi < WEAPON_NUM; ++wi) { tech_field_t fi; fi = tbl_shiptech_weap[wi].is_bio ? TECH_FIELD_PLANETOLOGY : TECH_FIELD_WEAPON; if (game_tech_player_has_tech(d->g, fi, tbl_shiptech_weap[wi].tech_i, d->gd->player_i)) { j = wi; } } d->last_avail_tech_weap = j; } { ship_special_t j = 0; for (ship_special_t si = SHIP_SPECIAL_RESERVE_FUEL_TANKS; si < SHIP_SPECIAL_NUM; ++si) { if (game_tech_player_has_tech(d->g, tbl_shiptech_special[si].field, tbl_shiptech_special[si].tech_i, d->gd->player_i)) { j = si; } } d->last_avail_tech_special = j; } game_design_update_haveflags(d); } 1oom-1.11.2/src/game/game_design.h000066400000000000000000000077471476061725400166150ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_DESIGN_H #define INC_1OOM_GAME_DESIGN_H #include "game_shipdesign.h" #include "game_shiptech.h" #include "game_types.h" #include "types.h" struct game_design_s { shipdesign_t sd; char names[SHIP_HULL_NUM][SHIP_NAME_LEN + 1]; uint8_t percent[TECH_FIELD_NUM]; player_id_t player_i; int lookbase; int sd_num; uint8_t tbl_shiplook[NUM_SHIPDESIGNS]; uint8_t tbl_shiplook_hull[SHIP_HULL_NUM]; }; typedef enum { DESIGN_SLOT_COMP, /*1*/ DESIGN_SLOT_SHIELD, /*2*/ DESIGN_SLOT_JAMMER, /*3*/ DESIGN_SLOT_ARMOR, /*4*/ DESIGN_SLOT_ENGINE, /*5*/ DESIGN_SLOT_MAN, /*6*/ DESIGN_SLOT_SPECIAL1, /*7*/ DESIGN_SLOT_SPECIAL2, /*8*/ DESIGN_SLOT_SPECIAL3, /*14*/ DESIGN_SLOT_WEAPON1, /*9*/ DESIGN_SLOT_WEAPON2, /*10*/ DESIGN_SLOT_WEAPON3, /*11*/ DESIGN_SLOT_WEAPON4 /*15*/ } design_slot_t; typedef enum { WEAPON_GROUP_ALL, WEAPON_GROUP_BEAMS, WEAPON_GROUP_KINETIC, WEAPON_GROUP_BOMBS, WEAPON_GROUP_MISSILES, WEAPON_GROUP_BIOLOGICAL, WEAPON_GROUP_SPECIAL, WEAPON_GROUP_NUM, } weapon_group_t; struct game_s; struct game_aux_s; struct design_data_s { struct game_s *g; struct game_design_s *gd; player_id_t api; weapon_t last_avail_tech_weap; ship_special_t last_avail_tech_special; bool flag_disable_cspeed; bool flag_disable_comp; bool flag_disable_jammer; bool flag_disable_shield; bool flag_disable_armor; bool flag_disable_engine; bool flag_tbl_weapon[WEAPON_SLOT_NUM]; bool flag_tbl_special[SPECIAL_SLOT_NUM]; bool flag_tbl_hull[SHIP_HULL_NUM]; int16_t flag_tbl_weap_up[WEAPON_SLOT_NUM]; /* HACK int16_t for uiobj */ int16_t flag_tbl_weap_dn[WEAPON_SLOT_NUM]; /* HACK int16_t for uiobj */ }; extern void game_design_prepare(struct game_s *g, struct game_design_s *gd, player_id_t player, shipdesign_t *sd); extern void game_design_prepare_ai(struct game_s *g, struct game_design_s *gd, player_id_t player, ship_hull_t hull, uint8_t look); extern void game_design_update_engines(shipdesign_t *sd); extern int game_design_get_hull_space(const struct game_design_s *gd); extern int game_design_calc_space(struct game_design_s *gd); extern int game_design_calc_space_item(struct game_design_s *gd, design_slot_t slot, int itemi); extern int game_design_calc_cost(struct game_design_s *gd); extern int game_design_calc_cost_item(struct game_design_s *gd, design_slot_t slot, int itemi); extern void game_design_clear(struct game_design_s *gd); extern void game_design_look_next(struct game_design_s *gd); extern void game_design_look_prev(struct game_design_s *gd); extern void game_design_look_fix(const struct game_s *g, player_id_t pi, shipdesign_t *sd); extern int game_design_build_tbl_fit_comp(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_shield(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_jammer(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_armor(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_engine(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_man(struct game_s *g, struct game_design_s *gd, int8_t *buf); extern int game_design_build_tbl_fit_weapon(struct game_s *g, struct game_design_s *gd, int8_t *buf, int wslot, weapon_group_t wgroup); extern int game_design_build_tbl_fit_special(struct game_s *g, struct game_design_s *gd, int8_t *buf, int sslot); extern void game_design_compact_slots(shipdesign_t *sd); extern void game_design_scrap(struct game_s *g, player_id_t player, int shipi, bool flag_for_new); extern bool game_design_add(struct game_s *g, player_id_t player, const shipdesign_t *sd, bool update_reserve_fuel); extern void game_design_set_hp(shipdesign_t *sd); extern void game_design_update_haveflags(struct design_data_s *d); extern void game_design_init_maxtech_haveflags(struct design_data_s *d); #endif 1oom-1.11.2/src/game/game_diplo.c000066400000000000000000000335271476061725400164410ustar00rootroot00000000000000#include "config.h" #include /* abs */ #include "game_diplo.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_num.h" #include "game_planet.h" #include "game_spy.h" #include "game_tech.h" #include "rnd.h" #include "types.h" /* -------------------------------------------------------------------------- */ const int16_t game_diplo_tbl_reldiff[6] = { -50, -30, -20, 0, 10, 20 }; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void game_diplo_act(struct game_s *g, int dv, player_id_t pi, player_id_t pi2, int dtype, uint8_t pli1, int16_t dp2) { empiretechorbit_t *e = &(g->eto[pi]); empiretechorbit_t *e2 = &(g->eto[pi2]); int v1; if (g->end == GAME_END_FINAL_WAR) { if (IS_AI(g, pi) && (dv < 0) && IS_HUMAN(g, pi2) && BOOLVEC_IS1(g->refuse, pi2) && (rnd_1_n(100, &g->seed) <= (dv / -10))) { player_id_t i = g->winner; e2->diplo_val[i] = 100; e2->diplo_type[i] = 59; e2->diplo_p2[i] = dp2; e2->diplo_p1[i] = pli1; } return; } if (0 || (pi >= g->players) || (pi2 >= g->players) || (pi == pi2) || (dv == 0) || IS_HUMAN(g, pi2) || (e->treaty[pi2] == TREATY_FINAL_WAR) ) { return; } if (dv == -10000) { if (IS_HUMAN(g, pi) && (dtype != 0)) { e->diplo_val[pi2] = 10000; e->diplo_type[pi2] = dtype; e->diplo_p2[pi2] = dp2; e->diplo_p1[pi2] = pli1; } return; } if (dv > 0) { if (e2->relation1[pi] < 0) { dv *= 2; if ((e2->relation1[pi] + dv) > 10) { dv = 10 - e2->relation1[pi]; } } else { int v4 = e2->relation1[pi] / 25 + 1; if (v4 == 0) { v4 = 1; } dv /= v4; } } else { if (e2->relation1[pi] > 0) { dv *= 2; } else { int v4 = e2->relation1[pi] / -25 + 1; if (v4 == 0) { v4 = 1; } dv /= v4; } } if ((e2->trait1 == TRAIT1_HONORABLE) && (dv < 0)) { dv *= 2; } if ((e2->trait1 == TRAIT1_XENOPHOBIC) && (dv < 0)) { dv = (dv * 3) / 2; } if ((e2->trait1 == TRAIT1_XENOPHOBIC) && (dv > 0)) { dv = (dv * 3) / 4; } v1 = dv; if ((e->race == RACE_HUMAN) && (dv > 0)) { dv *= 2; } if ((e2->treaty[pi] == TREATY_WAR) && (dtype >= 4) && (dtype <= 12) && (dv < 0)) { if (IS_HUMAN(g, pi)) { e2->mood_peace[pi] += dv / 4; e->mood_peace[pi2] -= dv / 4; } dv = 0; } if (IS_AI(g, pi) && IS_AI(g, pi2) && (g->year > 100)) { if (dv > 0) { dv *= 2; } if (dv < 0) { dv /= (g->difficulty / 2 + 1); } } if (dv != 0) { int v = e2->relation1[pi]; v += dv; SETRANGE(v, -100, 100); e2->relation1[pi] = v; e2->mood_treaty[pi] += dv; e->mood_treaty[pi2] = e2->mood_treaty[pi]; e2->mood_trade[pi] += dv; e->mood_trade[pi2] = e2->mood_trade[pi]; e2->mood_tech[pi] += dv; e->mood_tech[pi2] = e2->mood_tech[pi]; if (v1 < 0) { e->mood_peace[pi2] -= v1 / 4; e2->mood_peace[pi] += v1 / 4; } else { e2->mood_peace[pi] += v1; } if (IS_HUMAN(g, pi) && (dtype != 0) && (abs(dv) > abs(e->diplo_val[pi2]))) { e->diplo_val[pi2] = dv; e->diplo_type[pi2] = dtype; e->diplo_p2[pi2] = dp2; e->diplo_p1[pi2] = pli1; } } if (e2->treaty[pi] >= TREATY_WAR) { SETMAX(e2->relation1[pi], -25); } if (e2->treaty[pi] != TREATY_ALLIANCE) { SETMIN(e2->relation1[pi], 65); } e->relation1[pi2] = e2->relation1[pi]; } void game_diplo_break_treaty(struct game_s *g, player_id_t breaker, player_id_t victim) { empiretechorbit_t *eb, *ev; int w; if ((breaker >= PLAYER_NUM) || (victim >= PLAYER_NUM)) { return; } eb = &(g->eto[breaker]); ev = &(g->eto[victim]); if (ev->treaty[breaker] >= TREATY_WAR) { return; } w = 0; if (eb->treaty[victim] == TREATY_NONAGGRESSION) { w = -10; } if (eb->treaty[victim] == TREATY_ALLIANCE) { w = -20; } if (g->ai_id != GAME_AI_CLASSIC) { w = -w; } if (eb->trait1 == TRAIT1_HONORABLE) { w *= 2; } eb->trust[victim] -= w; if (eb->treaty[victim] == TREATY_ALLIANCE) { int v = eb->relation2[victim]; v -= w; SETMAX(v, -100); eb->relation2[victim] = v; ev->relation2[breaker] = v; } if (w != 0) { int v; eb->broken_treaty[victim] = eb->treaty[victim]; if (g->ai_id == GAME_AI_CLASSIC) { /* WASBUG MOO1 blames both parties for breaking treaties */ ev->broken_treaty[breaker] = eb->treaty[victim]; } v = eb->relation1[victim] - rnd_1_n(20, &g->seed); SETMAX(v, -100); eb->relation1[victim] = v; ev->relation1[breaker] = v; } eb->treaty[victim] = TREATY_NONE; ev->treaty[breaker] = TREATY_NONE; eb->attack_bounty[victim] = PLAYER_NONE; ev->attack_bounty[breaker] = PLAYER_NONE; eb->mood_treaty[victim] = -200; eb->mood_trade[victim] = -200; eb->mood_tech[victim] = -200; eb->mood_peace[victim] = -200; ev->mood_treaty[breaker] = -200; ev->mood_trade[breaker] = -200; ev->mood_tech[breaker] = -200; ev->mood_peace[breaker] = -200; } void game_diplo_start_war(struct game_s *g, player_id_t pi, player_id_t pi2) { empiretechorbit_t *e, *e2; if ((pi >= PLAYER_NUM) || (pi2 >= PLAYER_NUM)) { return; } e = &(g->eto[pi]); e2 = &(g->eto[pi2]); if (IS_HUMAN(g, pi) && (e->have_met[pi2] == 0)) { e->have_met[pi2] = 1; } if (IS_HUMAN(g, pi2) && (e2->have_met[pi] == 0)) { e2->have_met[pi] = 1; } if (e->treaty[pi2] >= TREATY_WAR) { return; } /*6165b*/ game_diplo_break_trade(g, pi, pi2); game_diplo_break_treaty(g, pi, pi2); e->relation2[pi2] -= 5; e2->relation2[pi] -= 5; e2->relation1[pi] = e->relation1[pi2] = -75 - rnd_1_n(25, &g->seed); e->treaty[pi2] = TREATY_WAR; e2->treaty[pi] = TREATY_WAR; e->mood_treaty[pi2] = -200; e->mood_trade[pi2] = -200; e->mood_tech[pi2] = -200; e->mood_peace[pi2] = -130; e2->mood_treaty[pi] = -200; e2->mood_trade[pi] = -200; e2->mood_tech[pi] = -200; e2->mood_peace[pi] = -130; } void game_diplo_start_war_swap(struct game_s *g, player_id_t pi, player_id_t pi2) { if (g->ai_id != GAME_AI_CLASSIC) { /* WASBUG? game_diplo_start_war is called in a few places using odd order of parameters */ player_id_t t = pi; pi = pi2; pi2 = t; } game_diplo_start_war(g, pi, pi2); } void game_diplo_break_trade(struct game_s *g, player_id_t pi, player_id_t pi2) { empiretechorbit_t *e, *e2; if ((pi >= PLAYER_NUM) || (pi2 >= PLAYER_NUM)) { return; } e = &(g->eto[pi]); e2 = &(g->eto[pi2]); e->trade_bc[pi2] = 0; e2->trade_bc[pi] = 0; e->trade_established_bc[pi2] = 0; e2->trade_established_bc[pi] = 0; e->trade_percent[pi2] = 0; e2->trade_percent[pi] = 0; e->attack_bounty[pi2] = PLAYER_NONE; e2->attack_bounty[pi] = PLAYER_NONE; SETMAX(e->relation1[pi2], -100); e2->relation1[pi] = e->relation1[pi2]; if (e->treaty[pi2] >= TREATY_WAR) { return; } #if 0 if (e->trade_bc[pi2] != 0) { /* never true */ /* ignored */ } #endif } void game_diplo_annoy(struct game_s *g, player_id_t p1, player_id_t p2, int n) { empiretechorbit_t *e1 = &(g->eto[p1]); n *= 10; e1->mood_trade[p2] -= n; e1->mood_treaty[p2] -= n; e1->mood_tech[p2] -= n; e1->mood_peace[p2] -= n; } void game_diplo_battle_finish(struct game_s *g, int def, int att, int popdiff, uint32_t app_def, uint16_t biodamage, uint32_t app_att, uint8_t planet_i) { player_id_t claim, side_z, side_ai; uint32_t app_ai; planet_t *p; int offense; if ((att >= PLAYER_NUM) || (def >= PLAYER_NUM)) { return; } p = &(g->planet[planet_i]); claim = p->claim; if ((claim == PLAYER_NONE) || ((claim != att) && (claim != def))) { if (IS_AI(g, att)) { side_z = def; side_ai = att; app_ai = app_att; } else { side_z = att; side_ai = def; app_ai = app_def; } } else { if (claim == att) { side_z = def; side_ai = att; app_ai = app_att; } else { side_z = att; side_ai = def; app_ai = app_def; } } if (biodamage) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != side_z) && IS_AI(g, i)) { game_diplo_act(g, -10, side_z, i, 11, planet_i, 0); } } } popdiff *= 5; SETMIN(app_ai, 50); biodamage *= 10; offense = MAX(popdiff, app_ai); SETMAX(offense, biodamage); if (IS_AI(g, side_ai)) { int extra; if (biodamage > 0) { extra = 11; } else if (popdiff > 0) { extra = 10; } else { extra = 9; } game_diplo_act(g, -offense, side_z, side_ai, extra, planet_i, 0); } if ((offense >= 30) && IS_HUMAN(g, side_z)) { empiretechorbit_t *ea = &(g->eto[side_ai]); empiretechorbit_t *ez = &(g->eto[side_z]); for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (1 && (i != side_z) && (i != side_ai) && IS_AI(g, i) && ((ea->treaty[i] >= TREATY_WAR) || (ez->bounty_collect[i] == side_ai)) /* FIXME BUG? should be attack_bounty? */ ) { if (ez->attack_bounty[i] == side_ai) { ez->bounty_collect[i] = i; } else if (game_planet_get_random(g, side_ai) == PLANET_NONE) { game_diplo_act(g, offense, side_z, i, 3, planet_i, 0); } } } } } void game_diplo_set_treaty(struct game_s *g, player_id_t p1, player_id_t p2, treaty_t treaty) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); e1->treaty[p2] = treaty; e2->treaty[p1] = treaty; } void game_diplo_set_trade(struct game_s *g, player_id_t p1, player_id_t p2, int bc) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); int v; if (bc == 0) { return; } if (e1->trade_established_bc[p2] < bc) { v = ((e1->trade_percent[p2] * e1->trade_established_bc[p2]) - (bc * 30)) / (e1->trade_established_bc[p2] + bc); } else { v = e1->trade_percent[p2]; } SETMIN(v, 100); e1->trade_bc[p2] = bc; e1->trade_established_bc[p2] = bc; /* FIXME BUG? should be < bc to make the variable have a purpose */ e1->trade_percent[p2] = v; e2->trade_bc[p1] = bc; e2->trade_established_bc[p1] = bc; e2->trade_percent[p1] = v; } void game_diplo_stop_war(struct game_s *g, player_id_t p1, player_id_t p2) { empiretechorbit_t *e1 = &(g->eto[p1]); empiretechorbit_t *e2 = &(g->eto[p2]); game_diplo_set_treaty(g, p1, p2, TREATY_NONE); ADDSATT(e1->relation1[p2], 40, 100); e2->relation1[p1] = e1->relation1[p2]; if (IS_HUMAN(g, p1) /* && IS_AI(g, p2) */) { g->evn.ceasefire[p1][p2] = rnd_0_nm1(6, &g->seed) + 8; } if (IS_HUMAN(g, p2) /* && IS_AI(g, p1) */) { g->evn.ceasefire[p2][p1] = rnd_0_nm1(6, &g->seed) + 8; } } void game_diplo_esp_frame(struct game_s *g, player_id_t framed, player_id_t victim) { int v; v = -(rnd_1_n(12, &g->seed) + rnd_1_n(12, &g->seed)); game_diplo_act(g, v, framed, victim, 5, 0, 0); } void game_diplo_limit_mood_treaty(struct game_s *g) { for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e = &(g->eto[p1]); for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { if (p1 != p2) { SETRANGE(e->mood_treaty[p2], -200, 120); } } } } void game_diplo_mood_relax(struct game_s *g) { for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e = &(g->eto[p1]); for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { if (p1 != p2) { if (e->mood_treaty[p2] < 100) { e->mood_treaty[p2] += 10; } if (e->mood_trade[p2] < 100) { e->mood_trade[p2] += 10; } if (e->mood_tech[p2] < 100) { e->mood_tech[p2] += 10; } if (e->mood_peace[p2] < 100) { e->mood_peace[p2] += 10; } } } } } int16_t game_diplo_get_mood(struct game_s *g, player_id_t p1, player_id_t p2) { if (g->end == GAME_END_FINAL_WAR) { return 0; } else { empiretechorbit_t *e = &(g->eto[p1]); int16_t vmin, v; vmin = e->mood_treaty[p2]; v = e->mood_trade[p2]; SETMIN(vmin, v); v = e->mood_tech[p2]; SETMIN(vmin, v); v = e->mood_peace[p2]; SETMIN(vmin, v); return vmin; } } bool game_diplo_is_gone(struct game_s *g, player_id_t api, player_id_t pi) { if (IS_HUMAN(g, pi)) { return false; /* FIXME remote multiplayer */ } else { const empiretechorbit_t *e = &(g->eto[api]); int16_t v, vr; vr = game_diplo_get_mood(g, api, pi); v = e->trust[pi] /*+ e->relation1[pi]*/ + vr + game_diplo_tbl_reldiff[g->eto[pi].trait1]; if (((v /*- e->relation1[pi]*/) <= -100) || (vr <= -100)) { return true; } } return false; } 1oom-1.11.2/src/game/game_diplo.h000066400000000000000000000030551476061725400164370ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_DIPLO_H #define INC_1OOM_GAME_DIPLO_H #include "game_types.h" #include "types.h" struct game_s; extern const int16_t game_diplo_tbl_reldiff[6]; extern void game_diplo_act(struct game_s *g, int dv, player_id_t pi, player_id_t pi2, int dtype, uint8_t pli1, int16_t dp2); extern void game_diplo_break_treaty(struct game_s *g, player_id_t breaker, player_id_t victim); extern void game_diplo_start_war(struct game_s *g, player_id_t pi1, player_id_t pi2); extern void game_diplo_start_war_swap(struct game_s *g, player_id_t pi1, player_id_t pi2); extern void game_diplo_break_trade(struct game_s *g, player_id_t pi/*breaker*/, player_id_t pi2); extern void game_diplo_annoy(struct game_s *g, player_id_t pi1, player_id_t pi2, int n); extern void game_diplo_battle_finish(struct game_s *g, int def, int att, int popdiff, uint32_t app_def, uint16_t biodamage, uint32_t app_att, uint8_t planet_i); extern void game_diplo_set_treaty(struct game_s *g, player_id_t pi1, player_id_t pi2, treaty_t treaty); extern void game_diplo_set_trade(struct game_s *g, player_id_t pi1, player_id_t pi2, int bc); extern void game_diplo_stop_war(struct game_s *g, player_id_t pi1, player_id_t pi2); extern void game_diplo_esp_frame(struct game_s *g, player_id_t framed, player_id_t victim); extern void game_diplo_limit_mood_treaty(struct game_s *g); extern void game_diplo_mood_relax(struct game_s *g); extern int16_t game_diplo_get_mood(struct game_s *g, player_id_t p1, player_id_t p2); extern bool game_diplo_is_gone(struct game_s *g, player_id_t api, player_id_t pi); #endif 1oom-1.11.2/src/game/game_election.c000066400000000000000000000247711476061725400171350ustar00rootroot00000000000000#include "config.h" #include #include #include "game_election.h" #include "boolvec.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_diplo.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "ui.h" /* -------------------------------------------------------------------------- */ static void game_election_prepare(struct election_s *el) { const struct game_s *g = el->g; uint16_t tbl_votes[PLAYER_NUM]; player_id_t tbl_ei[PLAYER_NUM]; int num = 0, total_votes = 0; { bool found_human = false; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (IS_ALIVE(g, i)) { if (IS_HUMAN(g, i)) { el->last_human = i; if (!found_human) { found_human = true; el->first_human = i; continue; } } el->tbl_ei[num] = i; ++num; } } } el->tbl_ei[num] = el->first_human; el->num = num; memset(tbl_votes, 0, sizeof(tbl_votes)); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if ((p->owner != PLAYER_NONE) && (p->unrest != PLANET_UNREST_REBELLION)) { tbl_votes[p->owner] += p->pop; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { uint16_t v; v = tbl_votes[i]; v = (v / 100) + ((v % 100) != 0); tbl_votes[i] = v; total_votes += v; } el->total_votes = total_votes; for (player_id_t i = PLAYER_0; i < PLAYER_NUM; ++i) { tbl_ei[i] = i; el->tbl_votes[i] = tbl_votes[i]; } for (int loops = 0; loops < g->players; ++loops) { for (player_id_t i = PLAYER_0; i < (g->players - 1); ++i) { uint16_t v0, v1; v0 = tbl_votes[i]; v1 = tbl_votes[i + 1]; if (v0 < v1) { tbl_votes[i + 1] = v0; tbl_votes[i] = v1; v0 = tbl_ei[i]; tbl_ei[i] = tbl_ei[i + 1]; tbl_ei[i + 1] = v0; } } } if (IS_AI(g, tbl_ei[0]) && IS_HUMAN(g, tbl_ei[1])) { el->candidate[0] = tbl_ei[1]; el->candidate[1] = tbl_ei[0]; } else { el->candidate[0] = tbl_ei[0]; el->candidate[1] = tbl_ei[1]; } el->flag_show_votes = false; el->got_votes[0] = 0; el->got_votes[1] = 0; el->str = game_str_el_start; el->cur_i = PLAYER_NONE; } static void game_election_accept(struct election_s *el) { struct game_s *g = el->g; BOOLVEC_CLEAR(g->refuse, PLAYER_NUM); for (player_id_t ph = el->first_human; ph <= el->last_human; ++ph) { if (IS_AI(g, ph) || (!IS_ALIVE(g, ph))) { continue; } if (el->first_human == el->last_human) { el->str = game_str_el_accept; } else { lib_sprintf(el->buf, UI_STRBUF_SIZE, "(%s) %s", g->emperor_names[ph], game_str_el_accept); el->str = el->buf; } if (!ui_election_accept(el, ph)) { BOOLVEC_SET1(g->refuse, ph); } } if (!BOOLVEC_IS_CLEAR(g->refuse, PLAYER_NUM)) { for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { if (BOOLVEC_IS1(g->refuse, p1)) { continue; } for (player_id_t ph = el->first_human; ph <= el->last_human; ++ph) { if (BOOLVEC_IS0(g->refuse, ph)) { continue; } game_diplo_break_trade(g, ph, p1); game_diplo_set_treaty(g, ph, p1, TREATY_FINAL_WAR); } for (player_id_t p2 = p1; p2 < g->players; ++p2) { if (BOOLVEC_IS1(g->refuse, p2)) { continue; } game_diplo_set_treaty(g, p1, p2, TREATY_ALLIANCE); } } for (int i = 0; i < el->num; ++i) { if (el->tbl_ei[i] == el->candidate[1]) { el->cur_i = i; break; } } { struct strbuild_s str = strbuild_init(el->buf, UI_STRBUF_SIZE); strbuild_catf(&str, "%s", game_str_el_sobeit); if (g->end == GAME_END_WON_GOOD) { g->winner = el->candidate[1]; strbuild_catf(&str, " %s %s %s", game_str_el_emperor, g->emperor_names[g->winner], game_str_el_isnow); } } game_tech_final_war_share(g); el->str = el->buf; el->ui_delay = 3; ui_election_show(el); g->end = GAME_END_FINAL_WAR; } } /* -------------------------------------------------------------------------- */ const char *game_election_print_votes(uint16_t n, char *buf, size_t bufsize) { if (n == 0) { lib_sprintf(buf, bufsize, "%s %s", game_str_el_no, game_str_el_votes); } else { lib_sprintf(buf, bufsize, "%i %s", n, (n == 1) ? game_str_el_vote : game_str_el_votes); } return buf; } void game_election(struct game_s *g) { struct election_s el[1]; char vbuf[0x20]; el->g = g; el->buf = ui_get_strbuf(); game_election_prepare(el); ui_election_start(el); el->ui_delay = 3; ui_election_show(el); lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s %s %s %s %s %s %s %s %s %s", game_str_el_emperor, g->emperor_names[el->candidate[0]], game_str_el_ofthe, game_str_tbl_races[g->eto[el->candidate[0]].race], game_str_el_and, game_str_el_emperor, g->emperor_names[el->candidate[1]], game_str_el_ofthe, game_str_tbl_races[g->eto[el->candidate[1]].race], game_str_el_nomin ); el->str = el->buf; el->ui_delay = 2; ui_election_show(el); el->flag_show_votes = true; for (int i = 0; i < el->num; ++i) { int votefor, n; player_id_t player; el->cur_i = i; player = el->tbl_ei[i]; el->str = 0; el->ui_delay = 2; ui_election_delay(el, 5); n = el->tbl_votes[player]; if (IS_AI(g, player)) { votefor = game_ai->vote(el, player); } else { lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s (%s%s", g->emperor_names[player], game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_dots); el->str = el->buf; votefor = ui_election_vote(el, player); } if (n == 0) { votefor = 0; } if (votefor == 0) { lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s %s %s%s%s", game_str_el_abs1, game_str_tbl_races[g->eto[player].race], game_str_el_abs2, game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_dots ); g->evn.voted[player] = PLAYER_NONE; game_diplo_act(g, -6, player, el->candidate[1], 0, 0, 0); game_diplo_act(g, -6, player, el->candidate[0], 0, 0, 0); } else { player_id_t pfor; pfor = el->candidate[votefor - 1]; lib_sprintf(el->buf, UI_STRBUF_SIZE, "%i %s %s %s, %s %s %s", n, (n == 1) ? game_str_el_vote : game_str_el_votes, game_str_el_for, g->emperor_names[pfor], game_str_el_emperor, game_str_el_ofthe, game_str_tbl_races[g->eto[pfor].race] ); el->got_votes[votefor - 1] += n; g->evn.voted[player] = pfor; game_diplo_act(g, 24, player, pfor, 0, 0, 0); game_diplo_act(g, -12, player, el->candidate[(votefor - 1) ^ 1], 0, 0, 0); } el->str = el->buf; el->ui_delay = 3; ui_election_show(el); } { int votefor, n; player_id_t player; player = el->first_human; el->str = 0; el->ui_delay = 2; ui_election_delay(el, 5); n = el->tbl_votes[player]; if (g->gaux->local_players > 1) { el->cur_i = el->num; lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s (%s%s", g->emperor_names[player], game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_dots); } else { el->cur_i = PLAYER_NONE; lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s%s%s", game_str_el_your, game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_dots); } el->str = el->buf; votefor = ui_election_vote(el, player); if (n == 0) { votefor = 0; } if (votefor == 0) { g->evn.voted[player] = PLAYER_NONE; game_diplo_act(g, -6, player, el->candidate[1], 0, 0, 0); game_diplo_act(g, -6, player, el->candidate[0], 0, 0, 0); } else { player_id_t pfor, pnot; pfor = el->candidate[votefor - 1]; pnot = el->candidate[(votefor - 1) ^ 1]; el->got_votes[votefor - 1] += n; g->evn.voted[player] = pfor; if (el->candidate[0] == player) { game_diplo_act(g, 24, player, pfor, 0, 0, 0); game_diplo_act(g, -12, player, pnot, 0, 0, 0); } else { game_diplo_act(g, 24, player, pfor, 80, 0, pfor); game_diplo_act(g, -12, player, pnot, 79, 0, pfor); } } } { int winner; for (winner = 0; winner < 2; ++winner) { if ((((el->total_votes + 1) * 2) / 3) <= el->got_votes[winner]) { break; } } if (winner < 2) { g->winner = el->candidate[winner]; lib_sprintf(el->buf, UI_STRBUF_SIZE, "%s %i %s %s %s %s %s", game_str_el_chose1, g->year + YEAR_BASE, game_str_el_chose2, g->emperor_names[g->winner], game_str_el_ofthe, game_str_tbl_races[g->eto[g->winner].race], game_str_el_chose3 /* WASBUG MOO1 has the last period missing if second candidate won */ ); el->str = el->buf; el->cur_i = PLAYER_NONE; if (IS_AI(g, g->winner) || (g->gaux->local_players > 1)) { for (int i = 0; i < (el->num + 1); ++i) { if (el->tbl_ei[i] == g->winner) { el->cur_i = i; break; } } } g->end = IS_HUMAN(g, g->winner) ? GAME_END_WON_GOOD : GAME_END_LOST_EXILE; } else { el->str = game_str_el_neither; el->cur_i = PLAYER_NONE; } el->ui_delay = 3; ui_election_show(el); } if (g->end != GAME_END_NONE) { game_election_accept(el); } ui_election_end(el); } 1oom-1.11.2/src/game/game_election.h000066400000000000000000000011641476061725400171310ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_ELECTION_H #define INC_1OOM_GAME_ELECTION_H #include "game_types.h" struct game_s; struct election_s { struct game_s *g; void *uictx; char *buf; const char *str; int num; player_id_t tbl_ei[PLAYER_NUM]; uint8_t tbl_votes[PLAYER_NUM]; player_id_t candidate[2]; uint16_t total_votes; uint16_t got_votes[2]; player_id_t first_human; player_id_t last_human; int cur_i; bool flag_show_votes; int ui_delay; }; extern const char *game_election_print_votes(uint16_t n, char *buf, size_t bufsize); extern void game_election(struct game_s *g); #endif 1oom-1.11.2/src/game/game_end.h000066400000000000000000000003511476061725400160720ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_END_H #define INC_1OOM_GAME_END_H #include "game_types.h" struct game_end_s { game_end_type_t type; int race; /* or banner_live */ int banner_dead; const char *name; int varnum; }; #endif 1oom-1.11.2/src/game/game_endecode.h000066400000000000000000000052121476061725400170730ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_ENDECODE_H #define INC_1OOM_GAME_ENDECODE_H #define SG_1OOM_EN_DUMMY(_n_) memset(&buf[pos], 0, (_n_)), pos += (_n_) #define SG_1OOM_DE_DUMMY(_n_) pos += (_n_) #define SG_1OOM_EN_U8(_v_) buf[pos++] = (_v_) #define SG_1OOM_DE_U8(_v_) (_v_) = buf[pos++] #define SG_1OOM_EN_U16(_v_) SET_LE_16(&buf[pos], (_v_)), pos += 2 #define SG_1OOM_DE_U16(_v_) (_v_) = GET_LE_16(&buf[pos]), pos += 2 #define SG_1OOM_EN_U32(_v_) SET_LE_32(&buf[pos], (_v_)), pos += 4 #define SG_1OOM_DE_U32(_v_) (_v_) = GET_LE_32(&buf[pos]), pos += 4 #define SG_1OOM_EN_BV(_v_, _n_) do { int l = ((_n_) + 7) / 8; memcpy(&buf[pos], (_v_), l); pos += l; } while (0) #define SG_1OOM_DE_BV(_v_, _n_) do { int l = ((_n_) + 7) / 8; memcpy((_v_), &buf[pos], l); pos += l; } while (0) #define SG_1OOM_EN_TBL_U8(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { buf[pos] = (_v_)[i_]; ++pos; } } while (0) #define SG_1OOM_DE_TBL_U8(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { (_v_)[i_] = buf[pos]; ++pos; } } while (0) #define SG_1OOM_EN_TBL_U16(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { SET_LE_16(&buf[pos], (_v_)[i_]); pos += 2; } } while (0) #define SG_1OOM_DE_TBL_U16(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { (_v_)[i_] = GET_LE_16(&buf[pos]); pos += 2; } } while (0) #define SG_1OOM_EN_TBL_U32(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { SET_LE_32(&buf[pos], (_v_)[i_]); pos += 4; } } while (0) #define SG_1OOM_DE_TBL_U32(_v_, _n_) do { for (int i_ = 0; i_ < (_n_); ++i_) { (_v_)[i_] = GET_LE_32(&buf[pos]); pos += 4; } } while (0) #define SG_1OOM_EN_TBL_TBL_U8(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { buf[pos++] = (_v_)[o_][i_]; } } } while (0) #define SG_1OOM_DE_TBL_TBL_U8(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { (_v_)[o_][i_] = buf[pos++]; } } } while (0) #define SG_1OOM_EN_TBL_TBL_U16(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { SET_LE_16(&buf[pos], (_v_)[o_][i_]); pos += 2; } } } while (0) #define SG_1OOM_DE_TBL_TBL_U16(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { (_v_)[o_][i_] = GET_LE_16(&buf[pos]); pos += 2; } } } while (0) #define SG_1OOM_EN_TBL_TBL_U32(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { SET_LE_32(&buf[pos], (_v_)[o_][i_]); pos += 4; } } } while (0) #define SG_1OOM_DE_TBL_TBL_U32(_v_, _no_, _ni_) do { for (int o_ = 0; o_ < (_no_); ++o_) { for (int i_ = 0; i_ < (_ni_); ++i_) { (_v_)[o_][i_] = GET_LE_32(&buf[pos]); pos += 4; } } } while (0) #endif 1oom-1.11.2/src/game/game_event.c000066400000000000000000001206241476061725400164460ustar00rootroot00000000000000#include "config.h" #include "game_event.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_design.h" #include "game_diplo.h" #include "game_end.h" #include "game_fleet.h" #include "game_misc.h" #include "game_new.h" #include "game_news.h" #include "game_num.h" #include "game_shiptech.h" #include "game_stat.h" #include "game_str.h" #include "game_tech.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ bool game_opt_skip_random_news = false; /* -------------------------------------------------------------------------- */ static player_id_t game_event_new_get_victim(struct game_s *g) { int tbl_planets[PLAYER_NUM], min_planets = 10000, r, sum = 0; player_id_t player; memset(tbl_planets, 0, sizeof(tbl_planets)); for (int pli = 0; pli < g->galaxy_stars; ++pli) { const planet_t *p = &(g->planet[pli]); if (p->owner != PLAYER_NONE) { ++tbl_planets[p->owner]; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (tbl_planets[i] < 4) { tbl_planets[i] = 0; } else if (IS_HUMAN(g, i)) { tbl_planets[i] *= 5; } } for (player_id_t i = PLAYER_0; i < PLAYER_NUM; ++i) { /* FIXME BUG? on < 6 players min is always 0 */ SETMIN(min_planets, tbl_planets[i]); } SETMAX(min_planets, 5); for (player_id_t i = PLAYER_0; i < PLAYER_NUM; ++i) { tbl_planets[i] /= min_planets; if (i < g->players) { SETMAX(tbl_planets[i], 1); sum += tbl_planets[i]; } } r = rnd_0_nm1(sum, &g->seed); for (player = PLAYER_0; (r >= 0) && (player < (g->players - 1));) { r -= tbl_planets[player]; if (r >= 0) { ++player; } } return player; } static player_id_t game_event_new_get_trader(const struct game_s *g, player_id_t player) { const empiretechorbit_t *e = &(g->eto[player]); player_id_t trader = PLAYER_NONE; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != player) && BOOLVEC_IS1(e->contact, i) && (e->trade_bc[i] != 0)) { trader = i; } } return trader; } static void game_monster_set_start(struct game_s *g, monster_t *m) { int x, y, v; uint8_t dest; switch (rnd_0_nm1(4, &g->seed)) { case 0: v = rnd_0_nm1(g->galaxy_h, &g->seed); dest = v * g->galaxy_w; x = 0; y = (v - 1) * 32 + rnd_1_n(12, &g->seed) + 10; break; case 1: v = rnd_0_nm1(g->galaxy_w, &g->seed); dest = v; x = (v - 1) * 28 + rnd_1_n(12, &g->seed) + 30; y = 0; break; case 2: v = rnd_0_nm1(g->galaxy_h, &g->seed); dest = (v + 1) * g->galaxy_w - 1; x = g->galaxy_w * 28; y = (v - 1) * 32 + rnd_1_n(12, &g->seed) + 10; break; default: v = rnd_0_nm1(g->galaxy_w, &g->seed); dest = (g->galaxy_h - 1) * g->galaxy_w + v; x = (v - 1) * 28 + rnd_1_n(12, &g->seed) + 30; y = g->galaxy_h * 32; break; } m->x = x; m->y = y; m->dest = dest; } static void game_monster_set_next_dest(struct game_s *g, monster_t *m) { uint8_t olddest = m->dest; int dest = olddest, w = g->galaxy_w, h = g->galaxy_h; while (dest == olddest) { int x; x = olddest % w; if (x == 0) { dest += rnd_0_nm1(2, &g->seed); } else { /*7da47*/ dest += rnd_1_n((x == (w - 1)) ? 2 : 3, &g->seed) - 2; } /*7da6a*/ if (olddest < w) { dest += rnd_0_nm1(2, &g->seed) * w; } else { /*7da86*/ dest += rnd_1_n(((w * h - w - 1) < olddest) ? 2 : 3, &g->seed) * w - w * 2; } /*7dab3*/ if (0 || (dest < 0) || (dest >= g->galaxy_stars) || (g->planet[dest].type == PLANET_TYPE_NOT_HABITABLE) || (dest == g->evn.planet_orion_i) ) { dest = olddest; } } m->dest = dest; } static void game_event_kill_player(struct game_s *g, player_id_t pi) { g->evn.home[pi] = PLANET_NONE; game_remove_player_fleets(g, pi); BOOLVEC_SET0(g->refuse, pi); } /* -------------------------------------------------------------------------- */ void game_event_new(struct game_s *g) { gameevent_type_t type; int chance; player_id_t player; const empiretechorbit_t *e; uint8_t planet; planet_t *p; if (g->gaux->flag_cheat_events || (game_num_event_roll == 0)) { g->evn.have_plague = 0; g->evn.have_quake = false; g->evn.have_nova = 0; g->evn.have_accident = 0; g->evn.have_assassin = false; g->evn.have_virus = false; g->evn.have_comet = 0; g->evn.have_pirates = 0; g->evn.have_derelict = false; g->evn.crystal.exists = 0; g->evn.amoeba.exists = 0; g->evn.have_enviro = false; g->evn.have_rich = false; g->evn.have_support = false; g->evn.have_poor = false; return; } if (g->evn.year > g->year) { chance = 0; } else { chance = g->year - g->evn.year; } /*eb0c*/ switch (g->difficulty) { case DIFFICULTY_SIMPLE: chance /= 2; break; case DIFFICULTY_EASY: chance = (chance * 2) / 3; break; case DIFFICULTY_AVERAGE: chance = (chance * 3) / 4; break; case DIFFICULTY_HARD: chance = (chance * 4) / 5; break; default: break; } if (rnd_1_n(game_num_event_roll, &g->seed) > chance) { return; } player = game_event_new_get_victim(g); if ((player < PLAYER_0) || (player >= g->players)) { return; } e = &(g->eto[player]); planet = game_planet_get_random(g, player); if ((planet == g->evn.planet_orion_i) || (planet == PLANET_NONE)) { return; } p = &(g->planet[planet]); type = GAME_EVENT_NONE; for (int loops = 0; (loops < 5) && (type == GAME_EVENT_NONE); ++loops) { type = rnd_1_n(GAME_EVENT_NUM - 1, &g->seed); if (0 || BOOLVEC_IS1(g->evn.done, type) || ((type == GAME_EVENT_REBELLION) && (!IS_HUMAN(g, player) || (g->evn.home[player] == planet))) || ((type == GAME_EVENT_QUAKE) && (p->pop < 50)) || (((type == GAME_EVENT_CRYSTAL) || (type == GAME_EVENT_AMOEBA)) && (g->year < 200)) || (((type == GAME_EVENT_CRYSTAL) || (type == GAME_EVENT_AMOEBA)) && (g->evn.crystal.exists || g->evn.amoeba.exists)) || ((type == GAME_EVENT_DERELICT) && IS_HUMAN(g, player)) || ((type == GAME_EVENT_ASSASSIN) && (g->end != GAME_END_NONE)) || ((type == GAME_EVENT_COMET) && (g->year < 100)) || ((type == GAME_EVENT_PIRATES) && (game_event_new_get_trader(g, player) == PLAYER_NONE)) || (((type == GAME_EVENT_ACCIDENT) || (type == GAME_EVENT_PLAGUE)) && (e->race == RACE_SILICOID)) /* The OSG claims that the industrial accident event only happens on * planets with at least 30 factories. This is not true for MOO 1.3, * but we optionally check for it if accident_chk_factories is set in * a pbx file. */ || ((type == GAME_EVENT_ACCIDENT) && game_num_accident_chk_factories && (p->factories < 30)) || ((type == GAME_EVENT_ENVIRO) && (p->type < PLANET_TYPE_MINIMAL)) || ((type == GAME_EVENT_ENVIRO) && ((p->growth >= PLANET_GROWTH_FERTILE) || (p->special > PLANET_SPECIAL_NORMAL))) || ((type == GAME_EVENT_RICH) && (p->special > PLANET_SPECIAL_NORMAL)) || ((type == GAME_EVENT_RICH) && (p->special == PLANET_SPECIAL_ARTIFACTS)) || ((type == GAME_EVENT_POOR) && (p->special < PLANET_SPECIAL_NORMAL)) || ((type == GAME_EVENT_POOR) && (p->special == PLANET_SPECIAL_ARTIFACTS)) ) { type = GAME_EVENT_NONE; } if (type == GAME_EVENT_ASSASSIN) { bool found; found = false; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (1 && (i != player) && IS_AI(g, i) && (e->treaty[i] >= TREATY_NONAGGRESSION) && (e->treaty[i] <= TREATY_ALLIANCE) ) { found = true; } } if (!found) { type = GAME_EVENT_NONE; } } } /*edef*/ if (type == GAME_EVENT_NONE) { return; } g->evn.year = g->year; BOOLVEC_SET1(g->evn.done, type); #if 0 /* result is unused */ switch (g->difficulty) { case DIFFICULTY_SIMPLE: va = g->year / 20; break; case DIFFICULTY_EASY: va = g->year / 18; break; case DIFFICULTY_AVERAGE: va = g->year / 15; break; case DIFFICULTY_HARD: va = g->year / 13; break; case DIFFICULTY_IMPOSSIBLE: va = g->year / 10; break; default: break; } #endif switch (type) { case GAME_EVENT_PLAGUE: g->evn.have_plague = 1; g->evn.plague_player = player; g->evn.plague_planet_i = planet; g->evn.plague_val = (rnd_1_n(8, &g->seed) + g->difficulty * 2) * p->prod_after_maint; break; case GAME_EVENT_QUAKE: g->evn.have_quake = true; g->evn.quake_player = player; g->evn.quake_planet_i = planet; break; case GAME_EVENT_NOVA: g->evn.have_nova = 1; g->evn.nova_player = player; g->evn.nova_planet_i = planet; g->evn.nova_years = rnd_1_n(5, &g->seed) + 10 - g->difficulty; g->evn.nova_val = (rnd_1_n(5, &g->seed) + 10 - g->difficulty) * p->prod_after_maint; break; case GAME_EVENT_ACCIDENT: g->evn.have_accident = 1; g->evn.accident_player = player; g->evn.accident_planet_i = planet; break; case GAME_EVENT_ASSASSIN: g->evn.have_assassin = true; g->evn.assassin_player = player; { player_id_t player2; player2 = PLAYER_NONE; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (1 && (i != player) && IS_AI(g, i) && (e->treaty[i] >= TREATY_NONAGGRESSION) && (e->treaty[i] <= TREATY_ALLIANCE) ) { player2 = i; } } g->evn.assassin_player2 = player2; } break; case GAME_EVENT_VIRUS: g->evn.have_virus = true; g->evn.virus_player = player; { int v; v = rnd_0_nm1(4, &g->seed); switch (v) { case 0: v = TECH_FIELD_COMPUTER; break; case 1: v = TECH_FIELD_FORCE_FIELD; break; case 2: v = TECH_FIELD_PROPULSION; break; default: v = TECH_FIELD_WEAPON; break; } g->evn.virus_field = v; } break; case GAME_EVENT_COMET: g->evn.have_comet = 1; g->evn.comet_player = player; g->evn.comet_planet_i = planet; g->evn.comet_years = rnd_1_n(5, &g->seed) + 10 - g->difficulty; g->evn.comet_hp = (rnd_1_n(5, &g->seed) + 10 + g->difficulty) * 25; g->evn.comet_dmg = 0; break; case GAME_EVENT_PIRATES: g->evn.have_pirates = 1; g->evn.pirates_planet_i = rnd_0_nm1(g->galaxy_stars, &g->seed); g->evn.pirates_hp = (rnd_1_n(5, &g->seed) + 10 + g->difficulty) * 30; break; case GAME_EVENT_DERELICT: g->evn.have_derelict = true; g->evn.derelict_player = player; break; case GAME_EVENT_REBELLION: p->rebels = p->pop / 2; p->unrest = PLANET_UNREST_REBELLION; p->unrest_reported = false; break; case GAME_EVENT_CRYSTAL: case GAME_EVENT_AMOEBA: { monster_t *m = (type == GAME_EVENT_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); m->exists = 1; m->counter = 2; m->nuked = 0; m->killer = PLAYER_NONE; game_monster_set_start(g, m); } break; case GAME_EVENT_ENVIRO: g->evn.have_enviro = true; g->evn.enviro_planet_i = planet; break; case GAME_EVENT_RICH: g->evn.have_rich = true; g->evn.rich_planet_i = planet; break; case GAME_EVENT_SUPPORT: g->evn.have_support = true; g->evn.support_player = player; break; case GAME_EVENT_POOR: g->evn.have_poor = true; g->evn.poor_planet_i = planet; break; default: break; } } bool game_event_run(struct game_s *g, struct game_end_s *ge) { struct news_s ns; bool any_news = false; ui_news_start(); if (g->evn.have_plague) { uint8_t pli = g->evn.plague_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = g->evn.plague_player; if (p->owner == player) { empiretechorbit_t *e = &(g->eto[player]); if (g->evn.have_plague != 1) { int v; v = game_get_tech_prod(p->prod_after_maint, p->slider[PLANET_SLIDER_TECH], e->race, p->special); g->evn.plague_val -= v; v = ((rnd_1_n(6, &g->seed) + 4) * p->pop) / 100; SETMIN(v, p->pop); p->pop -= v; ns.num1 = v; } else { ns.num1 = 0; /* WASBUG MOO1 uses uninitialized stack variable */ } ns.num2 = g->evn.plague_val; ns.type = GAME_NEWS_PLAGUE; ns.planet_i = pli; ns.race = e->race; if (g->evn.plague_val <= 0) { g->evn.have_plague = 3; } switch (g->evn.have_plague) { case 1: ns.subtype = IS_HUMAN(g, player) ? 0 : 4; break; case 2: ns.subtype = (IS_HUMAN(g, player) && (!rnd_0_nm1(10, &g->seed))) ? 1 : -1; break; case 3: ns.subtype = IS_HUMAN(g, player) ? 2 : 5; break; default: ns.subtype = -1; break; } /*f48e*/ if (g->evn.have_plague == 1) { g->evn.have_plague = 2; } if (g->evn.have_plague == 3) { g->evn.have_plague = 0; } if (ns.subtype != -1) { ui_news(g, &ns); any_news = true; } if (IS_AI(g, player)) { game_ai->plague(g, pli); } } else { g->evn.have_plague = 0; } } /*f4ec*/ if (g->evn.have_quake) { uint8_t pli = g->evn.quake_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = g->evn.quake_player; int vp, vf; ns.planet_i = pli; vp = ((rnd_1_n(10, &g->seed) + 20) * p->pop) / 100; vf = ((rnd_1_n(50, &g->seed) + 30) * p->factories) / 100; SETMIN(vp, p->pop); SETMIN(vf, p->factories); ns.num1 = vp; ns.num2 = vf; ns.type = GAME_NEWS_QUAKE; ns.planet_i = pli; ns.race = g->eto[p->owner].race; g->evn.have_quake = false; p->pop -= vp; p->factories -= vf; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; } /*f662*/ if (g->evn.have_nova) { uint8_t pli = g->evn.nova_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = p->owner; if ((g->evn.have_nova != 1) && (player != PLAYER_NONE)) { empiretechorbit_t *e = &(g->eto[player]); int v; v = game_get_tech_prod(p->prod_after_maint, p->slider[PLANET_SLIDER_TECH], e->race, p->special); g->evn.nova_val -= v; if (g->evn.nova_val <= 0) { g->evn.have_nova = 3; } --g->evn.nova_years; } /*f718*/ if ((g->evn.nova_years <= 0) && (g->evn.have_nova != 3)) { /*f734*/ int v = rnd_1_n(10, &g->seed) + 10; p->max_pop2 = v; p->max_pop3 = v; p->type = PLANET_TYPE_RADIATED; p->growth = PLANET_GROWTH_HOSTILE; v = rnd_1_n(v, &g->seed); SETMIN(p->pop, v); if (player == PLAYER_NONE) { p->pop = 0; } v = ((rnd_1_n(3, &g->seed) + 1) * p->factories) / 20; SETMIN(p->factories, v); g->evn.have_nova = 3; } /*f878*/ ns.num1 = g->evn.nova_years; ns.num2 = g->evn.nova_val; ns.type = GAME_NEWS_NOVA; ns.planet_i = pli; ns.race = (player != PLAYER_NONE) ? g->eto[player].race : RACE_HUMAN; /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ switch (g->evn.have_nova) { case 1: ns.subtype = IS_HUMAN(g, player) ? 0 : 4; break; case 2: ns.subtype = (IS_HUMAN(g, player) && ((!rnd_0_nm1(10, &g->seed)) || (g->evn.nova_years < 3))) ? 1 : -1; break; case 3: ns.subtype = IS_HUMAN(g, player) ? 2 : 5; if (g->evn.nova_val > 0) { ++ns.subtype; } break; default: ns.subtype = -1; break; } if (g->evn.have_nova == 1) { g->evn.have_nova = 2; } if (g->evn.have_nova == 3) { g->evn.have_nova = 0; } if (ns.subtype != -1) { ui_news(g, &ns); any_news = true; } if (IS_AI(g, player)) { game_ai->nova(g, pli); } } /*f986*/ if (g->evn.have_accident) { uint8_t pli = g->evn.accident_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = g->evn.accident_player; ns.planet_i = pli; ns.type = GAME_NEWS_ACCIDENT; ns.race = g->eto[player].race; if (g->evn.have_accident == 1) { p->max_pop3 /= 2; SETMIN(p->max_pop2, p->max_pop3); p->waste = p->max_pop3 - 10; p->type = PLANET_TYPE_RADIATED; p->growth = PLANET_GROWTH_HOSTILE; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; g->evn.have_accident = 2; } else if (p->waste == 0) { /*fac7*/ ns.subtype = IS_HUMAN(g, player) ? 1 : 5; g->evn.have_accident = 0; ui_news(g, &ns); any_news = true; } } /*fb20*/ if (g->evn.have_assassin) { player_id_t player = g->evn.assassin_player; player_id_t player2 = g->evn.assassin_player2; empiretechorbit_t *e = &(g->eto[player]); ns.type = GAME_NEWS_ASSASSIN; ns.race = e->race; ns.num1 = player2; game_diplo_start_war(g, player2, player); if (IS_HUMAN(g, player)) { e->diplo_type[player2] = 13; e->diplo_val[player2] = 100; } g->evn.have_assassin = false; ns.subtype = 0; ui_news(g, &ns); any_news = true; } /*fba9*/ if (g->evn.have_virus) { player_id_t player = g->evn.virus_player; empiretechorbit_t *e = &(g->eto[player]); ns.type = GAME_NEWS_VIRUS; ns.race = e->race; ns.num1 = g->evn.virus_field; ns.num2 = e->tech.investment[g->evn.virus_field]; /* MOO1 limits the shown loss to 32000 and also sets it to 100 if 0 */ e->tech.investment[g->evn.virus_field] = 0; g->evn.have_virus = false; ns.subtype = 4; ui_news(g, &ns); any_news = true; } /*fc6e*/ if (g->evn.have_comet) { uint8_t pli = g->evn.comet_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = p->owner; int dmg = 0; if (player != PLAYER_NONE) { /* BUG? only colonized planets can fight off comets */ const empiretechorbit_t *e = &(g->eto[player]); const shipdesign_t *sd = &(g->srd[player].design[0]); for (int i = 0; i < e->shipdesigns_num; ++i) { dmg += rnd_1_n(game_num_tbl_hull_w[sd->hull], &g->seed) * e->orbit[pli].ships[i]; } ns.race = e->race; } else { ns.race = RACE_HUMAN; /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ } if ((g->evn.have_comet != 1) && (player != PLAYER_NONE)) { dmg += g->evn.comet_dmg; if (dmg > g->evn.comet_hp) { g->evn.comet_dmg = g->evn.comet_hp; g->evn.have_comet = 3; } else { g->evn.comet_dmg = dmg; } --g->evn.comet_years; } if ((g->evn.comet_years <= 0) && (g->evn.have_comet != 3)) { game_planet_destroy(g, pli, PLAYER_NONE); p->type = PLANET_TYPE_NOT_HABITABLE; p->growth = PLANET_GROWTH_HOSTILE; g->evn.have_comet = 3; } /*fde3*/ ns.num1 = g->evn.comet_years; ns.num2 = (g->evn.comet_dmg * 100) / g->evn.comet_hp; ns.type = GAME_NEWS_COMET; ns.planet_i = pli; switch (g->evn.have_comet) { case 1: ns.subtype = IS_HUMAN(g, player) ? 0 : 4; break; case 2: ns.subtype = (IS_HUMAN(g, player) && ((!rnd_0_nm1(10, &g->seed)) || (g->evn.comet_years < 3))) ? 1 : -1; break; case 3: ns.subtype = IS_HUMAN(g, player) ? 2 : 5; if (g->evn.comet_dmg < g->evn.comet_hp) { ++ns.subtype; } break; default: ns.subtype = -1; break; } if (g->evn.have_comet == 1) { g->evn.have_comet = 2; } if (g->evn.have_comet == 3) { g->evn.have_comet = 0; } if (ns.subtype != -1) { ui_news(g, &ns); any_news = true; } if (IS_AI(g, p->owner)) { game_ai->comet(g, pli); } } /*ff19*/ if (g->evn.have_pirates) { uint8_t pli = g->evn.pirates_planet_i; planet_t *p = &(g->planet[pli]); int dmg = 0, setback; for (monster_id_t i = MONSTER_CRYSTAL; i <= MONSTER_AMOEBA; ++i) { monster_t *m = (i == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists && (m->x == p->x) && (m->y == p->y) && (m->killer == PLAYER_NONE)) { dmg = 32000; } } for (player_id_t player = PLAYER_0; player < g->players; ++player) { const empiretechorbit_t *e = &(g->eto[player]); const shipdesign_t *sd = &(g->srd[player].design[0]); for (int i = 0; i < e->shipdesigns_num; ++i) { dmg += rnd_1_n(game_num_tbl_hull_w[sd->hull], &g->seed) * e->orbit[pli].ships[i]; } SETMIN(dmg, 32000); } SUBSAT0(g->evn.pirates_hp, dmg); ns.planet_i = pli; ns.num1 = setback = g->evn.pirates_hp / 6; if (g->evn.pirates_hp == 0) { g->evn.have_pirates = 3; } for (player_id_t p1 = PLAYER_0; p1 < g->players; ++p1) { empiretechorbit_t *e1 = &(g->eto[p1]); if (p->within_frange[p1] != 1) { continue; } for (player_id_t p2 = PLAYER_0; p2 < g->players; ++p2) { empiretechorbit_t *e2 = &(g->eto[p2]); if (p1 == p2) { continue; } e1->trade_percent[p2] = (e1->trade_percent[p2] * (100 - setback)) / 100; e2->trade_percent[p1] = (e2->trade_percent[p1] * (100 - setback)) / 100; } } ns.type = GAME_NEWS_PIRATES; switch (g->evn.have_pirates) { case 1: ns.subtype = 0; break; case 2: ns.subtype = (!rnd_0_nm1(10, &g->seed)) ? 1 : -1; break; case 3: ns.subtype = 2; break; default: ns.subtype = -1; break; } if (g->evn.have_pirates == 1) { g->evn.have_pirates = 2; } if (g->evn.have_pirates == 3) { g->evn.have_pirates = 0; } if (ns.subtype != -1) { ui_news(g, &ns); any_news = true; } game_ai->pirates(g, pli); } /*10244*/ if (g->evn.have_derelict) { player_id_t player = g->evn.derelict_player; empiretechorbit_t *e = &(g->eto[player]); const uint8_t (*rl)[TECH_TIER_NUM][3] = g->srd[player].researchlist; ns.type = GAME_NEWS_DERELICT; ns.race = e->race; for (int fi = 0; fi < 2; ++fi) { const tech_field_t ftbl[2] = { TECH_FIELD_WEAPON, TECH_FIELD_FORCE_FIELD }; tech_field_t field; int tier; field = ftbl[fi]; tier = e->tech.percent[field] / 5; for (int i = 0; (i < (tier + 2)) && (i < TECH_TIER_NUM); ++i) { game_tech_get_new(g, player, field, rl[field][i][0], TECHSOURCE_RESEARCH, 0, ns.race, false); /* BUG? ns.race makes no sense but is unused */ } } ns.subtype = 0; ui_news(g, &ns); any_news = true; g->evn.have_derelict = false; } /*10364,10470*/ for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); if ((p->owner == PLAYER_NONE) || (p->unrest_reported)) { continue; } if (p->unrest == PLANET_UNREST_REBELLION) { empiretechorbit_t *e; player_id_t player; player = p->owner; e = &(g->eto[player]); ns.planet_i = pli; ns.race = e->race; ns.type = GAME_NEWS_REBELLION; ns.subtype = 0; ns.num1 = p->rebels; { int n; n = 0; for (int i = 0; (i < g->galaxy_stars) && (n < 2); ++i) { /* WASBUG MOO1 loops while i < g->players */ const planet_t *p2 = &(g->planet[i]); if ((p2->owner == player) && (p2->unrest == PLANET_UNREST_REBELLION)) { ++n; } } if (n > 1) { ++ns.subtype; } } if (IS_AI(g, player)) { ns.subtype += 3; } ui_news(g, &ns); any_news = true; p->unrest_reported = true; } else if (p->unrest == PLANET_UNREST_RESOLVED) { empiretechorbit_t *e; player_id_t player; player = p->owner; e = &(g->eto[player]); ns.planet_i = pli; ns.race = e->race; ns.type = GAME_NEWS_REBELLION; ns.subtype = 2; if (IS_AI(g, player)) { ns.subtype += 3; } ui_news(g, &ns); any_news = true; p->unrest = PLANET_UNREST_NORMAL; p->unrest_reported = true; } } /*10530*/ for (monster_id_t i = MONSTER_CRYSTAL; i <= MONSTER_AMOEBA; ++i) { monster_t *m = (i == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists) { planet_t *p = &(g->planet[m->dest]); player_id_t owner; bool flag_colony, flag_last_planet = false, flag_new_dest; flag_colony = false; owner = p->owner; if ((m->nuked > 4) || (m->killer != PLAYER_NONE)) { m->exists = 3; } if (m->killer != PLAYER_NONE) { /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ ns.race = g->eto[m->killer].race; } else if (owner != PLAYER_NONE) { ns.race = g->eto[owner].race; } else { ns.race = RACE_HUMAN; } flag_new_dest = false; if ((m->x == p->x) && (m->y == p->y) && (m->killer == PLAYER_NONE) && (m->counter <= 0)) { if ((p->pop > 0) && (owner != PLAYER_NONE)) { flag_colony = true; } ns.planet_i = m->dest; p->pop = 0; if (i == MONSTER_AMOEBA) { p->factories /= 10; p->type = PLANET_TYPE_RADIATED; p->max_pop2 = rnd_1_n(3, &g->seed) * 5 + 5; p->max_pop3 = p->max_pop2; game_planet_destroy(g, ns.planet_i, PLAYER_NONE); } else { p->waste = p->max_pop3 - 10; } ++m->nuked; game_monster_set_next_dest(g, m); m->counter = 4; flag_new_dest = true; m->exists = 3; if (owner != PLAYER_NONE) { flag_last_planet = true; for (int pli = 0; (pli < g->galaxy_stars) && flag_last_planet; ++pli) { planet_t *p2 = &(g->planet[pli]); if ((pli != ns.planet_i) && (p2->owner == owner)) { flag_last_planet = false; } } } } else { --m->counter; } switch (m->exists) { case 1: ns.subtype = 0; break; case 2: ns.subtype = -1; break; case 3: if (flag_new_dest) { ns.subtype = flag_colony ? 3 : -1; m->exists = 2; } else { ns.subtype = (m->killer == PLAYER_NONE) ? 2 : 1; } break; default: ns.subtype = -1; break; } if (m->exists == 1) { m->exists = 2; } if (m->exists == 3) { m->exists = 0; } ns.type = (i == MONSTER_CRYSTAL) ? GAME_NEWS_CRYSTAL : GAME_NEWS_AMOEBA; if ((ns.subtype == 3) && flag_last_planet) { ns.subtype = 6; } if (flag_last_planet) { game_event_kill_player(g, owner); } if (ns.subtype != -1) { ui_news(g, &ns); any_news = true; } } } /*10c37*/ if (g->evn.have_enviro) { uint8_t pli = g->evn.enviro_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = p->owner; empiretechorbit_t *e = 0; int terraf = 0; if (player != PLAYER_NONE) { e = &(g->eto[player]); terraf = e->have_terraform_n; } ns.planet_i = pli; ns.race = (player != PLAYER_NONE) ? e->race : RACE_HUMAN; /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ game_turn_soil_enrich(p, terraf, 0); g->evn.have_enviro = false; ns.type = GAME_NEWS_ENVIRO; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; } /*10dfb*/ if (g->evn.have_rich) { uint8_t pli = g->evn.rich_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = p->owner; empiretechorbit_t *e = 0; if (player != PLAYER_NONE) { e = &(g->eto[player]); } ns.planet_i = pli; ns.race = (player != PLAYER_NONE) ? e->race : RACE_HUMAN; /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ p->special = PLANET_SPECIAL_RICH; g->evn.have_rich = false; ns.type = GAME_NEWS_RICH; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; } /*10e80*/ if (g->evn.have_support) { player_id_t player = g->evn.support_player; empiretechorbit_t *e = &(g->eto[player]); int v; ns.race = e->race; v = (g->year * 10 / 100) * 100; SETMAX(v, 500); e->reserve_bc += v; ns.num1 = v; g->evn.have_support = false; ns.type = GAME_NEWS_SUPPORT; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; } /*10f1e*/ if (g->evn.have_poor) { uint8_t pli = g->evn.poor_planet_i; planet_t *p = &(g->planet[pli]); player_id_t player = p->owner; empiretechorbit_t *e = 0; if (player != PLAYER_NONE) { e = &(g->eto[player]); } ns.planet_i = pli; ns.race = (player != PLAYER_NONE) ? e->race : RACE_HUMAN; /* WASBUG MOO1 does not check for none, taking race from eto[-1] */ p->special = PLANET_SPECIAL_POOR; g->evn.have_poor = false; ns.type = GAME_NEWS_POOR; ns.subtype = IS_HUMAN(g, player) ? 0 : 4; ui_news(g, &ns); any_news = true; } /*10ff3*/ ns.type = GAME_NEWS_GENOCIDE; ns.subtype = 0; { int num_humans = 0; uint8_t num_planets[PLAYER_NUM]; memset(num_planets, 0, sizeof(num_planets)); for (int pli = 0; pli < g->galaxy_stars; ++pli) { const planet_t *p = &(g->planet[pli]); if (p->owner != PLAYER_NONE) { ++num_planets[p->owner]; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (IS_HUMAN(g, i) && IS_ALIVE(g, i)) { ++num_humans; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (1 && (num_planets[i] == 0) && IS_ALIVE(g, i) && (IS_AI(g, i) || (num_humans > 1)) ) { player_id_t killer; killer = PLAYER_NONE; for (player_id_t j = PLAYER_0; (j < g->players) && (killer == PLAYER_NONE); ++j) { empiretechorbit_t *e = &(g->eto[j]); for (int pli = 0; pli < g->galaxy_stars; ++pli) { const planet_t *p = &(g->planet[pli]); if (p->claim == i) { bool any_ships; any_ships = false; for (int k = 0; k < e->shipdesigns_num; ++k) { if (e->orbit[pli].ships[k] > 0) { any_ships = true; break; } } if (any_ships || (p->owner == j)) { killer = j; } } } } if (killer != PLAYER_NONE) { ns.race = g->eto[i].race; ns.num2 = killer; ui_news(g, &ns); any_news = true; for (player_id_t j = PLAYER_0; j < g->players; ++j) { if ((j != i) && (j != killer)) { game_diplo_act(g, -36, killer, j, 0, 0, 0); } } } game_event_kill_player(g, i); if (IS_HUMAN(g, i)) { --num_humans; } } } } /*1124f*/ for (player_id_t player = PLAYER_0; player < g->players; ++player) { empiretechorbit_t *e; int num_humans; if (BOOLVEC_IS0(g->evn.coup, player) || (!IS_ALIVE(g, player))) { continue; } e = &(g->eto[player]); num_humans = 0; ns.type = GAME_NEWS_COUP; ns.race = e->race; for (int i = PLAYER_0; i < g->players; ++i) { if (IS_HUMAN(g, i) && IS_ALIVE(g, i)) { ++num_humans; } } if (IS_HUMAN(g, player) && (num_humans == 1)) { ns.subtype = 2; ns.num1 = player; ui_news(g, &ns); any_news = true; ge->type = GAME_END_LOST_FUNERAL; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != player) && IS_ALIVE(g, i)) { ge->race = g->eto[i].banner; break; } } ge->banner_dead = e->banner; return true; } else { /*11304*/ bool any_in_range; if (IS_AI(g, player)) { game_new_generate_other_emperor_name(g, player); } ns.subtype = rnd_0_nm1(2, &g->seed); ns.num1 = e->trait1; ns.num2 = e->trait2; any_in_range = IS_HUMAN(g, player); for (player_id_t i = PLAYER_0; (i < g->players) && (!any_in_range); ++i) { empiretechorbit_t *e2 = &(g->eto[i]); if (IS_HUMAN(g, i) && BOOLVEC_IS1(e2->contact, player) && IS_ALIVE(g, i)) { any_in_range = true; } } if (any_in_range) { ui_news(g, &ns); any_news = true; /* WASBUG If multiple coups happen in one turn, MOO1 reports only one. */ } /* TODO What about multiplayer? Set overthrown player to AI? */ } } /*11383*/ { player_id_t top_player = PLAYER_0; uint8_t half = g->galaxy_stars / 2, max_pl = 0; uint8_t num_planets[PLAYER_NUM]; memset(num_planets, 0, sizeof(num_planets)); for (int pli = 0; pli < g->galaxy_stars; ++pli) { const planet_t *p = &(g->planet[pli]); if (p->owner != PLAYER_NONE) { ++num_planets[p->owner]; } } for (int i = PLAYER_0; i < g->players; ++i) { if (num_planets[i] > max_pl) { max_pl = num_planets[i]; top_player = i; } } if (0 || ((((g->evn.report_stars + 1) * half) / 4) <= max_pl) || ((g->evn.report_stars == 3) && ((half - 2) <= max_pl) && (max_pl < half) && (g->end == GAME_END_NONE)) ) { ns.type = GAME_NEWS_STARS; ns.subtype = g->evn.report_stars++; if (ns.subtype < 4) { ns.num1 = max_pl; ns.race = g->eto[top_player].race; ui_news(g, &ns); any_news = true; } } } /*114b2*/ if (g->guardian_killer != PLAYER_NONE) { player_id_t player = g->guardian_killer; ns.type = GAME_NEWS_GUARDIAN; ns.subtype = IS_HUMAN(g, player) ? 0 : 1; ns.race = g->eto[player].race; ui_news(g, &ns); any_news = true; game_tech_get_orion_loot(g, player); g->guardian_killer = PLAYER_NONE; } /* MOO1 has the following way before the guardian news which gives a strange news order */ if (g->evn.have_orion_conquer && BOOLVEC_IS0(g->evn.done, 17)) { player_id_t player = g->evn.have_orion_conquer - 1; empiretechorbit_t *e = &(g->eto[player]); BOOLVEC_SET1(g->evn.done, 17); ns.race = e->race; ns.num1 = player; ns.type = GAME_NEWS_ORION; ns.subtype = 0; /* WASBUG MOO1 does not set this here */ ui_news(g, &ns); any_news = true; } /*114fb*/ if (1 && (!game_opt_skip_random_news) && (!any_news) && (!rnd_0_nm1(40, &g->seed)) && (g->year > 25) && (g->end == GAME_END_NONE) ) { ns.type = GAME_NEWS_STATS; ns.subtype = rnd_0_nm1(4, &g->seed); ui_news(g, &ns); } /*11538*/ ui_news_end(); return false; } 1oom-1.11.2/src/game/game_event.h000066400000000000000000000004271476061725400164510ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_EVENT_H #define INC_1OOM_GAME_EVENT_H #include "types.h" struct game_s; struct game_end_s; extern void game_event_new(struct game_s *g); extern bool game_event_run(struct game_s *g, struct game_end_s *ge); extern bool game_opt_skip_random_news; #endif 1oom-1.11.2/src/game/game_fleet.c000066400000000000000000000233261476061725400164250ustar00rootroot00000000000000#include "config.h" #include #include "game_fleet.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_num.h" #include "game_str.h" #include "log.h" #include "types.h" #include "ui.h" #include "util.h" /* -------------------------------------------------------------------------- */ static bool game_send_fleet_do(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes, bool retreat) { fleet_enroute_t *r; const planet_t *pf, *pt; uint8_t speed; { bool found = false; for (int i = 0; i < numtypes; ++i) { if (ships[i] != 0) { found = true; break; } } if (!found) { return false; } } pf = (&g->planet[from]); pt = (&g->planet[dest]); if ((pt->owner == owner) && (pf->owner == owner) && pt->have_stargate && pf->have_stargate) { speed = FLEET_SPEED_STARGATE; } else { const shipdesign_t *sd = (&g->srd[owner].design[0]); speed = 100; for (int i = 0; i < numtypes; ++i) { if (ships[i] > 0) { uint8_t s, st; st = shiptypes[i]; s = sd[st].engine + 1; SETMIN(speed, s); } } } for (int i = 0; i < g->enroute_num; ++i) { r = &(g->enroute[i]); if ((r->owner == owner) && (r->x == pf->x) && (r->y == pf->y) && (r->dest == dest) && (r->speed == speed)) { for (int j = 0; j < numtypes; ++j) { if (ships[j] > 0) { uint8_t st; st = shiptypes[j]; ADDSATT(r->ships[st], ships[j], game_num_limit_ships); } } return true; } } if (g->enroute_num == FLEET_ENROUTE_MAX) { log_warning("fleet enroute table (size %i) full!\n", FLEET_ENROUTE_MAX); return false; } r = (&g->enroute[g->enroute_num]); r->owner = owner; r->x = pf->x; r->y = pf->y; r->dest = dest; r->speed = speed; r->retreat = retreat; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { r->ships[i] = 0; } for (int i = 0; i < numtypes; ++i) { if (ships[i] > 0) { uint8_t st; st = shiptypes[i]; r->ships[st] = ships[i]; } } BOOLVEC_CLEAR(r->visible, PLAYER_NUM); BOOLVEC_SET1(r->visible, owner); ++g->enroute_num; return true; } static bool game_send_fleet_from_orbit_do(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes, bool retreat) { if (!game_send_fleet_do(g, owner, from, dest, ships, shiptypes, numtypes, retreat)) { return false; } { fleet_orbit_t *o = &(g->eto[owner].orbit[from]); bool found = false; for (int i = 0; i < numtypes; ++i) { o->ships[shiptypes[i]] -= ships[i]; } for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (o->ships[i] > 0) { found = true; break; } } if (!found) { BOOLVEC_CLEAR(o->visible, PLAYER_NUM); } } return true; } /* -------------------------------------------------------------------------- */ bool game_send_fleet_from_orbit(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes) { if (dest == from) { return false; } return game_send_fleet_from_orbit_do(g, owner, from, dest, ships, shiptypes, numtypes, false); } bool game_send_fleet_retreat(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes) { return game_send_fleet_from_orbit_do(g, owner, from, dest, ships, shiptypes, numtypes, true); } bool game_send_fleet_reloc(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, uint8_t si, shipcount_t shipnum) { shipcount_t ships[NUM_SHIPDESIGNS]; uint8_t shiptypes[NUM_SHIPDESIGNS]; ships[0] = shipnum; shiptypes[0] = si; return game_send_fleet_do(g, owner, from, dest, ships, shiptypes, 1, false); } bool game_send_transport(struct game_s *g, struct planet_s *pf) { transport_t *r; const planet_t *pt; player_id_t owner; if (g->transport_num == TRANSPORT_MAX) { log_warning("transport table (size %i) full, could not send!\n", TRANSPORT_MAX); return false; } pt = &(g->planet[pf->trans_dest]); owner = pf->owner; r = (&g->transport[g->transport_num]); r->owner = owner; r->x = pf->x; r->y = pf->y; r->dest = pf->trans_dest; { uint8_t speed = g->eto[owner].have_engine; if ((pt->owner == owner) && pt->have_stargate && pf->have_stargate) { speed = FLEET_SPEED_STARGATE; } r->speed = speed; } { uint16_t n = pf->trans_num; r->pop = n; pf->pop -= n; SETMAX(pf->pop, 1); SUBSAT0(pf->rebels, n / 2 + 1); } pf->trans_num = 0; ++g->transport_num; return true; } void game_remove_empty_fleets(struct game_s *g) { for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); bool is_empty; is_empty = true; for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { if (r->ships[j] != 0) { is_empty = false; break; } } if (is_empty) { util_table_remove_item_any_order(i, g->enroute, sizeof(fleet_enroute_t), g->enroute_num); --g->enroute_num; --i; } } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); if (r->pop == 0) { util_table_remove_item_any_order(i, g->transport, sizeof(transport_t), g->transport_num); --g->transport_num; --i; } } } void game_remove_player_fleets(struct game_s *g, player_id_t owner) { for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); if (r->owner == owner) { util_table_remove_item_any_order(i, g->enroute, sizeof(fleet_enroute_t), g->enroute_num); --g->enroute_num; --i; } } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); if (r->owner == owner) { util_table_remove_item_any_order(i, g->transport, sizeof(transport_t), g->transport_num); --g->transport_num; --i; } } memset(g->eto[owner].orbit, 0, sizeof(g->eto[owner].orbit)); } bool game_fleet_any_dest_player(const struct game_s *g, player_id_t owner, player_id_t target) { for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if ((r->owner == owner) && (g->planet[r->dest].owner == target)) { return true; } } return false; } void game_fleet_unrefuel(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { const shipresearch_t *srd = &(g->srd[pi]); empiretechorbit_t *e = &(g->eto[pi]); for (uint8_t pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); uint8_t wr; wr = p->within_frange[pi]; if (wr != 1) { fleet_orbit_t *r = &(e->orbit[pli]); bool unfueled; unfueled = false; for (int si = 0; si < e->shipdesigns_num; ++si) { if (1 && (r->ships[si] != 0) && ((wr == 0) || ((wr == 2) && (!srd->have_reserve_fuel[si]))) ) { unfueled = true; r->ships[si] = 0; } } if (unfueled) { BOOLVEC_SET1(p->unrefuel, pi); } } } } } uint8_t game_fleet_get_speed(const struct game_s *g, const struct fleet_enroute_s *r, uint8_t pfrom, uint8_t pto) { if (game_num_stargate_redir_fix && ((r->speed == FLEET_SPEED_STARGATE) || (pfrom != PLANET_NONE))) { player_id_t owner = r->owner; const planet_t *pt = (&g->planet[pto]); const planet_t *pf = (pfrom != PLANET_NONE) ? (&g->planet[pfrom]) : 0; if (1 && ((pt->owner == owner) && pt->have_stargate) && ((r->speed == FLEET_SPEED_STARGATE) || (pf && (pf->owner == owner) && pf->have_stargate)) ) { return FLEET_SPEED_STARGATE; } else { const shipdesign_t *sd = (&g->srd[owner].design[0]); uint8_t speed = 100; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (r->ships[i] > 0) { uint8_t s; s = sd[i].engine + 1; SETMIN(speed, s); } } return speed; } } else { return r->speed; } } void game_fleet_redirect(struct game_s *g, struct fleet_enroute_s *r, uint8_t pfrom, uint8_t pto) { if ((pfrom != PLANET_NONE) && (pfrom == pto)) { shipcount_t *os; os = &(g->eto[r->owner].orbit[pto].ships[0]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { os[i] += r->ships[i]; } util_table_remove_item_any_order(r - g->enroute, g->enroute, sizeof(fleet_enroute_t), g->enroute_num); --g->enroute_num; } else { r->dest = pto; r->speed = game_fleet_get_speed(g, r, pfrom, pto); } } 1oom-1.11.2/src/game/game_fleet.h000066400000000000000000000024671476061725400164350ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_FLEET_H #define INC_1OOM_GAME_FLEET_H #include "game_types.h" #include "types.h" struct game_s; struct planet_s; struct fleet_enroute_s; #define FLEET_SPEED_STARGATE 35 extern bool game_send_fleet_from_orbit(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes); extern bool game_send_fleet_retreat(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, const shipcount_t ships[NUM_SHIPDESIGNS], const uint8_t shiptypes[NUM_SHIPDESIGNS], uint8_t numtypes); extern bool game_send_fleet_reloc(struct game_s *g, player_id_t owner, uint8_t from, uint8_t dest, uint8_t si, shipcount_t shipnum); extern bool game_send_transport(struct game_s *g, struct planet_s *p); extern void game_remove_empty_fleets(struct game_s *g); extern void game_remove_player_fleets(struct game_s *g, player_id_t owner); extern bool game_fleet_any_dest_player(const struct game_s *g, player_id_t owner, player_id_t target); extern void game_fleet_unrefuel(struct game_s *g); extern uint8_t game_fleet_get_speed(const struct game_s *g, const struct fleet_enroute_s *r, uint8_t pfrom, uint8_t pto); extern void game_fleet_redirect(struct game_s *g, struct fleet_enroute_s *r, uint8_t pfrom, uint8_t pto); #endif 1oom-1.11.2/src/game/game_ground.c000066400000000000000000000301601476061725400166160ustar00rootroot00000000000000#include "config.h" #include #include #include "game_ground.h" #include "bits.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_endecode.h" #include "game_misc.h" #include "game_num.h" #include "game_shiptech.h" #include "game_spy.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ static void game_ground_resolve_init(struct game_s *g, struct ground_s *gr) { gr->seed = g->seed; { const planet_t *p = &(g->planet[gr->planet_i]); gr->fact = p->factories; } for (int i = 0; i < 2; ++i) { const empiretechorbit_t *e = &(g->eto[gr->s[i].player]); const shipresearch_t *srd = &(g->srd[gr->s[i].player]); const uint8_t *rc; uint8_t bestarmor, bestsuit, bestshield, bestweap, besti; gr->s[i].human = IS_HUMAN(g, gr->s[i].player); gr->s[i].force = 0; bestarmor = 0; bestsuit = besti = 0; rc = &(srd->researchcompleted[TECH_FIELD_CONSTRUCTION][0]); for (int j = 0; j < e->tech.completed[TECH_FIELD_CONSTRUCTION]; ++j) { uint8_t tier; tech_group_t group; group = game_tech_get_group(g->gaux, TECH_FIELD_CONSTRUCTION, rc[j]); tier = game_tech_get_tier(g->gaux, TECH_FIELD_CONSTRUCTION, rc[j]); if (group == TECH_GROUP_ARMOR) { bestarmor = tier; } else if (group == TECH_GROUP_PERSONAL_ARMOR) { bestsuit = tier; besti = rc[j]; } } gr->s[i].force += bestarmor * 5 + bestsuit * 10; gr->s[i].armori = bestarmor; gr->s[i].suiti = besti; bestshield = besti = 0; rc = &(srd->researchcompleted[TECH_FIELD_FORCE_FIELD][0]); for (int j = 0; j < e->tech.completed[TECH_FIELD_FORCE_FIELD]; ++j) { uint8_t tier; tech_group_t group; group = game_tech_get_group(g->gaux, TECH_FIELD_FORCE_FIELD, rc[j]); tier = game_tech_get_tier(g->gaux, TECH_FIELD_FORCE_FIELD, rc[j]); if (group == TECH_GROUP_PERSONAL_SHIELD) { bestshield = tier; besti = rc[j]; } } gr->s[i].shieldi = besti; if (bestshield != 0) { gr->s[i].force += bestshield * 10; } bestweap = besti = 0; rc = &(srd->researchcompleted[TECH_FIELD_WEAPON][0]); for (int j = 0; j < e->tech.completed[TECH_FIELD_WEAPON]; ++j) { uint8_t tier; tech_group_t group; group = game_tech_get_group(g->gaux, TECH_FIELD_WEAPON, rc[j]); tier = game_tech_get_tier(g->gaux, TECH_FIELD_WEAPON, rc[j]); if (group == TECH_GROUP_PERSONAL_WEAPONS) { bestweap = tier; besti = rc[j]; } } gr->s[i].weapi = besti; if (bestweap != 0) { if (bestweap > 2) { ++bestweap; } gr->s[i].force += bestweap * 5; } if (e->race == RACE_BULRATHI) { gr->s[i].force += 25; } } gr->s[gr->flag_swap ? 0 : 1].force += 5; for (int i = 0; i < TECH_SPY_MAX; ++i) { gr->got[i].tech = 0; gr->got[i].field = 0; } } static void game_ground_show_init(struct game_s *g, struct ground_s *gr) { for (int i = 0; i < 2; ++i) { char strbuf[GAME_GROUND_STRBUF_SIZE]; uint8_t besti; gr->s[i].human = IS_HUMAN(g, gr->s[i].player); gr->s[i].pop2 = gr->s[i].pop1; gr->s[i].strnum = 1; lib_strcpy(strbuf, *tbl_shiptech_armor[gr->s[i].armori * 2].nameptr, sizeof(strbuf)); util_str_tolower(&strbuf[1], sizeof(strbuf) - 1); lib_sprintf(gr->s[i].str[0], GAME_GROUND_STRBUF_SIZE, "%s ", strbuf); besti = gr->s[i].suiti; if (besti == 0) { lib_strcat(gr->s[i].str[0], game_str_gr_carmor, GAME_GROUND_STRBUF_SIZE); } else { game_tech_get_name(g->gaux, TECH_FIELD_CONSTRUCTION, besti, strbuf, GAME_GROUND_STRBUF_SIZE); lib_strcat(gr->s[i].str[0], strbuf, GAME_GROUND_STRBUF_SIZE); } besti = gr->s[i].shieldi; if (besti != 0) { game_tech_get_name(g->gaux, TECH_FIELD_FORCE_FIELD, besti, gr->s[i].str[1], GAME_GROUND_STRBUF_SIZE); gr->s[i].strnum = 2; } besti = gr->s[i].weapi; if (besti != 0) { game_tech_get_name(g->gaux, TECH_FIELD_WEAPON, besti, gr->s[i].str[gr->s[i].strnum++], GAME_GROUND_STRBUF_SIZE); } } } static int game_ground_encode_start(const struct ground_s *gr, uint8_t *buf, int pos) { SG_1OOM_EN_U8(gr->planet_i); SG_1OOM_EN_U8(gr->s[0].player); SG_1OOM_EN_U8(gr->s[1].player); SG_1OOM_EN_U8(gr->flag_swap | (gr->flag_rebel ? 2 : 0)); SG_1OOM_EN_U32(gr->seed); SG_1OOM_EN_U16(gr->inbound); SG_1OOM_EN_U16(gr->total_inbound); SG_1OOM_EN_U16(gr->fact); for (int i = 0; i < 2; ++i) { SG_1OOM_EN_U16(gr->s[i].force); SG_1OOM_EN_U16(gr->s[i].pop1); SG_1OOM_EN_U8(gr->s[i].armori); SG_1OOM_EN_U8(gr->s[i].suiti); SG_1OOM_EN_U8(gr->s[i].shieldi); SG_1OOM_EN_U8(gr->s[i].weapi); } return pos; } static int game_ground_encode_end(const struct ground_s *gr, uint8_t *buf, int pos) { for (int i = 0; i < TECH_SPY_MAX; ++i) { SG_1OOM_EN_U8(gr->got[i].tech); SG_1OOM_EN_U8(gr->got[i].field); } return pos; } static int game_ground_decode(struct ground_s *gr, const uint8_t *buf, int pos) { { uint8_t v; SG_1OOM_DE_U8(v); if (v == 0xff) { return 0; } gr->planet_i = v; } SG_1OOM_DE_U8(gr->s[0].player); SG_1OOM_DE_U8(gr->s[1].player); { uint8_t v; SG_1OOM_DE_U8(v); gr->flag_swap = (v & 1) != 0; gr->flag_rebel = (v & 2) != 0; } SG_1OOM_DE_U32(gr->seed); SG_1OOM_DE_U16(gr->inbound); SG_1OOM_DE_U16(gr->total_inbound); SG_1OOM_DE_U16(gr->fact); for (int i = 0; i < 2; ++i) { SG_1OOM_DE_U16(gr->s[i].force); SG_1OOM_DE_U16(gr->s[i].pop1); SG_1OOM_DE_U8(gr->s[i].armori); SG_1OOM_DE_U8(gr->s[i].suiti); SG_1OOM_DE_U8(gr->s[i].shieldi); SG_1OOM_DE_U8(gr->s[i].weapi); } { int num = 0; for (int i = 0; i < TECH_SPY_MAX; ++i) { uint8_t t; SG_1OOM_DE_U8(t); gr->got[i].tech = t; if (t != 0) { ++num; } SG_1OOM_DE_U8(gr->got[i].field); } gr->techchance = num; } return pos; } static inline uint8_t *game_ground_get_buf(struct game_s *g) { return g->gaux->savebuf; /* unused during turn processing, large enough for ground data */ } static void game_ground_finish(struct game_s *g, struct ground_s *gr) { planet_t *p = &(g->planet[gr->planet_i]); struct spy_esp_s s[1]; g->seed = gr->seed; gr->techchance = 0; if (gr->s[0].pop1 > 0) { if (gr->flag_rebel) { p->unrest = PLANET_UNREST_RESOLVED; p->pop = p->pop - p->rebels + gr->s[0].pop1; p->rebels = 0; } else { int fact, chance, num; fact = gr->fact; chance = 0; for (int i = 0; i < fact; ++i) { if (!rnd_0_nm1(50, &g->seed)) { ++chance; } } gr->techchance = chance; s->target = gr->s[1].player; s->spy = gr->s[0].player; num = game_spy_esp_sub1(g, s, 0, 0); SETMIN(num, chance); s->tnum = num; for (int i = 0; i < num; ++i) { gr->got[i].tech = s->tbl_tech2[i]; gr->got[i].field = s->tbl_field[i]; game_tech_get_new(g, gr->s[0].player, s->tbl_field[i], s->tbl_tech2[i], TECHSOURCE_FOUND, gr->planet_i, gr->s[1].player, false); } gr->techchance = num; game_planet_destroy(g, gr->planet_i, gr->s[0].player); p->owner = gr->s[0].player; p->pop = gr->s[0].pop1; p->bc_to_refit = 0; p->pop_oper_fact = 1; } } else { if (gr->flag_rebel) { p->rebels = gr->s[1].pop1; if (p->rebels == 0) { p->unrest = PLANET_UNREST_RESOLVED; } } else { p->pop = gr->s[1].pop1; } } SETMIN(p->pop, p->max_pop3); } /* -------------------------------------------------------------------------- */ void game_ground_kill(struct ground_s *gr) { int v1, v2, death; v1 = rnd_1_n(100, &gr->seed) + gr->s[0].force; v2 = rnd_1_n(100, &gr->seed) + gr->s[1].force; if (v1 <= v2) { death = 0; } else { death = 1; } gr->death = death; --gr->s[death].pop1; } const uint8_t *game_turn_ground_resolve_all(struct game_s *g) { struct ground_s gr[1]; uint8_t *buf = game_ground_get_buf(g); int pos = 0; gr->seed = g->seed; for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); player_id_t powner; powner = p->owner; for (player_id_t i = 0; i < g->players; ++i) { if ((i != powner) || (p->unrest == PLANET_UNREST_REBELLION)) { if ((powner != PLAYER_NONE) && (p->inbound[i] > 0)) { int pop_planet; gr->flag_rebel = (p->unrest == PLANET_UNREST_REBELLION) && IS_HUMAN(g, i) && (p->owner == i); gr->inbound = p->inbound[i]; gr->total_inbound = p->total_inbound[i]; gr->s[0].pop2 = gr->s[0].pop1 = p->inbound[i]; pop_planet = gr->s[1].pop2 = gr->s[1].pop1 = gr->flag_rebel ? p->rebels : p->pop; gr->s[0].player = i; gr->s[1].player = powner; gr->planet_i = pli; gr->flag_swap = false; if (IS_HUMAN(g, i) || IS_HUMAN(g, powner)) { int t; gr->flag_swap = true; t = gr->s[0].pop2; gr->s[0].pop2 = gr->s[1].pop2; gr->s[1].pop2 = t; t = gr->s[0].pop1; gr->s[0].pop1 = gr->s[1].pop1; gr->s[1].pop1 = t; t = gr->s[0].player; gr->s[0].player = gr->s[1].player; gr->s[1].player = t; } game_ground_resolve_init(g, gr); if ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { if (gr->s[0].human || gr->s[1].human) { pos = game_ground_encode_start(gr, buf, pos); } while ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { game_ground_kill(gr); } if (gr->flag_swap) { int t; t = gr->s[0].pop1; gr->s[0].pop1 = gr->s[1].pop1; gr->s[1].pop1 = t; t = gr->s[0].player; gr->s[0].player = gr->s[1].player; gr->s[1].player = t; } game_ground_finish(g, gr); if (gr->s[0].human || gr->s[1].human) { pos = game_ground_encode_end(gr, buf, pos); } pop_planet -= gr->s[1].pop1; SETMAX(pop_planet, 1); game_ai->ground(g, gr->s[1].player, gr->s[0].player, pli, pop_planet, (p->owner != powner)); } } powner = p->owner; } } } SG_1OOM_EN_U8(0xff); return buf; } int game_turn_ground_show_all(struct game_s *g, const uint8_t *buf) { struct ground_s gr[1]; int pos = 0; /* TODO reorder for minimum player switching */ while ((pos = game_ground_decode(gr, buf, pos)) > 0) { game_ground_show_init(g, gr); ui_ground(g, gr); } return (pos == 0) ? 0 : -1; } 1oom-1.11.2/src/game/game_ground.h000066400000000000000000000016071476061725400166270ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_GROUND_H #define INC_1OOM_GAME_GROUND_H #include "game_types.h" #include "types.h" #define GAME_GROUND_STRBUF_SIZE 64 struct game_s; struct ground_side_s { player_id_t player; bool human; int force; int pop1; int pop2; uint8_t armori, suiti, shieldi, weapi; int strnum; char str[3][GAME_GROUND_STRBUF_SIZE]; }; struct ground_s { uint32_t seed; uint8_t planet_i; bool flag_swap; bool flag_rebel; int inbound; int total_inbound; int death; /* 0, 1, -1 */ int fact; int techchance; struct { uint8_t tech; tech_field_t field; } got[TECH_SPY_MAX]; struct ground_side_s s[2]; }; extern void game_ground_kill(struct ground_s *gr); extern const uint8_t *game_turn_ground_resolve_all(struct game_s *g); extern int game_turn_ground_show_all(struct game_s *g, const uint8_t *buf); #endif 1oom-1.11.2/src/game/game_misc.c000066400000000000000000000771721476061725400162710ustar00rootroot00000000000000#include "config.h" #include #include "game_misc.h" #include "bits.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_num.h" #include "game_shiptech.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void game_update_have_reserve_fuel(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { shipresearch_t *srd = &(g->srd[pi]); int num = g->eto[pi].shipdesigns_num; for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { srd->have_reserve_fuel[si] = false; } for (int si = 0; si < num; ++si) { shipdesign_t *sd = &(srd->design[si]); if (0 || (sd->special[0] == SHIP_SPECIAL_RESERVE_FUEL_TANKS) || (sd->special[1] == SHIP_SPECIAL_RESERVE_FUEL_TANKS) || (sd->special[2] == SHIP_SPECIAL_RESERVE_FUEL_TANKS) ) { srd->have_reserve_fuel[si] = true; } } } } void game_update_maint_costs(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { shipsum_t tbl_ships[NUM_SHIPDESIGNS]; uint32_t totalcost; /* FIXME maybe uint64_t? */ uint16_t bases; shipresearch_t *srd = &(g->srd[pi]); empiretechorbit_t *e = &(g->eto[pi]); int numsd = e->shipdesigns_num; for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { tbl_ships[si] = 0; } for (int si = 0; si < numsd; ++si) { for (int i = 0; i < g->galaxy_stars; ++i) { tbl_ships[si] += e->orbit[i].ships[si]; } } for (int j = 0; j < g->enroute_num; ++j) { if (g->enroute[j].owner == pi) { for (int si = 0; si < numsd; ++si) { tbl_ships[si] += g->enroute[j].ships[si]; } } } totalcost = 0; for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { const shipdesign_t *sd = &(srd->design[si]); srd->shipcount[si] = tbl_ships[si]; totalcost += tbl_ships[si] * sd->cost; } totalcost = totalcost / 50; SETMIN(totalcost, game_num_max_ship_maint); bases = 0; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { if (p->have_stargate) { totalcost += game_num_stargate_maint; /* WASBUG MOO1 sums to a int16_t var after limiting to 32000 */ } bases += p->missile_bases; } } SETMIN(totalcost, game_num_max_ship_maint); e->ship_maint_bc = totalcost; e->bases_maint_bc = (bases * game_get_base_cost(g, pi)) / 50; } } void game_update_production(struct game_s *g) { game_update_maint_costs(g); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { g->eto[pi].total_production_bc = 0; } for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { if ((pi == pi2) || BOOLVEC_IS0(e->contact, pi2)) { e->spying[pi2] = 0; } } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner = p->owner; if (owner != PLAYER_NONE) { empiretechorbit_t *e = &(g->eto[owner]); int pop = p->pop; int v; if (game_num_leaving_trans_fix) { int rebels = p->rebels; if (p->trans_num) { /* see game_send_transport() */ pop -= p->trans_num; SUBSAT0(rebels, p->trans_num / 2 + 1); SETMAX(pop, 1); } v = (pop - rebels) * game_planet_get_pop_oper_fact(g, p); SETMAX(v, 0); } else { int popx = p->pop - p->rebels; SETMAX(popx, 0); v = popx * game_planet_get_pop_oper_fact(g, p); } { uint16_t factories = p->factories; int extra; SETMIN(factories, v); extra = (pop * (e->tech.percent[TECH_FIELD_PLANETOLOGY] * 3 + 50)) / 100; if (e->race == RACE_KLACKON) { extra <<= 1; } v = factories + extra; } if (BOOLVEC_IS1(g->is_ai, owner)) { switch (g->difficulty) { /* TODO BUG? simple has larger v than easy */ case DIFFICULTY_EASY: v = (v << 2) / 5; break; case DIFFICULTY_AVERAGE: v += v / 4; break; case DIFFICULTY_HARD: v += v / 2; break; case DIFFICULTY_IMPOSSIBLE: v += v; break; default: break; } } { uint32_t reserve; reserve = p->reserve; SETMIN(reserve, v); v += reserve; } if (p->unrest == PLANET_UNREST_REBELLION) { v = 0; } SETMAX(v, 0); p->prod_after_maint = v; p->total_prod = v; e->total_production_bc += v; } } for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); uint16_t spysum; spysum = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { spysum += e->spying[pi2]; } { uint16_t spymaint; spymaint = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { spymaint += (e->total_production_bc * e->spying[pi2]) / 1000; } e->spying_maint_bc = spymaint; } { uint8_t bonus = (e->race == RACE_HUMAN) ? 25 : 0; int32_t trade = 0; for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { trade += (e->trade_bc[pi2] * (e->trade_percent[pi2] + bonus)) / 100; } e->total_trade_bc = trade; } { int32_t actual_prod; actual_prod = (e->total_production_bc * (1000 - e->security - spysum)) / 1000 + e->total_trade_bc - e->ship_maint_bc - e->bases_maint_bc - (e->total_production_bc * e->tax) / 1000; if (actual_prod < 1) { actual_prod = 1; } e->total_maint_bc = e->total_production_bc - actual_prod; e->percent_prod_total_to_actual = e->total_production_bc ? ((actual_prod * 100) / e->total_production_bc) : 0; } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { int v; v = (p->prod_after_maint * e->percent_prod_total_to_actual) / 100 - p->trans_num; /* BUG: deducting transport cost takes no effect for actual production, * which happens after departure, but leads to wrong display for player. */ p->prod_after_maint = (v > 0) ? v : 0; } } } } void game_update_total_research(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { g->eto[pi].total_research_bc = 0; } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (1 && (p->owner != PLAYER_NONE) && (!(g->evn.have_plague && (g->evn.plague_planet_i == i))) && (!(g->evn.have_nova && (g->evn.nova_planet_i == i))) ) { empiretechorbit_t *e; e = &(g->eto[p->owner]); e->total_research_bc += game_get_tech_prod(p->prod_after_maint, p->slider[PLANET_SLIDER_TECH], e->race, p->special); } } } void game_update_eco_on_waste(struct game_s *g, int player_i, bool force_adjust) { empiretechorbit_t *e = &(g->eto[player_i]); if (e->race == RACE_SILICOID) { return; } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == player_i) { uint16_t v; int16_t left; bool check_locks = !force_adjust && game_num_slider_respects_locks && IS_HUMAN(g, p->owner); v = game_planet_get_waste_percent(NULL, g, p, false); if (check_locks && p->slider_lock[PLANET_SLIDER_ECO]) { } else if (check_locks && p->slider_lock[PLANET_SLIDER_SHIP] && p->slider_lock[PLANET_SLIDER_DEF] && p->slider_lock[PLANET_SLIDER_IND] && p->slider_lock[PLANET_SLIDER_TECH]) { } else if ((p->slider[PLANET_SLIDER_ECO] < v) || force_adjust) { int16_t eco_diff = v - p->slider[PLANET_SLIDER_ECO]; int16_t sum = 100; if (game_num_waste_adjust_fix) { sum = p->slider[PLANET_SLIDER_SHIP] + p->slider[PLANET_SLIDER_DEF] + p->slider[PLANET_SLIDER_IND] + p->slider[PLANET_SLIDER_TECH]; } if (check_locks) { int16_t sum_locks = 0; for (int si = 0; si < PLANET_SLIDER_NUM; ++si){ if (p->slider_lock[si]) { sum_locks += p->slider[si]; } } sum -= sum_locks; SETMIN(v, 100 - sum_locks); } p->slider[PLANET_SLIDER_ECO] = v; if (sum > 0) { if (!check_locks || !p->slider_lock[PLANET_SLIDER_SHIP]) { p->slider[PLANET_SLIDER_SHIP] -= (p->slider[PLANET_SLIDER_SHIP] * eco_diff) / sum; } if (!check_locks || !p->slider_lock[PLANET_SLIDER_DEF]) { p->slider[PLANET_SLIDER_DEF] -= (p->slider[PLANET_SLIDER_DEF] * eco_diff) / sum; } if (!check_locks || !p->slider_lock[PLANET_SLIDER_IND]) { p->slider[PLANET_SLIDER_IND] -= (p->slider[PLANET_SLIDER_IND] * eco_diff) / sum; } } } SETMAX(p->slider[PLANET_SLIDER_SHIP], 0); SETMAX(p->slider[PLANET_SLIDER_DEF], 0); SETMAX(p->slider[PLANET_SLIDER_IND], 0); SETRANGE(p->slider[PLANET_SLIDER_ECO], 0, 100); left = 100; left -= p->slider[PLANET_SLIDER_SHIP]; left -= p->slider[PLANET_SLIDER_DEF]; left -= p->slider[PLANET_SLIDER_IND]; left -= p->slider[PLANET_SLIDER_ECO]; SETMAX(left, 0); if (!check_locks || !p->slider_lock[PLANET_SLIDER_TECH]) { p->slider[PLANET_SLIDER_TECH] = left; } } } } void game_update_seen_by_orbit(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); bool in_orbit; in_orbit = false; for (int j = 0; j < e->shipdesigns_num; ++j) { if (e->orbit[i].ships[j] != 0) { in_orbit = true; break; } } if ((p->owner == pi) || in_orbit) { g->seen[pi][i].owner = p->owner; g->seen[pi][i].pop = p->pop; g->seen[pi][i].bases = p->missile_bases; g->seen[pi][i].factories = p->factories; } } } void game_update_within_range(struct game_s *g) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { uint8_t tblplanet[PLANETS_MAX]; uint8_t tblplanet_num; empiretechorbit_t *e = &(g->eto[pi]); bool tbl_alliance[PLAYER_NUM]; uint8_t frange, frangep3, srange, srange2; for (int i = 0; i < PLAYER_NUM; ++i) { tbl_alliance[i] = (e->treaty[i] == TREATY_ALLIANCE); } tbl_alliance[pi] = true; frange = e->fuel_range; frangep3 = frange + 3; srange = e->scanner_range; switch (srange) { case 3: srange2 = 0; break; case 5: srange2 = 10; break; case 7: srange2 = 20; break; case 9: srange2 = 30; break; default: break; } tblplanet_num = 0; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if ((p->owner != PLAYER_NONE) && tbl_alliance[p->owner]) { tblplanet[tblplanet_num++] = i; } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == pi) { p->within_frange[pi] = 1; BOOLVEC_SET1(p->within_srange, pi); } else { uint16_t dist, mindist1, mindist2; mindist1 = 0x2710; mindist2 = 0x2710; for (int j = 0; (j < tblplanet_num) && ((mindist1 > frange) || (mindist2 > srange)); ++j) { uint8_t planet_i2; planet_i2 = tblplanet[j]; dist = g->gaux->star_dist[i][planet_i2]; SETMIN(mindist1, dist); if ((dist < mindist2) && (g->planet[planet_i2].owner == pi)) { mindist2 = dist; } } if (mindist1 <= frange) { p->within_frange[pi] = 1; } else if (mindist1 <= frangep3) { p->within_frange[pi] = 2; } else { p->within_frange[pi] = 0; } BOOLVEC_SET(p->within_srange, pi, (mindist2 <= srange)); if (BOOLVEC_IS0(p->within_srange, pi) && ((srange2 > 0) || game_num_ship_scanner_fix)) { mindist1 = 10000; for (int j = 0; (j < g->enroute_num) && (mindist1 > srange2); ++j) { if (g->enroute[j].owner == pi) { dist = util_math_dist_fast(g->enroute[j].x, g->enroute[j].y, p->x, p->y); if (game_num_ship_scanner_fix) { if (dist < mindist1) { mindist1 = dist; } } else { dist = (dist + 9) / 10; if (dist < mindist1) { dist = mindist1; } } } } if (mindist1 <= srange2) { BOOLVEC_SET1(p->within_srange, pi); } } } } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); uint16_t snum; snum = 0; for (int j = 0; (j < e->shipdesigns_num) && !snum; ++j) { snum += e->orbit[i].ships[j]; } if (!snum) { for (player_id_t pi2 = PLAYER_0; pi2 < PLAYER_NUM; ++pi2) { BOOLVEC_CLEAR(g->eto[pi2].orbit[i].visible, PLAYER_NUM); /* WASBUG? only cleared bit 0 */ } } else { BOOLVEC_SET1(p->within_srange, pi); } } } } void game_update_reloc_dest(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { struct planet_s *pf = &(g->planet[i]); if (!game_reloc_dest_ok(g, pf->reloc, pf->owner)) { pf->reloc = i; } } } void game_update_empire_contact(struct game_s *g) { uint8_t tbl_pnum[PLAYER_NUM]; uint8_t tbl_planet[PLAYER_NUM][PLANETS_MAX]; for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { tbl_pnum[pi] = 0; } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; if (owner != PLAYER_NONE) { tbl_planet[owner][tbl_pnum[owner]++] = i; } } for (player_id_t pi1 = PLAYER_0; pi1 < g->players; ++pi1) { empiretechorbit_t *e1 = &(g->eto[pi1]); for (player_id_t pi2 = pi1 + 1; pi2 < g->players; ++pi2) { empiretechorbit_t *e2 = &(g->eto[pi2]); uint8_t frange, dist, mindist; frange = MAX(e1->fuel_range, e2->fuel_range); mindist = 0xff; for (int i1 = 0; i1 < tbl_pnum[pi1]; ++i1) { for (int i2 = 0; i2 < tbl_pnum[pi2]; ++i2) { dist = g->gaux->star_dist[tbl_planet[pi1][i1]][tbl_planet[pi2][i2]]; SETMIN(mindist, dist); } } if (mindist <= frange) { BOOLVEC_SET1(e1->contact, pi2); BOOLVEC_SET1(e2->contact, pi1); } else { BOOLVEC_SET0(e1->contact, pi2); BOOLVEC_SET0(e2->contact, pi1); } } } } bool game_check_coord_is_visible(const struct game_s *g, player_id_t pi, int range, int x, int y) { const empiretechorbit_t *e = &(g->eto[pi]); range *= 10; /* 30, 50, 70, 90 */ for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if ((p->owner == pi) && (util_math_dist_fast(x, y, p->x, p->y) <= range)) { return true; } } range = (range - 30) / 2; /* 0, 10, 20, 30 */ for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); uint32_t snum; snum = 0; for (int j = 0; (j < e->shipdesigns_num) && !snum; ++j) { snum += e->orbit[i].ships[j]; } if (snum && (util_math_dist_fast(x, y, p->x, p->y) <= range)) { return true; } } for (int ei = 0; ei < g->enroute_num; ++ei) { const fleet_enroute_t *r = &(g->enroute[ei]); if ((r->owner == pi) && (util_math_dist_fast(x, y, r->x, r->y) <= range)) { return true; } } return false; } void game_update_visibility(struct game_s *g) { for (int ei = 0; ei < g->enroute_num; ++ei) { fleet_enroute_t *r = &(g->enroute[ei]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (r->owner != pi) { BOOLVEC_SET(r->visible, pi, game_check_coord_is_visible(g, pi, g->eto[pi].scanner_range, r->x, r->y)); } else { BOOLVEC_SET1(r->visible, pi); } } } for (int i = 0; i < g->transport_num; ++i) { transport_t *t = &(g->transport[i]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (t->owner != pi) { BOOLVEC_SET(t->visible, pi, game_check_coord_is_visible(g, pi, g->eto[pi].scanner_range, t->x, t->y)); } else { BOOLVEC_SET1(t->visible, pi); } } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { bool visible = BOOLVEC_IS1(p->within_srange, pi); for (player_id_t pi2 = PLAYER_0; pi2 < g->players; ++pi2) { BOOLVEC_SET(g->eto[pi2].orbit[i].visible, pi, visible); } BOOLVEC_SET1(g->eto[pi].orbit[i].visible, pi); } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { fleet_orbit_t *o = &(g->eto[pi].orbit[i]); bool any_ships; any_ships = false; for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { if (o->ships[j] != 0) { any_ships = true; break; } } if (!any_ships) { BOOLVEC_CLEAR(o->visible, PLAYER_NUM); } } } } void game_adjust_slider_group(int16_t *slidertbl, int slideri, int16_t value, int num, const uint16_t *locktbl) { bool have_unlocked = false; int first_unlocked_i = 0; int last_unlocked_i = 0; int left = 100; for (int i = 0; i < num; ++i) { if (locktbl[i]) { left -= slidertbl[i]; } else { last_unlocked_i = i; if (!have_unlocked) { have_unlocked = true; first_unlocked_i = i; } } } SETMIN(value, left); slidertbl[slideri] = value; left -= value; for (int i = 0; i < num; ++i) { if ((i != slideri) && (!locktbl[i])) { if (slidertbl[i] <= left) { left -= slidertbl[i]; } else { slidertbl[i] = left; left = 0; } } } if ((left > 0) && (have_unlocked)) { int j; if (slideri != last_unlocked_i) { j = last_unlocked_i; } else { j = first_unlocked_i; } slidertbl[j] += left; } } void game_equalize_slider_group(int16_t *slidertbl, int num, const uint16_t *locktbl) { int total = 0; int num_unlocked = 0; for (int i = 0; i < num; ++i) { if (!locktbl[i]) { total += slidertbl[i]; ++num_unlocked; } } if (num_unlocked > 0) { int n = total / num_unlocked; int o = total % num_unlocked; for (int i = 0; i < num; ++i) { if (!locktbl[i]) { int v; v = n; if (o) { ++v; --o; } slidertbl[i] = v; } } } } int game_get_min_dist(const struct game_s *g, int player_i, int planet_i) { int dist, mindist = 255; for (int i = 0; i < g->galaxy_stars; ++i) { if ((i != planet_i) && (g->planet[i].owner == player_i)) { dist = g->gaux->star_dist[planet_i][i]; SETMIN(mindist, dist); } } return mindist; } int game_adjust_prod_by_special(int prod, planet_special_t special) { switch (special) { case PLANET_SPECIAL_ULTRA_POOR: prod /= 3; break; case PLANET_SPECIAL_POOR: prod /= 2; break; case PLANET_SPECIAL_RICH: prod *= 2; break; case PLANET_SPECIAL_ULTRA_RICH: prod *= 3; break; default: break; } return prod; } int game_get_pop_growth_max(const struct game_s *g, const planet_t *p, int max_pop3) { const empiretechorbit_t *e = &(g->eto[p->owner]); int v, retval; if (e->race == RACE_SILICOID) { v = (100 - (p->pop * 100) / max_pop3) / 2; } else { v = 100 - ((p->pop + p->waste) * 100) / max_pop3; switch (p->growth) { case PLANET_GROWTH_HOSTILE: if (v >= 0) { v /= 2; } else { v *= 2; } break; case PLANET_GROWTH_NORMAL: default: break; case PLANET_GROWTH_FERTILE: if (v >= 0) { v += v / 2; } else { v = (v * 2) / 3; } break; case PLANET_GROWTH_GAIA: if (v >= 0) { v *= 2; } else { v /= 2; } break; } if (e->race == RACE_SAKKRA) { v *= 2; } } retval = (v * p->pop + 5) / 100; if (!game_num_pop_tenths_fix) { retval += p->pop_tenths; } if ((v > 0) && (retval < 1)) { retval = 1; } if ((p->pop + retval / 10) < 1) { retval = 1; } return retval; } int game_get_pop_growth_for_eco(const struct game_s *g, const planet_t *p, int eco) { const empiretechorbit_t *e = &(g->eto[p->owner]); int v, vmax; v = (eco * 10) / e->inc_pop_cost; if (e->race == RACE_SAKKRA) { v *= 2; } else if (e->race == RACE_SILICOID) { v /= 2; } vmax = (p->pop * 10) / 4; return MIN(v, vmax); } int game_get_tech_prod(int prod, int slider, race_t race, planet_special_t special) { int v = (prod * slider) / 100; if (race == RACE_PSILON) { v += v / 2; } switch (special) { case PLANET_SPECIAL_ARTIFACTS: v *= 2; break; case PLANET_SPECIAL_4XTECH: v *= 4; break; default: break; } return MIN(v, 0x7fff); } void game_print_prod_of_total(const struct game_s *g, player_id_t pi, int prod, char *buf, size_t bufsize) { int v = g->eto[pi].total_production_bc; if (v == 0) { lib_strcpy(buf, "0%%", bufsize); } else { v = (prod * 1000) / v; lib_sprintf(buf, bufsize, "%i.%i%%", v / 10, v % 10); } } bool game_xy_is_in_nebula(const struct game_s *g, int x, int y) { for (int n = 0; n < g->nebula_num; ++n) { for (int i = 0; i < 4; ++i) { if (1 && (x >= g->nebula_x0[n][i]) && (x <= g->nebula_x1[n][i]) && (y >= g->nebula_y0[n][i]) && (y <= g->nebula_y1[n][i]) ) { return true; } } } return false; } int game_calc_eta_ship(const struct game_s *g, int speed, int x0, int y0, int x1, int y1) { int x, y, num = 0; x = x0; y = y0; while ((x != x1) || (y != y1)) { int v; bool first; v = speed; first = true; do { /* Inside nebulas, ships move on frame 0 and then on every odd frame. */ if (first || (!game_xy_is_in_nebula(g, x, y))) { util_math_go_line_dist(&x, &y, x1, y1, 5); } util_math_go_line_dist(&x, &y, x1, y1, 6); first = false; --v; } while (v > 0); ++num; } return num; } int game_calc_eta_trans(const struct game_s *g, int speed, int x0, int y0, int x1, int y1) { int x = x0, y = y0, num = 0; while ((x != x1) || (y != y1)) { int v = speed; do { /* Inside nebulas, transports move on every even frame. */ util_math_go_line_dist(&x, &y, x1, y1, 5); if (!game_xy_is_in_nebula(g, x, y)) { util_math_go_line_dist(&x, &y, x1, y1, 6); } --v; } while (v > 0); ++num; } return num; } bool game_transport_dest_ok(const struct game_s *g, const planet_t *p, player_id_t pi) { if (!game_num_trans_redir_fix) { return (p->within_frange[pi] != 0); /* WASBUG MOO1 allows redirection almost anywhere */ } else { return (p->within_frange[pi] == 1) && BOOLVEC_IS1(p->explored, pi) && (p->type >= g->eto[pi].have_colony_for) && (p->owner != PLAYER_NONE) ; } } bool game_reloc_dest_ok(const struct game_s *g, uint8_t planet_i, player_id_t pi) { return game_num_extended_reloc_range ? (g->planet[planet_i].within_frange[pi] == 1) : (g->planet[planet_i].owner == pi); } void game_rng_step(struct game_s *g) { /* TODO disable for multiplayer */ if (!game_num_deterministic) { rnd_0_nm1(2, &g->seed); } } /* Max. population values: Each planet has three max_pop variables which are * affected by the ECO projects in different ways. * * The base size, max_pop1, is the size of the planet at the start of the game. * It is used to determine the increase in max. population from (advanced) soil * enrichment; max_pop1 itself is increased only when applying atmospheric * terraforming to some types of hostile planets. * * max_pop2 is max_pop1 modified by (advanced) soil enrichment. Note that for * planets that are Fertile or Gaia at the start of the game, * max_pop1 == max_pop2. They are only different when the planets were made * Fertile or Gaia by a player (human or AI). * * max_pop3 is the actual population maximum. It equals max_pop2 modified by * terraforming and/or by bioweapon damage. */ void game_turn_atmos_tform(struct planet_s *p) { int max_pop_increase; if (p->type < PLANET_TYPE_DEAD) { max_pop_increase = 20; } else if (p->type < PLANET_TYPE_BARREN) { max_pop_increase = 10; } else { max_pop_increase = 0; } /* WASBUG max_pop += moved from outside if (bc >= cost) */ p->type = PLANET_TYPE_MINIMAL; p->max_pop1 += max_pop_increase; p->max_pop2 += max_pop_increase; p->max_pop3 += max_pop_increase; p->growth = PLANET_GROWTH_NORMAL; } void game_turn_soil_enrich(struct planet_s *p, int best_tform, bool advanced) { int max_pop_increase = 0; int16_t old_max_pop2 = 0; p->growth = advanced ? PLANET_GROWTH_GAIA : PLANET_GROWTH_FERTILE; if (advanced) { max_pop_increase = (p->max_pop1 / 10) * 5; /* BUG? If we want to calculate 50% of the base size, rounded up * to the next multiple of 5, we'd check if p->max_pop1 % 10 != 0 * below. Instead, we add an additional +5 unless the base size is * in the range 50-59 or 100-109. Penalizing these specific sizes * seems weird and arbitrary. */ if ((p->max_pop1 / 10) % 5) { max_pop_increase += 5; } if (game_num_soil_rounding_fix) { max_pop_increase = ((p->max_pop1 + 9) / 10) * 5; } } else { max_pop_increase = (p->max_pop1 / 20) * 5; /* BUG? See above. */ if ((p->max_pop1 / 20) % 5) { max_pop_increase += 5; } if (game_num_soil_rounding_fix) { max_pop_increase = ((p->max_pop1 + 19) / 20) * 5; } } SETMAX(max_pop_increase, 5); old_max_pop2 = p->max_pop2; p->max_pop2 = p->max_pop1 + max_pop_increase; p->max_pop3 += p->max_pop2 - old_max_pop2; if (game_num_reset_tform_to_max) { /* BUG? Having p->max_pop3 > (best_tform + p->max_pop2) seems * only possible when conquering a planet from a race with better * terraforming tech. Is it intended that the player loses the * more advanced terraforming here, or is this a sanity check * with unintended consequences? */ SETMIN(p->max_pop3, (best_tform + p->max_pop2)); } SETMIN(p->max_pop3, game_num_max_pop); } void game_ship_build_everywhere(struct game_s *g, player_id_t owner, uint8_t ship_i) { for (uint8_t i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == owner) { if (ship_i == BUILDSHIP_STARGATE) { if (!p->have_stargate) { p->buildship = BUILDSHIP_STARGATE; } } else { p->buildship = ship_i; } } } } void game_ship_replace_everywhere(struct game_s *g, player_id_t owner, uint8_t replace_i, uint8_t ship_i) { for (uint8_t i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == owner && p->buildship == replace_i) { if (ship_i == BUILDSHIP_STARGATE) { if (!p->have_stargate) { p->buildship = BUILDSHIP_STARGATE; } } else { p->buildship = ship_i; } } } } 1oom-1.11.2/src/game/game_misc.h000066400000000000000000000055771476061725400162760ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_MISC_H #define INC_1OOM_GAME_MISC_H #include "game.h" #include "game_num.h" #include "game_planet.h" #include "game_types.h" #include "types.h" struct game_s; struct empiretechorbit_s; extern void game_update_have_reserve_fuel(struct game_s *g); extern void game_update_maint_costs(struct game_s *g); extern void game_update_production(struct game_s *g); extern void game_update_total_research(struct game_s *g); extern void game_update_eco_on_waste(struct game_s *g, int player_i, bool force_adjust); extern void game_update_seen_by_orbit(struct game_s *g, player_id_t pi); extern void game_update_within_range(struct game_s *g); extern void game_update_reloc_dest(struct game_s *g); extern void game_update_empire_contact(struct game_s *g); extern void game_update_visibility(struct game_s *g); extern void game_adjust_slider_group(int16_t *slidertbl, int slideri, int16_t value, int num, const uint16_t *locktbl); extern void game_equalize_slider_group(int16_t *slidertbl, int num, const uint16_t *locktbl); extern int game_get_min_dist(const struct game_s *g, int player_i, int planet_i); extern int game_adjust_prod_by_special(int prod, planet_special_t special); extern int game_get_pop_growth_max(const struct game_s *g, const planet_t *p, int max_pop3); extern int game_get_pop_growth_for_eco(const struct game_s *g, const planet_t *p, int eco); extern int game_get_tech_prod(int prod, int slider, race_t race, planet_special_t special); extern void game_print_prod_of_total(const struct game_s *g, player_id_t pi, int prod, char *buf, size_t bufsize); extern bool game_xy_is_in_nebula(const struct game_s *g, int x, int y); extern int game_calc_eta_ship(const struct game_s *g, int speed, int x0, int y0, int x1, int y1); extern int game_calc_eta_trans(const struct game_s *g, int speed, int x0, int y0, int x1, int y1); extern bool game_transport_dest_ok(const struct game_s *g, const planet_t *p, player_id_t api); extern bool game_reloc_dest_ok(const struct game_s *g, uint8_t planet_i, player_id_t api); extern void game_rng_step(struct game_s *g); extern void game_turn_atmos_tform(struct planet_s *p); extern void game_turn_soil_enrich(struct planet_s *p, int best_tform, bool advanced); extern void game_ship_build_everywhere(struct game_s *g, player_id_t owner, uint8_t ship_i); extern void game_ship_replace_everywhere(struct game_s *g, player_id_t owner, uint8_t replace_i, uint8_t ship_i); static inline int game_planet_get_pop_oper_fact(const struct game_s *g, const struct planet_s *p) { return game_num_factory_cost_fix ? p->pop_oper_fact : g->eto[p->owner].colonist_oper_factories; } static inline int game_planet_get_fact_adj_cost(const struct game_s *g, const struct planet_s *p) { const struct empiretechorbit_s *e = &g->eto[p->owner]; return (game_num_factory_cost_fix && (e->race != RACE_MEKLAR)) ? ((e->factory_cost * p->pop_oper_fact) / 2) : e->factory_adj_cost; } #endif 1oom-1.11.2/src/game/game_nebula.c000066400000000000000000000034121476061725400165660ustar00rootroot00000000000000#include "game_nebula.h" #include "types.h" /* Nebula data is used by game_new.c and game_save.c. */ const uint8_t tbl_nebula_data[NEBULA_TYPE_NUM][4][4] = { { /* 0 */ { 0x14, 0x07, 0x0f, 0x1f }, { 0x05, 0x12, 0x0c, 0x02 }, { 0x28, 0x1c, 0x1f, 0x24 }, { 0x14, 0x27, 0x1b, 0x04 } }, { /* 1 */ { 0x0a, 0x14, 0x1b, 0x1e }, { 0x11, 0x0d, 0x0d, 0x05 }, { 0x1a, 0x26, 0x29, 0x29 }, { 0x25, 0x18, 0x10, 0x10 } }, { /* 2 */ { 0x09, 0x03, 0x17, 0x1a }, { 0x02, 0x08, 0x12, 0x0f }, { 0x16, 0x19, 0x29, 0x23 }, { 0x19, 0x15, 0x20, 0x24 } }, { /* 3 */ { 0x19, 0x08, 0x0a, 0x10 }, { 0x0c, 0x0f, 0x09, 0x07 }, { 0x1e, 0x1c, 0x16, 0x17 }, { 0x1c, 0x1d, 0x0f, 0x09 } }, { /* 4 */ { 0x07, 0x0f, 0x15, 0x19 }, { 0x02, 0x0f, 0x16, 0x23 }, { 0x19, 0x25, 0x29, 0x29 }, { 0x13, 0x1c, 0x23, 0x27 } }, { /* 5 */ { 0x03, 0x08, 0x0e, 0x09 }, { 0x0e, 0x15, 0x02, 0x0a }, { 0x23, 0x24, 0x1a, 0x22 }, { 0x14, 0x23, 0x1f, 0x0f } }, { /* 6 */ { 0x0d, 0x09, 0x13, 0x05 }, { 0x03, 0x0b, 0x21, 0x16 }, { 0x1b, 0x22, 0x1b, 0x08 }, { 0x21, 0x20, 0x25, 0x1e } }, { /* 7 */ { 0x08, 0x0f, 0x1c, 0x25 }, { 0x08, 0x18, 0x02, 0x0a }, { 0x25, 0x22, 0x23, 0x27 }, { 0x19, 0x1f, 0x07, 0x12 } }, { /* 8 */ { 0x08, 0x05, 0x05, 0x1b }, { 0x06, 0x01, 0x0c, 0x03 }, { 0x23, 0x0c, 0x09, 0x25 }, { 0x1f, 0x08, 0x15, 0x0a } }, { /* 9 */ { 0x04, 0x08, 0x0d, 0x25 }, { 0x02, 0x12, 0x0e, 0x11 }, { 0x2a, 0x26, 0x26, 0x29 }, { 0x12, 0x1e, 0x21, 0x1d } } }; 1oom-1.11.2/src/game/game_nebula.h000066400000000000000000000002641476061725400165750ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_NEBULA_H #define INC_1OOM_GAME_NEBULA_H #include "types.h" #define NEBULA_TYPE_NUM 10 extern const uint8_t tbl_nebula_data[NEBULA_TYPE_NUM][4][4]; #endif 1oom-1.11.2/src/game/game_new.c000066400000000000000000001304331476061725400161150ustar00rootroot00000000000000#include "config.h" #include #include #include "game_nebula.h" #include "game_new.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_misc.h" #include "game_num.h" #include "game_shipdesign.h" #include "game_str.h" #include "game_tech.h" #include "game_techtypes.h" #include "lbx.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ #define EMPEROR_NAMES_PER_RACE 6 #define EMPEROR_NAME_LBX_LEN 20 /* index to planets.lbx + 1 */ /* index to starview.lbx - 6 */ static const uint8_t tbl_planet_type_infogfx[PLANET_TYPE_NUM][6] = { { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }, { 0x05, 0x05, 0x14, 0x14, 0x22, 0x22 }, { 0x04, 0x04, 0x06, 0x06, 0x17, 0x17 }, { 0x0b, 0x0b, 0x0d, 0x0d, 0x18, 0x18 }, { 0x07, 0x07, 0x08, 0x08, 0x23, 0x23 }, { 0x20, 0x20, 0x20, 0x1e, 0x1e, 0x1e }, { 0x02, 0x02, 0x1a, 0x1a, 0x20, 0x20 }, { 0x09, 0x09, 0x09, 0x19, 0x19, 0x19 }, { 0x11, 0x11, 0x11, 0x1d, 0x1d, 0x1d }, { 0x0f, 0x0f, 0x12, 0x12, 0x1f, 0x1f }, { 0x15, 0x15, 0x15, 0x1c, 0x1c, 0x1c }, { 0x0e, 0x0e, 0x0e, 0x1b, 0x1b, 0x1b }, { 0x03, 0x03, 0x01, 0x10, 0x0c, 0x16 }, { 0x01, 0x01, 0x0a, 0x0a, 0x13, 0x21 } }; static const int8_t tbl_orion_race_relation[RACE_NUM][RACE_NUM] = { { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 0, 0,-2, 0,-3,-1,-1, 0,-1 }, { 1, 0, 0, 0, 0, 0,-1, 0, 1,-1 }, { 1,-2, 0, 0, 0,-1,-1, 0,-1,-1 }, { 1, 0, 0, 0, 0, 0, 0, 0, 0,-1 }, { 1,-3, 0,-1, 0, 0,-1, 0, 0,-1 }, { 1,-1,-1,-1, 0,-1, 0, 0, 0,-1 }, { 1,-1, 0, 0, 0, 0, 0, 0, 0,-1 }, { 1, 0, 1,-1, 0, 0, 0, 0, 0,-1 }, { 1,-1,-1,-1,-1,-1,-1,-1,-1, 1 } }; /* -------------------------------------------------------------------------- */ static void game_generate_planets(struct game_s *g) { /* assumes the planet data is already 0'd by caller */ uint16_t tblpx[PLANETS_MAX], tblpy[PLANETS_MAX]; for (uint16_t h = 0; h < g->galaxy_h; ++h) { for (uint16_t w = 0; w < g->galaxy_w; ++w) { uint16_t x, y; again: x = rnd_1_n(0x2b, &g->seed) + w * 0x1c + 9; y = rnd_1_n(0x33, &g->seed) + h * 0x20 + 7; for (uint16_t i = 0; i < (h * g->galaxy_w + w); ++i) { if ((tblpx[i] < x) || (tblpy[i] < y)) { if (util_math_dist_fast(tblpx[i], tblpy[i], x, y) < 20) { goto again; } } else if (util_math_dist_fast(tblpx[i], tblpy[i], x, y) < 10) { goto again; } } tblpx[h * g->galaxy_w + w] = x; tblpy[h * g->galaxy_w + w] = y; } } for (int i = 0; i < g->galaxy_stars; ++i) { bool in_nebula; planet_t *p; p = &g->planet[i]; p->x = tblpx[i] + 4; p->y = tblpy[i] + 4; switch (rnd_0_nm1(0x14, &g->seed)) { /* case 0x00: case 0x01: case 0x02: */ default: p->star_type = STAR_TYPE_YELLOW; break; case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: case 0x08: p->star_type = STAR_TYPE_RED; break; case 0x09: case 0x0a: case 0x0b: case 0x0c: case 0x0d: p->star_type = STAR_TYPE_GREEN; break; case 0x0e: case 0x0f: case 0x10: p->star_type = STAR_TYPE_BLUE; break; case 0x11: case 0x12: p->star_type = STAR_TYPE_WHITE; break; case 0x13: p->star_type = STAR_TYPE_NEUTRON; break; } p->look = rnd_0_nm1(2, &g->seed) * 6; p->frame = rnd_0_nm1(50, &g->seed); /* Needed for the original sequence of random numbers */ /*p->field_16 =*/ rnd_0_nm1(4, &g->seed); in_nebula = false; for (int k = 0; k < g->nebula_num; ++k) { for (int j = 0; j < 4; ++j) { if (1 && (p->x >= g->nebula_x0[k][j]) && (p->x <= g->nebula_x1[k][j]) && (p->y >= g->nebula_y0[k][j]) && (p->y <= g->nebula_y1[k][j]) ) { in_nebula = true; /* could break out here */ } } } { planet_type_t t; int16_t r; t = PLANET_TYPE_NOT_HABITABLE; r = rnd_1_n(20, &g->seed) - (in_nebula ? 4 : 0); switch (p->star_type) { case STAR_TYPE_YELLOW: /*if (r < -1) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if (r == -1) { t = PLANET_TYPE_RADIATED; } if (r == 0) { t = PLANET_TYPE_TOXIC; } if (r == 1) { t = PLANET_TYPE_INFERNO; } if (r == 2) { t = PLANET_TYPE_TUNDRA; } if (r == 3) { t = PLANET_TYPE_BARREN; } if (r == 4) { t = PLANET_TYPE_MINIMAL; } if (r == 5) { t = PLANET_TYPE_DESERT; } if (r == 6) { t = PLANET_TYPE_STEPPE; } if ((r > 6) && (r < 9)) { t = PLANET_TYPE_ARID; } if ((r > 8) && (r < 0xb)) { t = PLANET_TYPE_OCEAN; } if ((r > 0xa) && (r < 0xd)) { t = PLANET_TYPE_JUNGLE; } if (r > 0xc) { t = PLANET_TYPE_TERRAN; } break; case STAR_TYPE_RED: /*if (r < 2) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if (r == 2) { t = PLANET_TYPE_RADIATED; } if (r == 3) { t = PLANET_TYPE_TOXIC; } if (r == 4) { t = PLANET_TYPE_INFERNO; } if (r == 5) { t = PLANET_TYPE_DEAD; } if (r == 6) { t = PLANET_TYPE_TUNDRA; } if (r == 7) { t = PLANET_TYPE_BARREN; } if (r == 8) { t = PLANET_TYPE_MINIMAL; } if ((r > 8) && (r < 0xb)) { t = PLANET_TYPE_DESERT; } if ((r > 0xa) && (r < 0xd)) { t = PLANET_TYPE_STEPPE; } if ((r > 0xc) && (r < 0x10)) { t = PLANET_TYPE_ARID; } if ((r > 0xf) && (r < 0x12)) { t = PLANET_TYPE_OCEAN; } if ((r > 0x11) && (r < 0x14)) { t = PLANET_TYPE_JUNGLE; } if (r == 0x14) { t = PLANET_TYPE_TERRAN; } break; case STAR_TYPE_GREEN: /*if (r < 2) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if (r == 2) { t = PLANET_TYPE_RADIATED; } if (r == 3) { t = PLANET_TYPE_TOXIC; } if (r == 4) { t = PLANET_TYPE_INFERNO; } if (r == 5) { t = PLANET_TYPE_DEAD; } if (r == 6) { t = PLANET_TYPE_TUNDRA; } if (r == 7) { t = PLANET_TYPE_BARREN; } if (r == 8) { t = PLANET_TYPE_MINIMAL; } if (r == 9) { t = PLANET_TYPE_DESERT; } if ((r > 9) && (r < 0xc)) { t = PLANET_TYPE_STEPPE; } if ((r > 0xb) && (r < 0xe)) { t = PLANET_TYPE_ARID; } if ((r > 0xd) && (r < 0x10)) { t = PLANET_TYPE_OCEAN; } if ((r > 0xf) && (r < 0x12)) { t = PLANET_TYPE_JUNGLE; } if (r > 0x11) { t = PLANET_TYPE_TERRAN; } break; case STAR_TYPE_WHITE: /*if (r < 3) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if (r == 3) { t = PLANET_TYPE_RADIATED; } if ((r > 3) && (r < 6)) { t = PLANET_TYPE_TOXIC; } if ((r > 5) && (r < 8)) { t = PLANET_TYPE_INFERNO; } if ((r > 7) && (r < 0xa)) { t = PLANET_TYPE_DEAD; } if ((r > 9) && (r < 0xc)) { t = PLANET_TYPE_TUNDRA; } if ((r > 0xb) && (r < 0xe)) { t = PLANET_TYPE_BARREN; } if ((r > 0xd) && (r < 0x10)) { t = PLANET_TYPE_MINIMAL; } if ((r > 0xf) && (r < 0x12)) { t = PLANET_TYPE_DESERT; } if (r == 0x12) { t = PLANET_TYPE_STEPPE; } if (r == 0x13) { t = PLANET_TYPE_ARID; } if (r == 0x14) { t = PLANET_TYPE_OCEAN; } break; case STAR_TYPE_BLUE: /*if (r < 4) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if ((r > 3) && (r < 6)) { t = PLANET_TYPE_RADIATED; } if ((r > 5) && (r < 8)) { t = PLANET_TYPE_TOXIC; } if ((r > 7) && (r < 0xa)) { t = PLANET_TYPE_INFERNO; } if ((r > 9) && (r < 0xc)) { t = PLANET_TYPE_DEAD; } if ((r > 0xb) && (r < 0xe)) { t = PLANET_TYPE_TUNDRA; } if ((r > 0xd) && (r < 0x10)) { t = PLANET_TYPE_BARREN; } if ((r > 0xf) && (r < 0x12)) { t = PLANET_TYPE_MINIMAL; } if (r == 0x12) { t = PLANET_TYPE_DESERT; } if (r == 0x13) { t = PLANET_TYPE_STEPPE; } if (r == 0x14) { t = PLANET_TYPE_ARID; } break; case STAR_TYPE_NEUTRON: /*if (r < 5) { t = PLANET_TYPE_NOT_HABITABLE; }*/ if ((r > 4) && (r < 0xa)) { t = PLANET_TYPE_RADIATED; } if ((r > 9) && (r < 0xd)) { t = PLANET_TYPE_TOXIC; } if ((r > 0xc) && (r < 0x10)) { t = PLANET_TYPE_INFERNO; } if ((r > 0xf) && (r < 0x12)) { t = PLANET_TYPE_DEAD; } if (r == 0x12) { t = PLANET_TYPE_TUNDRA; } if (r == 0x13) { t = PLANET_TYPE_BARREN; } if (r == 0x14) { t = PLANET_TYPE_MINIMAL; } break; default: break; } p->type = t; } { uint16_t a; switch (p->type) { case PLANET_TYPE_NOT_HABITABLE: a = 10; break; case PLANET_TYPE_RADIATED: case PLANET_TYPE_TOXIC: case PLANET_TYPE_INFERNO: a = rnd_1_n(7, &g->seed) * 5 + 5; break; case PLANET_TYPE_DEAD: case PLANET_TYPE_TUNDRA: a = rnd_1_n(7, &g->seed) * 5 + 0xf; break; case PLANET_TYPE_BARREN: case PLANET_TYPE_MINIMAL: a = rnd_1_n(5, &g->seed) * 5 + 0x19; break; /* case PLANET_TYPE_DESERT: case PLANET_TYPE_STEPPE: case PLANET_TYPE_ARID: case PLANET_TYPE_OCEAN: */ default: a = rnd_1_n(4, &g->seed) * 5 + (((int)(p->type)) - (int)PLANET_TYPE_DESERT) * 0xa + 0x1e; break; case PLANET_TYPE_JUNGLE: a = rnd_1_n(4, &g->seed) * 5 + 0x46; break; case PLANET_TYPE_TERRAN: a = rnd_1_n(4, &g->seed) * 5 + 0x50; break; } p->max_pop2 = a; } { uint8_t di; di = rnd_1_n(10, &g->seed); while ((di == 1) || (di == 10)) { if (di == 1) { p->max_pop2 -= 20; } else { p->max_pop2 += 20; } di = rnd_1_n(10, &g->seed); SETMAX(p->max_pop2, 10); } SETMIN(p->max_pop2, 120); } p->max_pop3 = p->max_pop2; p->max_pop1 = p->max_pop2; if (!in_nebula) { p->battlebg = rnd_1_n(4, &g->seed); } p->special = PLANET_SPECIAL_NORMAL; { star_type_t star_type; int16_t di; star_type = p->star_type; if (p->type >= PLANET_TYPE_STEPPE) { di = rnd_1_n(0x14, &g->seed); if (star_type == STAR_TYPE_RED) { di -= 4; } else if (star_type == STAR_TYPE_GREEN) { di -= 2; } if (di <= 2) { p->special = PLANET_SPECIAL_POOR; } di = rnd_1_n(0x14, &g->seed); if (star_type == STAR_TYPE_RED) { di -= 4; } else if (star_type == STAR_TYPE_GREEN) { di -= 2; } if (di <= 5) { if (p->special == PLANET_SPECIAL_POOR) { p->special = PLANET_SPECIAL_ULTRA_POOR; } } } di = rnd_1_n(0x14, &g->seed) - (in_nebula ? 8 : 0); if (star_type == STAR_TYPE_BLUE) { di -= 2; } else if (star_type == STAR_TYPE_NEUTRON) { di -= 5; } if ((((int)PLANET_TYPE_STEPPE) - ((int)p->type)) > di) { p->special = PLANET_SPECIAL_RICH; } di = rnd_1_n(0x14, &g->seed) - (in_nebula ? 8 : 0); if (star_type == STAR_TYPE_BLUE) { di -= 2; } else if (star_type == STAR_TYPE_NEUTRON) { di -= 5; } if (di < 6) { if (p->special == PLANET_SPECIAL_RICH) { p->special = PLANET_SPECIAL_ULTRA_RICH; } } } if (1 && (p->type >= PLANET_TYPE_MINIMAL) && (p->type <= PLANET_TYPE_OCEAN) && (p->special == PLANET_SPECIAL_NORMAL) && (rnd_1_n(10, &g->seed) == 1) ) { p->special = PLANET_SPECIAL_ARTIFACTS; } { int16_t di; di = rnd_1_n(100, &g->seed); if (p->special == PLANET_SPECIAL_ULTRA_RICH) { di -= 20; } else if (p->special == PLANET_SPECIAL_RICH) { di -= 10; } di -= 15 - (int)(p->type); if (di < 15) { p->rocks = PLANET_ROCKS_MANY; } else if (di < 40) { p->rocks = PLANET_ROCKS_SOME; } else { p->rocks = PLANET_ROCKS_NONE; } } p->growth = PLANET_GROWTH_NORMAL; if (p->type < PLANET_TYPE_MINIMAL) { p->growth = PLANET_GROWTH_HOSTILE; } else if ((p->type > PLANET_TYPE_DESERT) && (rnd_1_n(12, &g->seed) == 1)) { uint16_t v; p->growth = PLANET_GROWTH_FERTILE; v = p->max_pop2 + (p->max_pop2 / 20) * 5; p->max_pop2 = v; p->max_pop3 = v; p->max_pop1 = v; } p->owner = PLAYER_NONE; p->prev_owner = PLAYER_NONE; p->claim = PLAYER_NONE; if (p->type == PLANET_TYPE_NOT_HABITABLE) { p->growth = PLANET_GROWTH_NORMAL; p->special = PLANET_SPECIAL_NORMAL; } p->pop_oper_fact = 2; p->infogfx = tbl_planet_type_infogfx[p->type][rnd_0_nm1(6, &g->seed)] - 1; p->slider[PLANET_SLIDER_IND] = 100; p->reloc = i; } { uint16_t tx = 0, ty = 0; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p; p = &g->planet[i]; if (p->x > tx) { tx = p->x; } if (p->y > ty) { ty = p->y; } } g->galaxy_maxx = tx + 27; g->galaxy_maxy = ty + 25; } for (int i = PLAYER_0; i < PLAYER_NUM; ++i) { g->evn.voted[i] = PLAYER_NONE; } { uint16_t i; planet_t *p; i = rnd_0_nm1(g->galaxy_stars, &g->seed); g->evn.planet_orion_i = i; g->evn.have_guardian = true; p = &g->planet[i]; p->type = PLANET_TYPE_TERRAN; p->max_pop3 = 120; p->max_pop2 = 120; p->max_pop1 = 120; p->special = PLANET_SPECIAL_4XTECH; p->growth = PLANET_GROWTH_NORMAL; p->infogfx = tbl_planet_type_infogfx[p->type][rnd_0_nm1(6, &g->seed)] - 1; } } static void game_generate_galaxy(struct game_s *g, struct game_new_options_s *opts) { { uint16_t a = 0, w = 0, h = 0; switch (g->galaxy_size) { default: case GALAXY_SIZE_SMALL: a = rnd_0_nm1(2, &g->seed); w = 6; h = 4; break; case GALAXY_SIZE_MEDIUM: a = rnd_1_n(3, &g->seed); w = 8; h = 6; break; case GALAXY_SIZE_LARGE: a = rnd_1_n(2, &g->seed) + 1; w = 10; h = 7; break; case GALAXY_SIZE_HUGE: a = rnd_1_n(3, &g->seed) + 1; w = 12; h = 9; break; } g->nebula_num = opts->nebulae ? a : 0; g->galaxy_w = w; g->galaxy_h = h; g->galaxy_maxx = (w - 1) * 0x1c + 0x14; g->galaxy_maxy = (h - 1) * 0x20 + 0x10; g->galaxy_stars = w * h; } g->guardian_killer = PLAYER_NONE; { uint16_t gw, gh; uint16_t v8 = 0, i = 0; gw = g->galaxy_maxx - 70; gh = g->galaxy_maxy - 70; while (i < g->nebula_num) { uint16_t found, j; g->nebula_type[i] = rnd_0_nm1(NEBULA_TYPE_NUM, &g->seed); g->nebula_x[i] = rnd_1_n(gw, &g->seed) + 4; g->nebula_y[i] = rnd_1_n(gh, &g->seed) + 4; found = j = 0; while (j < i) { if (0 || (g->nebula_type[i] == g->nebula_type[j]) || ((abs(g->nebula_x[i] - g->nebula_x[j]) < 0x3c) && (abs(g->nebula_y[i] - g->nebula_y[j]) < 0x3c)) ) { found = 1; } ++j; } if (found == 0) { ++i; } if (++v8 > 200) { g->nebula_num = i; i = 0; } } } for (int i = 0; i < g->nebula_num; ++i) { uint16_t type = g->nebula_type[i]; for (int j = 0; j < 4; ++j) { g->nebula_x0[i][j] = tbl_nebula_data[type][0][j] + g->nebula_x[i]; g->nebula_x1[i][j] = tbl_nebula_data[type][2][j] + g->nebula_x[i]; g->nebula_y0[i][j] = tbl_nebula_data[type][1][j] + g->nebula_y[i]; g->nebula_y1[i][j] = tbl_nebula_data[type][3][j] + g->nebula_y[i]; } } game_generate_planets(g); } static void game_generate_planet_names(struct game_s *g) { BOOLVEC_DECLARE(in_use, PLANETS_MAX); BOOLVEC_CLEAR(in_use, PLANETS_MAX); for (int i = 0; i < g->galaxy_stars; ++i) { uint16_t j; do { j = rnd_0_nm1(PLANETS_MAX, &g->seed); } while (BOOLVEC_IS1(in_use, j)); BOOLVEC_SET1(in_use, j); lib_strcpy(g->planet[i].name, game_str_tbl_planet_names[j], PLANET_NAME_LEN); } lib_strcpy(g->planet[g->evn.planet_orion_i].name, game_str_planet_name_orion, PLANET_NAME_LEN); } static void game_generate_race_banner(struct game_s *g) { const uint16_t race_tbl[] = {7, 1, 5, 0, 3, 9, 4, 6, 2, 8}; BOOLVEC_DECLARE(in_use, (int)BANNER_NUM); uint16_t loops; loops = 0; for (player_id_t i = PLAYER_0; i < g->players; ++i) { race_t race; bool in_use = false; race = g->eto[i].race; if (race != RACE_RANDOM) { continue; } race = race_tbl[rnd_0_nm1(RACE_NUM, &g->seed)]; for (player_id_t j = PLAYER_0; j < i; ++j) { if (g->eto[j].race == race) { in_use = true; --i; break; } } if (!in_use) { g->eto[i].race = race; } } loops = 0; BOOLVEC_CLEAR(in_use, (int)BANNER_NUM); for (player_id_t i = PLAYER_0; i < g->players; ++i) { banner_t banner; banner = g->eto[i].banner; if (banner != BANNER_RANDOM) { BOOLVEC_SET1(in_use, banner); continue; } banner = rnd_0_nm1(BANNER_NUM, &g->seed); if (BOOLVEC_IS0(in_use, banner)) { BOOLVEC_SET1(in_use, banner); g->eto[i].banner = banner; } else { --i; /* try again */ if (++loops == 100) { for (banner = 0; banner < BANNER_NUM; ++banner) { if (BOOLVEC_IS0(in_use, banner)) { BOOLVEC_SET1(in_use, banner); g->eto[i].banner = banner; break; } } loops = 0; } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (IS_AI(g, i)) { race_t r; r = g->eto[i].race; g->eto[i].trait2 = game_num_tbl_trait2[r][rnd_0_nm1(TRAIT2_TBL_NUM, &g->seed)]; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { race_t r; r = g->eto[i].race; g->eto[i].trait1 = game_num_tbl_trait1[r][rnd_0_nm1(TRAIT1_TBL_NUM, &g->seed)]; } } static bool game_generate_home_improved_do_i(struct game_s *g, struct game_new_options_s *opts, uint8_t tblhome[], player_id_t i) { //NOTE: Bottleneck for SMALL galaxy and 6 PLAYERS static const int mindist = 80; uint8_t ok_home_i[PLANETS_MAX]; uint16_t ok_home_count = 0; int safe_mindist = (g->galaxy_size > GALAXY_SIZE_SMALL || g->players < 6) ? mindist : mindist - 10; for (uint8_t pi = 0; pi < g->galaxy_stars; ++pi) { int x = g->planet[pi].x; int y = g->planet[pi].y; { bool next = false; int num_checks = opts->homeworlds.num_dist_checks; for (int j = 0; j < i; ++j) { planet_t *p; p = &g->planet[tblhome[j]]; if (tblhome[j] == pi) { next = true; break; } if ((j < num_checks) && (util_math_dist_fast(x, y, p->x, p->y) < safe_mindist)) { next = true; break; } } if (next) continue; } if ((i < opts->homeworlds.num_ok_planet_checks) && (i < 5 || g->galaxy_size > GALAXY_SIZE_SMALL)) { bool next = true; for (int j = 0; j < g->galaxy_stars; ++j) { planet_t *p; p = &g->planet[j]; if (1 && (p->type >= PLANET_TYPE_MINIMAL) && (j != g->evn.planet_orion_i) && (j != pi) ) { if (util_math_dist_fast(x, y, p->x, p->y) <= 29) { next = false; break; } } } if (next) continue; } if (pi == g->evn.planet_orion_i) { continue; } ok_home_i[ok_home_count] = pi; ++ok_home_count; } while (ok_home_count > 0) { int k = rnd_0_nm1(ok_home_count, &g->seed); tblhome[i] = ok_home_i[k]; --ok_home_count; ok_home_i[k] = ok_home_i[ok_home_count]; if ((i + 1) >= g->players) { return true; } if ((i < (PLAYER_NUM - 1)) && game_generate_home_improved_do_i(g, opts, tblhome, i + 1)) { return true; } } return false; } static bool game_generate_home_improved_do(struct game_s *g, struct game_new_options_s *opts, uint16_t tblhome[]) { uint8_t homes[PLAYER_NUM] = { PLANET_NONE , PLANET_NONE , PLANET_NONE , PLANET_NONE , PLANET_NONE , PLANET_NONE }; game_generate_race_banner(g); bool result = game_generate_home_improved_do_i(g, opts, homes, PLAYER_0); for (int i = 0; i < PLAYER_NUM; ++i) { tblhome[i] = homes[i]; } return result; } static bool game_generate_home_do(struct game_s *g, uint16_t tblhome[]) { uint16_t loops; bool flag_all_ok; flag_all_ok = false; loops = 0; game_generate_race_banner(g); while ((!flag_all_ok) && (loops < 200)) { flag_all_ok = true; for (player_id_t i = PLAYER_0; i < g->players; ++i) { uint16_t pi; bool flag_again2; flag_again2 = true; while (flag_again2) { if (g->galaxy_stars > 24) { pi = rnd_1_n(g->galaxy_w - 2, &g->seed) + rnd_1_n(g->galaxy_h - 2, &g->seed) * g->galaxy_w; } else if (g->players > 3) { pi = rnd_0_nm1(g->galaxy_stars, &g->seed); } else { pi = rnd_1_n(g->galaxy_w - 2, &g->seed) + rnd_1_n(g->galaxy_h - 2, &g->seed) * g->galaxy_w; } flag_again2 = false; for (int j = 0; j < i; ++j) { if (tblhome[j] == pi) { flag_again2 = true; } } if (pi == g->evn.planet_orion_i) { flag_again2 = true; } } tblhome[i] = pi; } { uint16_t dist, mindist; mindist = 10000; for (player_id_t i = PLAYER_0; (i < g->players) && (i < 2); ++i) { for (int j = 0; j < g->players; ++j) { if (i == j) { continue; } dist = util_math_dist_fast(g->planet[tblhome[i]].x, g->planet[tblhome[i]].y, g->planet[tblhome[j]].x, g->planet[tblhome[j]].y); SETMIN(mindist, dist); } } if (mindist < 80) { /* homeworlds too close */ flag_all_ok = false; /* could break out here */ } for (player_id_t i = PLAYER_0; (i < g->players) && (i < 2); ++i) { mindist = 10000; for (int j = 0; j < g->galaxy_stars; ++j) { planet_t *p; p = &g->planet[j]; if (1 && (p->type >= PLANET_TYPE_MINIMAL) && (j != g->evn.planet_orion_i) && (j != tblhome[i]) ) { dist = util_math_dist_fast(g->planet[tblhome[i]].x, g->planet[tblhome[i]].y, p->x, p->y); SETMIN(mindist, dist); } } if (mindist > 29) { /* ok planet too far away */ flag_all_ok = false; /* could break out here */ } } for (player_id_t i = PLAYER_0; (i < g->players) && (i < 2); ++i) { mindist = 10000; for (int j = 0; j < g->galaxy_stars; ++j) { planet_t *p; p = &g->planet[j]; if (1 && (j != g->evn.planet_orion_i) && (j != tblhome[i]) ) { dist = util_math_dist_fast(g->planet[tblhome[i]].x, g->planet[tblhome[i]].y, p->x, p->y); SETMIN(mindist, dist); } } if (mindist > 29) { /* regular planet too far away */ flag_all_ok = false; /* could break out here */ } } } ++loops; } #if 0 /* FIXME in MOO1 this is actually after the if (!flag_all_ok) test, making it ineffective */ for (int i = 0; (i < g->players) && (i <= g->difficulty); ++i) { uint16_t dist, mindist; mindist = 10000; for (int j = 0; j < g->galaxy_stars; ++j) { planet_t *p; p = &g->planet[j]; if (1 && (p->type >= PLANET_TYPE_MINIMAL) && (j != g->evn.planet_orion_i) && (j != tblhome[i]) ) { dist = util_math_dist_fast(g->planet[tblhome[i]].x, g->planet[tblhome[i]].y, p->x, p->y); SETMIN(mindist, dist); } } if (mindist > "\x1d\x23\x27\x3c\x50"[g->difficulty]) { /* ok planet too far away */ flag_all_ok = false; /* could break out here */ } } #endif return flag_all_ok; } static void game_generate_home_etc(struct game_s *g, struct game_new_options_s *opts) { uint16_t tblhome[PLAYER_NUM]; uint16_t homei; bool flag_all_ok; do { game_generate_galaxy(g, opts); game_generate_planet_names(g); if (opts->improved_galaxy_generator) { flag_all_ok = game_generate_home_improved_do(g, opts, tblhome); } else { flag_all_ok = game_generate_home_do(g, tblhome); } } while (!flag_all_ok); for (player_id_t i = PLAYER_0; i < g->players; ++i) { planet_t *p; homei = tblhome[i]; g->evn.home[i] = homei; g->planet_focus_i[i] = homei; p = &g->planet[homei]; p->owner = i; p->claim = i; p->type = PLANET_TYPE_TERRAN; p->star_type = STAR_TYPE_YELLOW; if ((opts->homeworlds.max_pop < 50) || (opts->homeworlds.max_pop > 120)) { opts->homeworlds.max_pop = 100; } p->max_pop2 = opts->homeworlds.max_pop; p->max_pop3 = opts->homeworlds.max_pop; p->max_pop1 = opts->homeworlds.max_pop; p->infogfx = tbl_planet_type_infogfx[p->type][rnd_0_nm1(6, &g->seed)] - 1; p->growth = PLANET_GROWTH_NORMAL; if ((opts->homeworlds.special < PLANET_SPECIAL_ULTRA_POOR) || (opts->homeworlds.special >= PLANET_SPECIAL_NUM)) { opts->homeworlds.special = PLANET_SPECIAL_NORMAL; } p->special = opts->homeworlds.special; BOOLVEC_SET1(p->explored, i); BOOLVEC_SET1(p->within_srange, i); p->within_frange[i] = 1; switch (g->difficulty) { case DIFFICULTY_SIMPLE: case DIFFICULTY_EASY: case DIFFICULTY_AVERAGE: p->pop = 50; p->factories = 30; p->total_prod = 55; break; case DIFFICULTY_HARD: case DIFFICULTY_IMPOSSIBLE: p->pop = 40; p->factories = 30; p->total_prod = 50; break; default: break; } p->pop_prev = p->pop; game_new_generate_home_name(g->eto[i].race, p->name, PLANET_NAME_LEN); } for (int j = 0; j < g->galaxy_stars; ++j) { player_id_t owner; owner = g->planet[j].owner; for (player_id_t i = PLAYER_0; i < g->players; ++i) { g->seen[i][j].owner = (owner == i) ? i : PLAYER_NONE; } /* seen_pop.._factories cleared here */ } if ((opts->homeworlds.num_scouts < 0) || (opts->homeworlds.num_scouts > 5)) { opts->homeworlds.num_scouts = 2; } startfleet_ships[0] = opts->homeworlds.num_scouts; if ((opts->homeworlds.num_fighters < 0) || (opts->homeworlds.num_fighters > 10)) { opts->homeworlds.num_fighters = 0; } startfleet_ships[1] = opts->homeworlds.num_fighters; if ((opts->homeworlds.num_colony_ships < 0) || (opts->homeworlds.num_colony_ships > 2)) { opts->homeworlds.num_colony_ships = 1; } startfleet_ships[4] = opts->homeworlds.num_colony_ships; for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e; e = &g->eto[i]; e->have_colony_for = PLANET_TYPE_MINIMAL; e->factory_adj_cost = 10; e->factory_cost = 10; e->have_engine = 1; e->colonist_oper_factories = 2; for (tech_field_t field = 0; field < TECH_FIELD_NUM; ++field) { e->tech.percent[field] = 1; } { shipresearch_t *srd; shipdesign_t *sd; srd = &g->srd[i]; sd = &srd->design[0]; e->shipdesigns_num = startship_num; for (int j = 0; j < startship_num; ++j, ++sd) { *sd = tbl_startship[j]; lib_strcpy(sd->name, game_str_tbl_stship_names[j], SHIP_NAME_LEN); sd->look += e->banner * SHIP_LOOK_PER_BANNER; } memcpy(&g->current_design[i], &srd->design[0], sizeof(shipdesign_t)); for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { shipcount_t n; n = startfleet_ships[j]; e->orbit[tblhome[i]].ships[j] = n; srd->shipcount[j] = n; if ((j == 4) && opts->homeworlds.armed_colony_ships && !srd->design[4].wpnt[0]) { srd->design[4].wpnn[0] = 1; srd->design[4].wpnt[0] = 2; } } } e->fuel_range = 3; if (IS_AI(g, i)) { game_ai->new_game_init(g, i, tblhome[i]); } else { e->tech.slider[TECH_FIELD_COMPUTER] = 20; e->tech.slider[TECH_FIELD_CONSTRUCTION] = 10; e->tech.slider[TECH_FIELD_FORCE_FIELD] = 15; e->tech.slider[TECH_FIELD_PLANETOLOGY] = 15; e->tech.slider[TECH_FIELD_PROPULSION] = 20; e->tech.slider[TECH_FIELD_WEAPON] = 20; } } } static void game_generate_relation_etc(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e; e = &g->eto[i]; for (player_id_t j = PLAYER_0; j < g->players; ++j) { uint16_t v; v = tbl_orion_race_relation[e->race][g->eto[j].race] * 12; e->relation1[j] = v; e->relation2[j] = v; for (int k = 0; k < TECH_FIELD_NUM; ++k) { e->spyreportfield[j][k] = 1; } } } } static bool game_generate_research_check_field(const uint8_t (*rl)[TECH_TIER_NUM][3], tech_field_t field, const uint8_t *rr) { uint8_t rmask = 0, got = 0; for (int i = 1; i < 50 + 1; ++i) { rmask |= rr[i]; } rmask &= ~(GAME_NG_TECH_NEVER | GAME_NG_TECH_ALWAYS); if (!rmask) { return true; } for (int tier = 0; tier < TECH_TIER_NUM; ++tier) { for (int l = 0; l < 3; ++l) { uint8_t v; v = rl[field][tier][l]; got |= rr[v]; } } return (rmask & got) == rmask; } static void game_generate_research(struct game_s *g, const uint8_t *rflag) { bool flag_got_essentials = false; while (!flag_got_essentials) { flag_got_essentials = true; for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { uint8_t rmax; uint8_t (*rl)[TECH_TIER_NUM][3]; race_t race; race = g->eto[pli].race; rl = g->srd[pli].researchlist; rmax = (g->eto[pli].race == RACE_PSILON) ? 3 : 2; for (tech_field_t field = TECH_FIELD_COMPUTER; field < TECH_FIELD_NUM; ++field) { const uint8_t *rr; rr = game_num_ng_tech[race][field]; for (int tier = 0; tier < TECH_TIER_NUM; ++tier) { int num_taken; num_taken = 0; for (int l = 0; l < 3; ++l) { rl[field][tier][l] = 0; } while (num_taken == 0) { for (int ti = tier * 5 + 4; (ti >= (tier * 5)) && (num_taken < 3); --ti) { if (rr[ti + 1] & GAME_NG_TECH_ALWAYS) { rl[field][tier][num_taken++] = ti + 1; } } for (int ti = tier * 5 + 4; ti >= (tier * 5); --ti) { bool flag_skip; flag_skip = false; if (0 || (rr[ti + 1] & (GAME_NG_TECH_NEVER | GAME_NG_TECH_ALWAYS)) || (rflag[field * 50 + ti] == 0) ) { flag_skip = true; } if ((!flag_skip) && (rnd_1_n(4, &g->seed) <= rmax) && (num_taken < 3)) { rl[field][tier][num_taken++] = ti + 1; } } for (int loops = 0; loops < 3; ++loops) { for (int l = 0; l < 2; ++l) { uint8_t v0, v1; v1 = rl[field][tier][l + 1]; if (v1 != 0) { v0 = rl[field][tier][l]; if (v0 > v1) { rl[field][tier][l] = v1; rl[field][tier][l + 1] = v0; } } } } } } if (!game_generate_research_check_field(rl, field, rr)) { flag_got_essentials = false; } } } } for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { empiretechorbit_t *e; shipresearch_t *srd; e = &g->eto[pli]; srd = &g->srd[pli]; e->base_shield = SHIP_SHIELD_CLASS_I; e->base_comp = SHIP_COMP_MARK_I; e->base_weapon = WEAPON_NUCLEAR_MISSILE_2; for (tech_field_t field = TECH_FIELD_COMPUTER; field < TECH_FIELD_NUM; ++field) { e->tech.completed[field] = 1; srd->researchcompleted[field][0] = 1; } } game_ai->new_game_tech(g); } static void game_generate_misc(struct game_s *g) { g->year = 1; g->evn.year = 40; for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { empiretechorbit_t *e; e = &g->eto[pli]; for (player_id_t pli2 = PLAYER_0; pli2 < g->players; ++pli2) { e->attack_bounty[pli2] = PLAYER_NONE; e->bounty_collect[pli2] = PLAYER_NONE; } } } static void game_generate_load(struct game_s *g) { /* MOO1 does these when loading a game; moved here to maintain slider state after save/load */ game_update_production(g); game_update_tech_util(g); for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { game_update_eco_on_waste(g, pli, false); game_update_seen_by_orbit(g, pli); } game_update_within_range(g); game_update_visibility(g); game_update_have_reserve_fuel(g); } static void game_generate_emperor_names(struct game_s *g, const uint8_t *namedata) { for (player_id_t pli = PLAYER_0; pli < g->players; ++pli) { uint16_t base; if (g->emperor_names[pli][0] != '\0') { continue; } base = ((uint16_t)g->eto[pli].race) * EMPEROR_NAMES_PER_RACE; for (int loops = 0; loops < 200; ++loops) { char buf[EMPEROR_NAME_LBX_LEN]; const char *str; bool flag_name_used; str = (const char *)&namedata[4 + (base + rnd_0_nm1(EMPEROR_NAMES_PER_RACE, &g->seed)) * EMPEROR_NAME_LBX_LEN]; lib_strcpy(buf, str, sizeof(buf)); util_trim_whitespace(buf, sizeof(buf)); /* fix "Zygot " */ flag_name_used = false; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (strcasecmp(buf, g->emperor_names[i]) == 0) { flag_name_used = true; break; } } if (!flag_name_used) { lib_strcpy(g->emperor_names[pli], buf, EMPEROR_NAME_LEN); break; } } } } /* -------------------------------------------------------------------------- */ int game_new(struct game_s *g, struct game_aux_s *gaux, struct game_new_options_s *opt) { uint8_t researchflag[6 * 50]; memset(g, 0, sizeof(struct game_s)); g->gaux = gaux; if (opt->galaxy_seed == 0) { g->galaxy_seed = rnd_get_new_seed(); } else { g->galaxy_seed = opt->galaxy_seed; } g->seed = g->galaxy_seed; g->ai_id = opt->ai_id; game_ai = game_ais[g->ai_id]; g->players = opt->players; g->difficulty = opt->difficulty; g->galaxy_size = opt->galaxy_size; for (player_id_t i = PLAYER_0; i < g->players; ++i) { g->eto[i].race = opt->pdata[i].race; g->eto[i].banner = opt->pdata[i].banner; if (opt->pdata[i].is_ai) { BOOLVEC_SET1(g->is_ai, i); } } { const uint8_t *rawdata; rawdata = gaux->research.d0; for (int f = 0; f < 6; ++f) { for (int t = 0; t < 50; ++t) { researchflag[f * 50 + t] = (rawdata[(f * 50 + t) * 6] != 0xff) ? 1 : 0; } researchflag[f * 50] = 0; } } researchflag[TECH_FIELD_WEAPON * 50 + (TECH_WEAP_DEATH_RAY - 1)] = 0; { uint32_t vo, vr = 0, vb = 0, m = 1, va = 0; vo = g->difficulty + g->galaxy_size * 10 + g->players * 100; for (int i = 0; i < g->players; ++i, m *= 0x10) { vr += ((g->eto[i].race + 1) % (RACE_NUM + 1)) * m; } m = 1; for (int i = 0; i < g->players; ++i, m *= 10) { vb += ((g->eto[i].banner + 1) % (BANNER_NUM + 1)) * m; if (IS_HUMAN(g, i)) { va += m; } } log_message("Game: new game -new %u:0x%x:%u:0x%x:%u -nga %u\n", vo, vr, vb, g->galaxy_seed, va, g->ai_id); } game_generate_home_etc(g, opt); game_generate_relation_etc(g); game_generate_research(g, researchflag); game_generate_misc(g); if (!game_num_update_on_load) { game_generate_load(g); } for (player_id_t i = PLAYER_0; i < g->players; ++i) { char *b; const char *str; str = opt->pdata[i].playername; b = g->emperor_names[i]; lib_strcpy(b, str, EMPEROR_NAME_LEN); util_trim_whitespace(b, EMPEROR_NAME_LEN); str = opt->pdata[i].homename; if (*str != '\0') { b = g->planet[g->planet_focus_i[i]].name; lib_strcpy(b, str, PLANET_NAME_LEN); util_trim_whitespace(b, PLANET_NAME_LEN); } } { uint8_t *namedata = lbxfile_item_get(LBXFILE_NAMES, 0); game_generate_emperor_names(g, namedata); lbxfile_item_release(LBXFILE_NAMES, namedata); } g->active_player = PLAYER_0; return 0; } int game_new_tutor(struct game_s *g, struct game_aux_s *gaux) { struct game_new_options_s opt = GAME_NEW_OPTS_DEFAULT; opt.galaxy_size = GALAXY_SIZE_MEDIUM; opt.players = 4; opt.difficulty = DIFFICULTY_SIMPLE; opt.pdata[PLAYER_0].race = RACE_KLACKON; opt.pdata[PLAYER_0].banner = BANNER_WHITE; lib_strcpy(opt.pdata[PLAYER_0].playername, "Mr Tutor", EMPEROR_NAME_LEN); lib_strcpy(opt.pdata[PLAYER_0].homename, "SOL", PLANET_NAME_LEN); opt.galaxy_seed = 0xfda3f; return game_new(g, gaux, &opt); } void game_new_generate_emperor_name(race_t race, char *buf, size_t bufsize) { if (race == RACE_RANDOM) { lib_strcpy(buf, game_str_rndempname, bufsize); } else { uint32_t seed = rnd_get_new_seed(); uint8_t *namedata = lbxfile_item_get(LBXFILE_NAMES, 0); int base = race * EMPEROR_NAMES_PER_RACE; const char *str = (const char *)&namedata[4 + (base + rnd_0_nm1(EMPEROR_NAMES_PER_RACE, &seed)) * EMPEROR_NAME_LBX_LEN]; /* TODO check if in use for the case of forced same races */ lib_strcpy(buf, str, bufsize); util_trim_whitespace(buf, bufsize); /* fix "Zygot " */ lbxfile_item_release(LBXFILE_NAMES, namedata); } } void game_new_generate_home_name(race_t race, char *buf, size_t bufsize) { /* TODO check if in use for the case of forced same races */ lib_strcpy(buf, game_str_tbl_home_names[race], bufsize); } void game_new_generate_other_emperor_name(struct game_s *g, player_id_t player) { uint8_t *namedata = lbxfile_item_get(LBXFILE_NAMES, 0); int base = g->eto[player].race * EMPEROR_NAMES_PER_RACE; for (int loops = 0; loops < 500; ++loops) { const char *str; char buf[EMPEROR_NAME_LBX_LEN + 1]; bool flag_in_use; str = (const char *)&namedata[4 + (base + rnd_0_nm1(EMPEROR_NAMES_PER_RACE, &g->seed)) * EMPEROR_NAME_LBX_LEN]; lib_strcpy(buf, str, sizeof(buf)); util_trim_whitespace(buf, sizeof(buf)); /* fix "Zygot " */ flag_in_use = true; for (int i = 0; i < g->players; ++i) { if (strcasecmp(g->emperor_names[i], buf) == 0) { flag_in_use = false; break; } } if (!flag_in_use) { lib_strcpy(g->emperor_names[player], buf, EMPEROR_NAME_LEN); break; } } lbxfile_item_release(LBXFILE_NAMES, namedata); } 1oom-1.11.2/src/game/game_new.h000066400000000000000000000046361476061725400161270ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_NEW_H #define INC_1OOM_GAME_NEW_H #include "game.h" struct game_new_options_s { bool improved_galaxy_generator; bool nebulae; uint32_t galaxy_seed; galaxy_size_t galaxy_size; difficulty_t difficulty; uint32_t ai_id; uint32_t players; struct { uint32_t max_pop; planet_special_t special; uint32_t num_dist_checks; uint32_t num_ok_planet_checks; uint32_t num_scouts; uint32_t num_fighters; uint32_t num_colony_ships; bool armed_colony_ships; } homeworlds; struct { char playername[EMPEROR_NAME_LEN]; char homename[PLANET_NAME_LEN]; race_t race; banner_t banner; bool is_ai; } pdata[PLAYER_NUM]; }; #define GAME_NEW_OPTS_DEFAULT \ { \ 0, 1, 0, GALAXY_SIZE_SMALL, DIFFICULTY_SIMPLE, 0, 2, \ { \ 100, PLANET_SPECIAL_NORMAL, \ 2, 2, \ 2, 0, 1, false \ }, \ { \ { "", "", RACE_HUMAN, BANNER_BLUE, false }, \ { "", "", RACE_RANDOM, BANNER_RANDOM, true }, \ { "", "", RACE_RANDOM, BANNER_RANDOM, true }, \ { "", "", RACE_RANDOM, BANNER_RANDOM, true }, \ { "", "", RACE_RANDOM, BANNER_RANDOM, true }, \ { "", "", RACE_RANDOM, BANNER_RANDOM, true } \ } \ } #define GAME_NEW_OPTS_CHALLENGE_118835000 \ { \ 1, 1, 118835000, GALAXY_SIZE_SMALL, DIFFICULTY_IMPOSSIBLE, 0, 6, \ { \ 100, PLANET_SPECIAL_NORMAL, \ 6, 6, \ 2, 0, 1, false \ }, \ { \ { "", "", RACE_HUMAN, BANNER_BLUE, false }, \ { "", "", RACE_MRRSHAN, BANNER_RANDOM, true }, \ { "", "", RACE_SAKKRA, BANNER_RANDOM, true }, \ { "", "", RACE_PSILON, BANNER_RANDOM, true }, \ { "", "", RACE_KLACKON, BANNER_RANDOM, true }, \ { "", "", RACE_SILICOID, BANNER_RANDOM, true } \ } \ } struct game_aux_s; extern int game_new(struct game_s *g, struct game_aux_s *gaux, struct game_new_options_s *opt); extern int game_new_tutor(struct game_s *g, struct game_aux_s *gaux); extern void game_new_generate_emperor_name(race_t race, char *buf, size_t bufsize); extern void game_new_generate_home_name(race_t race, char *buf, size_t bufsize); extern void game_new_generate_other_emperor_name(struct game_s *g, player_id_t player); #endif 1oom-1.11.2/src/game/game_news.c000066400000000000000000000115441476061725400163010ustar00rootroot00000000000000#include "config.h" #include #include #include "game_news.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_stat.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ void game_news_get_msg(const struct game_s *g, struct news_s *ns, char *buf, size_t buf_size) { const char *msg = EVENTMSG_PTR(g->gaux, ns->type, ns->subtype); struct strbuild_s strbuild = strbuild_init(buf, buf_size); for (int i = 0; (i < EVENTMSG_LEN) && (msg[i] != 0); ++i) { char c; c = msg[i]; /* Fill in placeholders. */ if (c & 0x80) { char techname[64]; switch (c & 0x7f) { case 0: strbuild_catf(&strbuild, "%s", g->planet[ns->planet_i].name); break; case 1: strbuild_catf(&strbuild, "%i", ns->num1); break; case 2: strbuild_catf(&strbuild, "%i", ns->num2); break; case 3: if (ns->num1 != 1) { strbuild_append_char(&strbuild, 's'); } break; case 0xe: if ((ns->num1 == 2) || (ns->num1 == 3)) { strbuild_append_char(&strbuild, 'n'); } strbuild_append_char(&strbuild, ' '); break; case 0xd: if (ns->num1 == 1) { strbuild_append_char(&strbuild, 's'); } break; case 4: strbuild_catf(&strbuild, "%s", game_str_tbl_race[ns->race]); break; case 5: strbuild_catf(&strbuild, "%s", game_str_tbl_race[g->eto[ns->num2].race]); break; case 6: strbuild_catf(&strbuild, "%s", game_str_tbl_te_field[ns->num1]); break; case 7: game_tech_get_name(g->gaux, ns->num2 / 50, ns->num2 % 50, techname, sizeof(techname)); strbuild_catf(&strbuild, "%s", techname); break; case 8: strbuild_catf(&strbuild, "%s", game_str_tbl_trait1[ns->num1]); break; case 9: strbuild_catf(&strbuild, "%s", game_str_tbl_trait2[ns->num2]); break; case 0xc: strbuild_catf(&strbuild, "%s", g->emperor_names[ns->num1]); break; default: strbuild_append_char(&strbuild, c); break; } } else { strbuild_append_char(&strbuild, c); } } if (ns->type == GAME_NEWS_STATS) { int num = 0; int tbl_player[PLAYER_NUM]; int tbl_stat[PLAYER_NUM]; for (int i = 0; i < PLAYER_NUM; ++i) { ns->stats[i] = 0; } for (int i = 0; i < g->players; ++i) { if (g->evn.home[i] != PLANET_NONE) { int v; tbl_player[num] = i; switch (ns->subtype) { case 0: v = game_stat_prod(g, i); SETMAX(v, 1); break; case 1: v = game_stat_pop(g, i); SETMAX(v, 1); break; case 2: v = game_stat_tech(g, i); SETMAX(v, 1); break; case 3: v = game_stat_fleet(g, i); SETMAX(v, 1); break; default: v = 0; break; } tbl_stat[num] = v; if (v != 0) { ++num; } } } ns->statsnum = num; for (int loops = 0; loops < num; ++loops) { for (int i = 0; i < (num - 1); ++i) { int v0, v1; v0 = tbl_stat[i]; v1 = tbl_stat[i + 1]; if (v0 < v1) { tbl_stat[i] = v1; tbl_stat[i + 1] = v0; v0 = tbl_player[i]; tbl_player[i] = tbl_player[i + 1]; tbl_player[i + 1] = v0; } } } for (int i = 0; i < num; ++i) { ns->stats[i] = game_str_tbl_race[g->eto[tbl_player[i]].race]; } } else { ns->statsnum = 0; } } 1oom-1.11.2/src/game/game_news.h000066400000000000000000000021401476061725400162760ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_NEWS_H #define INC_1OOM_GAME_NEWS_H #include "game_types.h" #include "types.h" /* order in eventmsg.lbx */ typedef enum { GAME_NEWS_NONE = 0, GAME_NEWS_PLAGUE, /*1*/ GAME_NEWS_QUAKE, /*2*/ GAME_NEWS_NOVA, /*3*/ GAME_NEWS_ACCIDENT, /*4*/ GAME_NEWS_ASSASSIN, /*5*/ GAME_NEWS_VIRUS, /*6*/ GAME_NEWS_COMET, /*7*/ GAME_NEWS_PIRATES, /*8*/ GAME_NEWS_DERELICT, /*9*/ GAME_NEWS_REBELLION, /*10*/ GAME_NEWS_CRYSTAL, /*11*/ GAME_NEWS_AMOEBA, /*12*/ GAME_NEWS_ENVIRO, /*13*/ GAME_NEWS_RICH, /*14*/ GAME_NEWS_SUPPORT, /*15*/ GAME_NEWS_POOR, /*16*/ GAME_NEWS_ORION, /*17*/ GAME_NEWS_COUP, /*18*/ GAME_NEWS_STARS, /*19*/ GAME_NEWS_STATS, /*20*/ GAME_NEWS_GENOCIDE, /*21*/ GAME_NEWS_GUARDIAN /*22*/ } news_type_t; struct news_s { news_type_t type; int subtype; int statsnum; int num1; int num2; race_t race; const char *stats[PLAYER_NUM]; uint8_t planet_i; }; struct game_s; extern void game_news_get_msg(const struct game_s *g, struct news_s *ns, char *buf, size_t buf_size); #endif 1oom-1.11.2/src/game/game_num.c000066400000000000000000000161631476061725400161260ustar00rootroot00000000000000#include "config.h" #include "game_num.h" #include "game_types.h" #include "types.h" /* -------------------------------------------------------------------------- */ bool game_num_deterministic = false; bool game_num_ai_trans_range_fix = false; bool game_num_ai_4_colony_curse_fix = false; bool game_num_ai_first_tech_cost_fix = false; int game_num_bt_turn_max = 50; bool game_num_bt_wait_no_reload = false; bool game_num_bt_precap_tohit = false; bool game_num_bt_no_tohit_acc = false; bool game_num_bt_oracle_fix = false; int game_num_stargate_cost = 3000; int game_num_stargate_maint = 100; int game_num_weapon_list_max = 30; int game_num_limit_ships = 32000; int game_num_limit_ships_all = 32000; int game_num_max_pop = 300; int game_num_max_factories = 2500; int game_num_max_inbound = 300; int game_num_atmos_cost = 200; int game_num_soil_cost = 150; int game_num_adv_soil_cost = 300; int game_num_adv_scan_range = 110; int game_num_pop_hp = 200; int game_num_fact_hp = 50; int game_num_max_bomb_dmg = 100000; int game_num_max_bio_dmg = 10000; int game_num_max_trans_dmg = 32000; int game_num_max_ship_maint = 32000; int game_num_max_tribute_bc = 32000; int game_num_event_roll = 512; bool game_num_accident_chk_factories = false; int game_num_council_years = 25; bool game_num_news_orion = false; bool game_num_aud_ask_break_nap = false; bool game_num_aud_bounty_give = false; bool game_num_aud_update_tech = false; bool game_num_update_on_load = true; bool game_num_newtech_adjust_fix = false; bool game_num_monster_rest_att = false; bool game_num_orbital_bio_fix = false; bool game_num_orbital_weap_any = false; bool game_num_orbital_weap_4 = false; bool game_num_orbital_torpedo = false; bool game_num_orbital_comp_fix = false; bool game_num_combat_trans_fix = false; bool game_num_stargate_redir_fix = false; bool game_num_trans_redir_fix = false; bool game_num_retreat_redir_fix = false; bool game_num_first_tech_rp_fix = false; bool game_num_waste_calc_fix = false; bool game_num_waste_adjust_fix = false; bool game_num_slider_respects_locks = false; bool game_num_pop_tenths_fix = false; bool game_num_factory_cost_fix = false; bool game_num_doom_stack_fix = false; uint8_t game_num_eco_slider_slack = 7; bool game_num_reset_tform_to_max = true; bool game_num_soil_rounding_fix = false; bool game_num_leaving_trans_fix = false; bool game_num_hidden_child_labor_fix = false; bool game_num_extended_reloc_range = false; bool game_num_colonized_factories_fix = false; bool game_num_cond_switch_to_ind_fix = false; bool game_num_slider_eco_done_fix = false; bool game_num_ship_scanner_fix = false; bool game_num_ai_fleet_cheating_fix = false; uint8_t game_num_tbl_hull_w[4] = { 1, 5, 25, 125 }; uint16_t game_num_base_hp[BASE_HP_TBL_NUM] = { 50, 75, 100, 125, 150, 175, 200 }; uint16_t game_num_pshield_cost[PSHIELD_NUM] = { 0, 500, 1000, 1500, 2000 }; uint8_t game_num_tech_costmuld[DIFFICULTY_NUM] = { 20, 25, 30, 35, 40 }; uint8_t game_num_tech_costmula[DIFFICULTY_NUM] = { 20, 20, 20, 20, 20 }; int game_num_tech_costmuld2 = 100; int game_num_tech_costmula2 = 100; int game_num_tech_costmul = 100; uint8_t game_num_tech_costmulr[RACE_NUM][TECH_FIELD_NUM] = { { 100, 100, 60, 80, 80, 100 }, { 100, 125, 100, 100, 100, 60 }, { 80, 125, 125, 125, 125, 125 }, { 100, 100, 100, 60, 100, 100 }, { 80, 80, 80, 80, 80, 80 }, { 100, 100, 125, 100, 60, 100 }, { 100, 60, 100, 100, 125, 100 }, { 125, 80, 100, 100, 100, 80 }, { 60, 100, 100, 125, 100, 100 }, { 80, 100, 100, 100, 100, 100 } }; /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 */ #define GAME_NUMT_CM { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0 } #define GAME_NUMT_CN { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define GAME_NUMT_FF { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define GAME_NUMT_PL { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0 } #define GAME_NUMT_PR { 0, 0, 0, 4, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } #define GAME_NUMT_WE { 0, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 0, 0, 0, 0, 0, 0 } uint8_t game_num_ng_tech[RACE_NUM][TECH_FIELD_NUM][50 + 1] = { { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { /* silicoid */ GAME_NUMT_CM, /* 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 */ { 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, GAME_NUMT_FF, { 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 1, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0 }, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE }, { GAME_NUMT_CM, GAME_NUMT_CN, GAME_NUMT_FF, GAME_NUMT_PL, GAME_NUMT_PR, GAME_NUMT_WE } }; uint8_t game_num_tbl_trait1[RACE_NUM][TRAIT1_TBL_NUM] = { { 4, 4, 4, 4, 4, 4, 4, 5, 5, 3 }, { 1, 1, 1, 1, 1, 1, 1, 2, 2, 0 }, { 0, 0, 0, 0, 0, 0, 0, 2, 2, 3 }, { 2, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, { 5, 5, 5, 5, 5, 5, 5, 4, 3, 3 }, { 4, 4, 4, 4, 4, 4, 4, 5, 5, 3 }, { 0, 0, 0, 0, 0, 0, 0, 2, 2, 1 }, { 2, 2, 2, 2, 2, 2, 2, 3, 3, 1 }, { 3, 3, 3, 3, 3, 3, 3, 2, 2, 0 }, { 2, 2, 2, 2, 2, 2, 2, 1, 1, 0 } }; uint8_t game_num_tbl_trait2[RACE_NUM][TRAIT2_TBL_NUM] = { { 0, 0, 0, 0, 1, 2, 3, 4, 4, 0, 3, 5 }, { 0, 1, 1, 1, 1, 3, 2, 2, 3, 3, 4, 5 }, { 0, 1, 2, 2, 2, 2, 3, 3, 3, 4, 4, 5 }, { 0, 3, 1, 5, 5, 3, 4, 2, 2, 2, 2, 2 }, { 0, 0, 3, 1, 2, 3, 3, 3, 3, 4, 4, 5 }, { 0, 1, 1, 1, 2, 2, 2, 3, 4, 2, 3, 5 }, { 0, 1, 1, 2, 2, 3, 3, 4, 5, 5, 5, 5 }, { 0, 5, 5, 5, 5, 2, 2, 3, 3, 3, 4, 5 }, { 0, 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, 5 }, { 0, 0, 3, 3, 1, 2, 0, 3, 3, 4, 4, 5 } }; uint8_t game_num_tbl_tech_autoadj[4] = { 0, 25, 50, 75 }; 1oom-1.11.2/src/game/game_num.h000066400000000000000000000065101476061725400161260ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_NUM_H #define INC_1OOM_GAME_NUM_H #include "game_types.h" #include "types.h" extern bool game_num_deterministic; extern bool game_num_ai_trans_range_fix; extern bool game_num_ai_4_colony_curse_fix; extern bool game_num_ai_first_tech_cost_fix; extern int game_num_bt_turn_max; extern bool game_num_bt_wait_no_reload; extern bool game_num_bt_precap_tohit; extern bool game_num_bt_no_tohit_acc; extern bool game_num_bt_oracle_fix; extern int game_num_stargate_cost; extern int game_num_stargate_maint; extern int game_num_weapon_list_max; extern int game_num_limit_ships; extern int game_num_limit_ships_all; extern int game_num_max_pop; extern int game_num_max_factories; extern int game_num_max_inbound; extern int game_num_atmos_cost; extern int game_num_soil_cost; extern int game_num_adv_soil_cost; extern int game_num_adv_scan_range; extern int game_num_pop_hp; extern int game_num_fact_hp; extern int game_num_max_bomb_dmg; extern int game_num_max_bio_dmg; extern int game_num_max_trans_dmg; extern int game_num_max_ship_maint; extern int game_num_max_tribute_bc; extern int game_num_event_roll; extern bool game_num_accident_chk_factories; extern int game_num_council_years; extern bool game_num_news_orion; extern bool game_num_aud_ask_break_nap; extern bool game_num_aud_bounty_give; extern bool game_num_aud_update_tech; extern bool game_num_update_on_load; extern bool game_num_newtech_adjust_fix; extern bool game_num_monster_rest_att; extern bool game_num_orbital_bio_fix; extern bool game_num_orbital_weap_any; extern bool game_num_orbital_weap_4; extern bool game_num_orbital_torpedo; extern bool game_num_orbital_comp_fix; extern bool game_num_combat_trans_fix; extern bool game_num_stargate_redir_fix; extern bool game_num_trans_redir_fix; extern bool game_num_retreat_redir_fix; extern bool game_num_first_tech_rp_fix; extern bool game_num_waste_calc_fix; extern bool game_num_waste_adjust_fix; extern bool game_num_slider_respects_locks; extern bool game_num_pop_tenths_fix; extern bool game_num_factory_cost_fix; extern bool game_num_doom_stack_fix; extern uint8_t game_num_eco_slider_slack; extern bool game_num_reset_tform_to_max; extern bool game_num_soil_rounding_fix; extern bool game_num_leaving_trans_fix; extern bool game_num_hidden_child_labor_fix; extern bool game_num_extended_reloc_range; extern bool game_num_colonized_factories_fix; extern bool game_num_cond_switch_to_ind_fix; extern bool game_num_slider_eco_done_fix; extern bool game_num_ship_scanner_fix; extern bool game_num_ai_fleet_cheating_fix; extern uint8_t game_num_tbl_hull_w[4]; extern uint8_t game_num_tech_costmuld[DIFFICULTY_NUM]; extern uint8_t game_num_tech_costmula[DIFFICULTY_NUM]; extern int game_num_tech_costmuld2; extern int game_num_tech_costmula2; extern int game_num_tech_costmul; extern uint8_t game_num_tech_costmulr[RACE_NUM][TECH_FIELD_NUM]; #define GAME_NG_TECH_NEVER (1 << 0) #define GAME_NG_TECH_ALWAYS (1 << 1) extern uint8_t game_num_ng_tech[RACE_NUM][TECH_FIELD_NUM][50 + 1]; #define BASE_HP_TBL_NUM 7 extern uint16_t game_num_base_hp[BASE_HP_TBL_NUM]; #define TRAIT1_TBL_NUM 10 #define TRAIT2_TBL_NUM 12 extern uint8_t game_num_tbl_trait1[RACE_NUM][TRAIT1_TBL_NUM]; extern uint8_t game_num_tbl_trait2[RACE_NUM][TRAIT2_TBL_NUM]; #define PSHIELD_NUM 5 extern uint16_t game_num_pshield_cost[PSHIELD_NUM]; extern uint8_t game_num_tbl_tech_autoadj[4]; #endif 1oom-1.11.2/src/game/game_nump.c000066400000000000000000001225111476061725400163010ustar00rootroot00000000000000#include "config.h" #include #include "game_nump.h" #include "gameapi.h" #include "game_aux.h" #include "game_num.h" #include "game_parsed.h" #include "game_shipdesign.h" #include "game_shiptech.h" #include "lib.h" #include "log.h" /* -------------------------------------------------------------------------- */ #define DEFNUMITEMLSTBL(id, name, field, type, vmin, vmax) { #id, &(name->field), type, sizeof(*name), sizeof(name) / sizeof(*name), vmin, vmax } #define DEFNUMITEMLTBL(id, name, type, vmin, vmax) { #id, &name, type, sizeof(*name), sizeof(name) / sizeof(*name), vmin, vmax } #define DEFNUMITEMLTBLL(name, type, vmin, vmax) { #name, game_num_##name, type, sizeof(*game_num_##name), sizeof(game_num_##name) / sizeof(*game_num_##name), vmin, vmax } #define DEFNUMITEM(id, name, type, vmin, vmax) { #id, &name, type, sizeof(name), 1, vmin, vmax } #define DEFNUMITEML(name, type, vmin, vmax) DEFNUMITEM(name, game_num_##name, type, vmin, vmax) #define DEFNUMEND { NULL, NULL, NUMTYPE_S, 0, 0, 0, 0 } #define NUMTYPE_GUESS(z) ((sizeof(z) == 4) ? NUMTYPE_U32 : ((sizeof(z) == 2) ? NUMTYPE_U16 : NUMTYPE_U8)) #define NUMTYPE_IS_S(t) (!(t & 1)) static const struct numtbl_s { const char *numid; void *ptr; enum { NUMTYPE_S = 0, NUMTYPE_U, NUMTYPE_S8, NUMTYPE_U8, NUMTYPE_S16, NUMTYPE_U16, NUMTYPE_S32, NUMTYPE_U32, NUMTYPE_BOOL } numtype; int tstep; int size; int vmin; uint32_t vmax; } game_num_id_tbl[] = { DEFNUMITEMLSTBL(st_weap_dmgmin, tbl_shiptech_weap, damagemin, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_weap_dmgmax, tbl_shiptech_weap, damagemax, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_weap_range, tbl_shiptech_weap, range, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_weap_extraacc, tbl_shiptech_weap, extraacc, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_weap_halveshield, tbl_shiptech_weap, halveshield, NUMTYPE_BOOL, 0, 1), DEFNUMITEMLSTBL(st_weap_is_bomb, tbl_shiptech_weap, is_bomb, NUMTYPE_BOOL, 0, 1), DEFNUMITEMLSTBL(st_weap_dmgfade, tbl_shiptech_weap, damagefade, NUMTYPE_BOOL, 0, 1), DEFNUMITEMLSTBL(st_weap_misstype, tbl_shiptech_weap, misstype, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_weap_dmgmul, tbl_shiptech_weap, damagemul, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_weap_numfire, tbl_shiptech_weap, numfire, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_weap_numshots, tbl_shiptech_weap, numshots, NUMTYPE_S8, -1, 0x7f), DEFNUMITEMLSTBL(st_weap_cost, tbl_shiptech_weap, cost, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_weap_space, tbl_shiptech_weap, space, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_weap_power, tbl_shiptech_weap, power, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_weap_is_bio, tbl_shiptech_weap, is_bio, NUMTYPE_BOOL, 0, 1), DEFNUMITEMLSTBL(st_comp_tech, tbl_shiptech_weap, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_v24, tbl_shiptech_weap, v24, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl0, tbl_shiptech_weap, dtbl[0], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl1, tbl_shiptech_weap, dtbl[1], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl2, tbl_shiptech_weap, dtbl[2], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl3, tbl_shiptech_weap, dtbl[3], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl4, tbl_shiptech_weap, dtbl[4], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl4, tbl_shiptech_weap, dtbl[5], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_dtbl6, tbl_shiptech_weap, dtbl[6], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_sound, tbl_shiptech_weap, v24, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_nummiss, tbl_shiptech_weap, nummiss, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_cost0, tbl_shiptech_comp, cost[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_cost1, tbl_shiptech_comp, cost[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_cost2, tbl_shiptech_comp, cost[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_cost3, tbl_shiptech_comp, cost[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_space0, tbl_shiptech_comp, space[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_space1, tbl_shiptech_comp, space[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_space2, tbl_shiptech_comp, space[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_space3, tbl_shiptech_comp, space[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_power0, tbl_shiptech_comp, power[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_power1, tbl_shiptech_comp, power[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_power2, tbl_shiptech_comp, power[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_power3, tbl_shiptech_comp, power[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_comp_tech, tbl_shiptech_comp, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_comp_level, tbl_shiptech_comp, level, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_jamm_cost0, tbl_shiptech_jammer, cost[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_cost1, tbl_shiptech_jammer, cost[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_cost2, tbl_shiptech_jammer, cost[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_cost3, tbl_shiptech_jammer, cost[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_space0, tbl_shiptech_jammer, space[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_space1, tbl_shiptech_jammer, space[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_space2, tbl_shiptech_jammer, space[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_space3, tbl_shiptech_jammer, space[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_power0, tbl_shiptech_jammer, power[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_power1, tbl_shiptech_jammer, power[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_power2, tbl_shiptech_jammer, power[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_power3, tbl_shiptech_jammer, power[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_jamm_tech, tbl_shiptech_jammer, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_jamm_level, tbl_shiptech_jammer, level, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_engn_cost, tbl_shiptech_engine, cost, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_engn_space, tbl_shiptech_engine, space, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_engn_power, tbl_shiptech_engine, power, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_engn_warp, tbl_shiptech_engine, warp, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_engn_tech, tbl_shiptech_engine, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_armr_cost0, tbl_shiptech_armor, cost[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_cost1, tbl_shiptech_armor, cost[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_cost2, tbl_shiptech_armor, cost[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_cost3, tbl_shiptech_armor, cost[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_space0, tbl_shiptech_armor, space[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_space1, tbl_shiptech_armor, space[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_space2, tbl_shiptech_armor, space[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_space3, tbl_shiptech_armor, space[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_armr_tech, tbl_shiptech_armor, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_armr_armor, tbl_shiptech_armor, armor, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_cost0, tbl_shiptech_shield, cost[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_cost1, tbl_shiptech_shield, cost[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_cost2, tbl_shiptech_shield, cost[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_cost3, tbl_shiptech_shield, cost[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_space0, tbl_shiptech_shield, space[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_space1, tbl_shiptech_shield, space[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_space2, tbl_shiptech_shield, space[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_space3, tbl_shiptech_shield, space[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_power0, tbl_shiptech_shield, power[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_power1, tbl_shiptech_shield, power[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_power2, tbl_shiptech_shield, power[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_power3, tbl_shiptech_shield, power[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_absorb, tbl_shiptech_shield, absorb, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_shld_tech, tbl_shiptech_shield, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_cost0, tbl_shiptech_special, cost[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_cost1, tbl_shiptech_special, cost[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_cost2, tbl_shiptech_special, cost[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_cost3, tbl_shiptech_special, cost[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_space0, tbl_shiptech_special, space[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_space1, tbl_shiptech_special, space[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_space2, tbl_shiptech_special, space[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_space3, tbl_shiptech_special, space[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_power0, tbl_shiptech_special, power[0], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_power1, tbl_shiptech_special, power[1], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_power2, tbl_shiptech_special, power[2], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_power3, tbl_shiptech_special, power[3], NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_spec_tech, tbl_shiptech_special, tech_i, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_field, tbl_shiptech_special, field, NUMTYPE_GUESS(tbl_shiptech_special[0].field), 0, 5), DEFNUMITEMLSTBL(st_spec_type, tbl_shiptech_special, type, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_repair, tbl_shiptech_special, repair, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_extraman, tbl_shiptech_special, extraman, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_misshield, tbl_shiptech_special, misshield, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_extrarange, tbl_shiptech_special, extrarange, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_pulsar, tbl_shiptech_special, pulsar, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_stream, tbl_shiptech_special, stream, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(st_spec_boolmask, tbl_shiptech_special, boolmask, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_hull_cost, tbl_shiptech_hull, cost, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_hull_space, tbl_shiptech_hull, space, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_hull_hits, tbl_shiptech_hull, hits, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_hull_power, tbl_shiptech_hull, power, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(st_hull_defense, tbl_shiptech_hull, defense, NUMTYPE_S16, -0x8000, 0x7fff), DEFNUMITEML(deterministic, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(ai_trans_range_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(ai_4_colony_curse_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(ai_first_tech_cost_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(bt_turn_max, NUMTYPE_S, 1, 0xffff), DEFNUMITEML(bt_wait_no_reload, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(bt_precap_tohit, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(bt_no_tohit_acc, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(bt_oracle_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(stargate_cost, NUMTYPE_S, 1, 0xffff), DEFNUMITEML(stargate_maint, NUMTYPE_S, 1, 0xffff), DEFNUMITEML(weapon_list_max, NUMTYPE_S, 0, WEAPON_NUM), DEFNUMITEML(limit_ships, NUMTYPE_S, 1, 0xffff), DEFNUMITEML(limit_ships_all, NUMTYPE_S, 1, 0xffff), DEFNUMITEML(max_pop, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(max_factories, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(max_inbound, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(atmos_cost, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(soil_cost, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(adv_soil_cost, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(adv_scan_range, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(pop_hp, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(fact_hp, NUMTYPE_S, 1, 0x7fff), DEFNUMITEML(max_bomb_dmg, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(max_bio_dmg, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(max_trans_dmg, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(max_ship_maint, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(max_tribute_bc, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(event_roll, NUMTYPE_S, 0, 0x7fffffff), DEFNUMITEML(accident_chk_factories, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(council_years, NUMTYPE_S, 0, 0x7fff), DEFNUMITEML(news_orion, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(aud_ask_break_nap, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(aud_bounty_give, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(aud_update_tech, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(update_on_load, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(newtech_adjust_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(monster_rest_att, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(orbital_bio_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(orbital_weap_any, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(orbital_weap_4, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(orbital_torpedo, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(orbital_comp_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(combat_trans_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(stargate_redir_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(trans_redir_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(retreat_redir_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(first_tech_rp_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(waste_calc_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(waste_adjust_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(slider_respects_locks, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(pop_tenths_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(factory_cost_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(doom_stack_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(eco_slider_slack, NUMTYPE_U8, 0, 0xff), DEFNUMITEML(reset_tform_to_max, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(soil_rounding_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(leaving_trans_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(hidden_child_labor_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(extended_reloc_range, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(colonized_factories_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(cond_switch_to_ind_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(slider_eco_done_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(ship_scanner_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEML(ai_fleet_cheating_fix, NUMTYPE_BOOL, 0, 1), DEFNUMITEMLTBLL(tbl_hull_w, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBLL(tech_costmuld, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBLL(tech_costmula, NUMTYPE_U8, 0, 0xff), DEFNUMITEML(tech_costmuld2, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(tech_costmula2, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEML(tech_costmul, NUMTYPE_S, 1, 0x7fffffff), DEFNUMITEMLTBL(tcostm_human, game_num_tech_costmulr[RACE_HUMAN], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_mrrshan, game_num_tech_costmulr[RACE_MRRSHAN], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_silicoid, game_num_tech_costmulr[RACE_SILICOID], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_sakkra, game_num_tech_costmulr[RACE_SAKKRA], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_psilon, game_num_tech_costmulr[RACE_PSILON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_alkari, game_num_tech_costmulr[RACE_ALKARI], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_klackon, game_num_tech_costmulr[RACE_KLACKON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_bulrathi, game_num_tech_costmulr[RACE_BULRATHI], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_meklar, game_num_tech_costmulr[RACE_MEKLAR], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(tcostm_darlok, game_num_tech_costmulr[RACE_DARLOK], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBLL(base_hp, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLTBLL(pshield_cost, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLTBL(trait1_human, game_num_tbl_trait1[RACE_HUMAN], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_mrrshan, game_num_tbl_trait1[RACE_MRRSHAN], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_silicoid, game_num_tbl_trait1[RACE_SILICOID], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_sakkra, game_num_tbl_trait1[RACE_SAKKRA], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_psilon, game_num_tbl_trait1[RACE_PSILON], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_alkari, game_num_tbl_trait1[RACE_ALKARI], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_klackon, game_num_tbl_trait1[RACE_KLACKON], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_bulrathi, game_num_tbl_trait1[RACE_BULRATHI], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_meklar, game_num_tbl_trait1[RACE_MEKLAR], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait1_darlok, game_num_tbl_trait1[RACE_DARLOK], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_human, game_num_tbl_trait2[RACE_HUMAN], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_mrrshan, game_num_tbl_trait2[RACE_MRRSHAN], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_silicoid, game_num_tbl_trait2[RACE_SILICOID], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_sakkra, game_num_tbl_trait2[RACE_SAKKRA], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_psilon, game_num_tbl_trait2[RACE_PSILON], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_alkari, game_num_tbl_trait2[RACE_ALKARI], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_klackon, game_num_tbl_trait2[RACE_KLACKON], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_bulrathi, game_num_tbl_trait2[RACE_BULRATHI], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_meklar, game_num_tbl_trait2[RACE_MEKLAR], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBL(trait2_darlok, game_num_tbl_trait2[RACE_DARLOK], NUMTYPE_U8, 0, 5), DEFNUMITEMLTBLL(tbl_tech_autoadj, NUMTYPE_U8, 0, 100), DEFNUMITEMLSTBL(startship_cost, tbl_startship, cost, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(startship_hull, tbl_startship, hull, NUMTYPE_GUESS(ship_hull_t), 0, SHIP_HULL_NUM - 1), DEFNUMITEMLSTBL(startship_look, tbl_startship, look, NUMTYPE_U8, 0, NUM_SHIPLOOKS - 1), DEFNUMITEMLSTBL(startship_wpnt1, tbl_startship, wpnt[0], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(startship_wpnt2, tbl_startship, wpnt[1], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(startship_wpnt3, tbl_startship, wpnt[2], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(startship_wpnt4, tbl_startship, wpnt[3], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(startship_wpnn1, tbl_startship, wpnn[0], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(startship_wpnn2, tbl_startship, wpnn[1], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(startship_wpnn3, tbl_startship, wpnn[2], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(startship_wpnn4, tbl_startship, wpnn[3], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(startship_engine, tbl_startship, engine, NUMTYPE_GUESS(ship_engine_t), 0, SHIP_ENGINE_NUM - 1), DEFNUMITEMLSTBL(startship_engines, tbl_startship, engines, NUMTYPE_U32, 0, 0xffffffff), DEFNUMITEMLSTBL(startship_special1, tbl_startship, special[0], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(startship_special2, tbl_startship, special[1], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(startship_special3, tbl_startship, special[2], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(startship_shield, tbl_startship, shield, NUMTYPE_GUESS(ship_shield_t), 0, SHIP_SHIELD_NUM - 1), DEFNUMITEMLSTBL(startship_jammer, tbl_startship, jammer, NUMTYPE_GUESS(ship_jammer_t), 0, SHIP_JAMMER_NUM - 1), DEFNUMITEMLSTBL(startship_comp, tbl_startship, comp, NUMTYPE_GUESS(ship_comp_t), 0, SHIP_COMP_NUM - 1), DEFNUMITEMLSTBL(startship_armor, tbl_startship, armor, NUMTYPE_GUESS(ship_armor_t), 0, SHIP_ARMOR_NUM - 1), DEFNUMITEMLSTBL(startship_man, tbl_startship, man, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(startship_hp, tbl_startship, hp, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLTBL(startship_num, startfleet_ships, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(crystal_hull, tbl_monster[MONSTER_CRYSTAL], hull, NUMTYPE_GUESS(ship_hull_t), 0, SHIP_HULL_NUM - 1), DEFNUMITEMLSTBL(crystal_comp, tbl_monster[MONSTER_CRYSTAL], comp, NUMTYPE_GUESS(ship_comp_t), 0, SHIP_COMP_NUM - 1), DEFNUMITEMLSTBL(crystal_jammer, tbl_monster[MONSTER_CRYSTAL], jammer, NUMTYPE_GUESS(ship_jammer_t), 0, SHIP_JAMMER_NUM - 1), DEFNUMITEMLSTBL(crystal_shield, tbl_monster[MONSTER_CRYSTAL], shield, NUMTYPE_GUESS(ship_shield_t), 0, SHIP_SHIELD_NUM - 1), DEFNUMITEMLSTBL(crystal_armor, tbl_monster[MONSTER_CRYSTAL], armor, NUMTYPE_GUESS(ship_armor_t), 0, SHIP_ARMOR_NUM - 1), DEFNUMITEMLSTBL(crystal_engine, tbl_monster[MONSTER_CRYSTAL], engine, NUMTYPE_GUESS(ship_engine_t), 0, SHIP_ENGINE_NUM - 1), DEFNUMITEMLSTBL(crystal_special1, tbl_monster[MONSTER_CRYSTAL], special[0], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(crystal_special2, tbl_monster[MONSTER_CRYSTAL], special[1], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(crystal_special3, tbl_monster[MONSTER_CRYSTAL], special[2], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(crystal_wpnt1, tbl_monster[MONSTER_CRYSTAL], wpnt[0], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(crystal_wpnt2, tbl_monster[MONSTER_CRYSTAL], wpnt[1], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(crystal_wpnt3, tbl_monster[MONSTER_CRYSTAL], wpnt[2], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(crystal_wpnt4, tbl_monster[MONSTER_CRYSTAL], wpnt[3], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(crystal_wpnn1, tbl_monster[MONSTER_CRYSTAL], wpnn[0], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_wpnn2, tbl_monster[MONSTER_CRYSTAL], wpnn[1], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_wpnn3, tbl_monster[MONSTER_CRYSTAL], wpnn[2], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_wpnn4, tbl_monster[MONSTER_CRYSTAL], wpnn[3], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_hp, tbl_monster[MONSTER_CRYSTAL], hp, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(crystal_man, tbl_monster[MONSTER_CRYSTAL], man, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_complevel, tbl_monster[MONSTER_CRYSTAL], complevel, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_defense, tbl_monster[MONSTER_CRYSTAL], defense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_misdefense, tbl_monster[MONSTER_CRYSTAL], misdefense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_absorb, tbl_monster[MONSTER_CRYSTAL], absorb, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_repair, tbl_monster[MONSTER_CRYSTAL], repair, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_misshield, tbl_monster[MONSTER_CRYSTAL], misshield, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_extrarange, tbl_monster[MONSTER_CRYSTAL], extrarange, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_num, tbl_monster[MONSTER_CRYSTAL], num, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(crystal_look, tbl_monster[MONSTER_CRYSTAL], look, NUMTYPE_U8, 0, NUM_SHIPLOOKS - 1), DEFNUMITEMLSTBL(crystal_pulsar, tbl_monster[MONSTER_CRYSTAL], pulsar, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_stream, tbl_monster[MONSTER_CRYSTAL], stream, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(crystal_sbmask, tbl_monster[MONSTER_CRYSTAL], sbmask, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(amoeba_hull, tbl_monster[MONSTER_AMOEBA], hull, NUMTYPE_GUESS(ship_hull_t), 0, SHIP_HULL_NUM - 1), DEFNUMITEMLSTBL(amoeba_comp, tbl_monster[MONSTER_AMOEBA], comp, NUMTYPE_GUESS(ship_comp_t), 0, SHIP_COMP_NUM - 1), DEFNUMITEMLSTBL(amoeba_jammer, tbl_monster[MONSTER_AMOEBA], jammer, NUMTYPE_GUESS(ship_jammer_t), 0, SHIP_JAMMER_NUM - 1), DEFNUMITEMLSTBL(amoeba_shield, tbl_monster[MONSTER_AMOEBA], shield, NUMTYPE_GUESS(ship_shield_t), 0, SHIP_SHIELD_NUM - 1), DEFNUMITEMLSTBL(amoeba_armor, tbl_monster[MONSTER_AMOEBA], armor, NUMTYPE_GUESS(ship_armor_t), 0, SHIP_ARMOR_NUM - 1), DEFNUMITEMLSTBL(amoeba_engine, tbl_monster[MONSTER_AMOEBA], engine, NUMTYPE_GUESS(ship_engine_t), 0, SHIP_ENGINE_NUM - 1), DEFNUMITEMLSTBL(amoeba_special1, tbl_monster[MONSTER_AMOEBA], special[0], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(amoeba_special2, tbl_monster[MONSTER_AMOEBA], special[1], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(amoeba_special3, tbl_monster[MONSTER_AMOEBA], special[2], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(amoeba_wpnt1, tbl_monster[MONSTER_AMOEBA], wpnt[0], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(amoeba_wpnt2, tbl_monster[MONSTER_AMOEBA], wpnt[1], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(amoeba_wpnt3, tbl_monster[MONSTER_AMOEBA], wpnt[2], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(amoeba_wpnt4, tbl_monster[MONSTER_AMOEBA], wpnt[3], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(amoeba_wpnn1, tbl_monster[MONSTER_AMOEBA], wpnn[0], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_wpnn2, tbl_monster[MONSTER_AMOEBA], wpnn[1], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_wpnn3, tbl_monster[MONSTER_AMOEBA], wpnn[2], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_wpnn4, tbl_monster[MONSTER_AMOEBA], wpnn[3], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_hp, tbl_monster[MONSTER_AMOEBA], hp, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(amoeba_man, tbl_monster[MONSTER_AMOEBA], man, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_complevel, tbl_monster[MONSTER_AMOEBA], complevel, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_defense, tbl_monster[MONSTER_AMOEBA], defense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_misdefense, tbl_monster[MONSTER_AMOEBA], misdefense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_absorb, tbl_monster[MONSTER_AMOEBA], absorb, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_repair, tbl_monster[MONSTER_AMOEBA], repair, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_misshield, tbl_monster[MONSTER_AMOEBA], misshield, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_extrarange, tbl_monster[MONSTER_AMOEBA], extrarange, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_num, tbl_monster[MONSTER_AMOEBA], num, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(amoeba_look, tbl_monster[MONSTER_AMOEBA], look, NUMTYPE_U8, 0, NUM_SHIPLOOKS - 1), DEFNUMITEMLSTBL(amoeba_pulsar, tbl_monster[MONSTER_AMOEBA], pulsar, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_stream, tbl_monster[MONSTER_AMOEBA], stream, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(amoeba_sbmask, tbl_monster[MONSTER_AMOEBA], sbmask, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(guardian_hull, tbl_monster[MONSTER_GUARDIAN], hull, NUMTYPE_GUESS(ship_hull_t), 0, SHIP_HULL_NUM - 1), DEFNUMITEMLSTBL(guardian_comp, tbl_monster[MONSTER_GUARDIAN], comp, NUMTYPE_GUESS(ship_comp_t), 0, SHIP_COMP_NUM - 1), DEFNUMITEMLSTBL(guardian_jammer, tbl_monster[MONSTER_GUARDIAN], jammer, NUMTYPE_GUESS(ship_jammer_t), 0, SHIP_JAMMER_NUM - 1), DEFNUMITEMLSTBL(guardian_shield, tbl_monster[MONSTER_GUARDIAN], shield, NUMTYPE_GUESS(ship_shield_t), 0, SHIP_SHIELD_NUM - 1), DEFNUMITEMLSTBL(guardian_armor, tbl_monster[MONSTER_GUARDIAN], armor, NUMTYPE_GUESS(ship_armor_t), 0, SHIP_ARMOR_NUM - 1), DEFNUMITEMLSTBL(guardian_engine, tbl_monster[MONSTER_GUARDIAN], engine, NUMTYPE_GUESS(ship_engine_t), 0, SHIP_ENGINE_NUM - 1), DEFNUMITEMLSTBL(guardian_special1, tbl_monster[MONSTER_GUARDIAN], special[0], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(guardian_special2, tbl_monster[MONSTER_GUARDIAN], special[1], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(guardian_special3, tbl_monster[MONSTER_GUARDIAN], special[2], NUMTYPE_GUESS(ship_special_t), 0, SHIP_SPECIAL_NUM - 1), DEFNUMITEMLSTBL(guardian_wpnt1, tbl_monster[MONSTER_GUARDIAN], wpnt[0], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(guardian_wpnt2, tbl_monster[MONSTER_GUARDIAN], wpnt[1], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(guardian_wpnt3, tbl_monster[MONSTER_GUARDIAN], wpnt[2], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(guardian_wpnt4, tbl_monster[MONSTER_GUARDIAN], wpnt[3], NUMTYPE_GUESS(weapon_t), 0, WEAPON_NUM - 1), DEFNUMITEMLSTBL(guardian_wpnn1, tbl_monster[MONSTER_GUARDIAN], wpnn[0], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_wpnn2, tbl_monster[MONSTER_GUARDIAN], wpnn[1], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_wpnn3, tbl_monster[MONSTER_GUARDIAN], wpnn[2], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_wpnn4, tbl_monster[MONSTER_GUARDIAN], wpnn[3], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_hp, tbl_monster[MONSTER_GUARDIAN], hp, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(guardian_man, tbl_monster[MONSTER_GUARDIAN], man, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_complevel, tbl_monster[MONSTER_GUARDIAN], complevel, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_defense, tbl_monster[MONSTER_GUARDIAN], defense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_misdefense, tbl_monster[MONSTER_GUARDIAN], misdefense, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_absorb, tbl_monster[MONSTER_GUARDIAN], absorb, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_repair, tbl_monster[MONSTER_GUARDIAN], repair, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_misshield, tbl_monster[MONSTER_GUARDIAN], misshield, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_extrarange, tbl_monster[MONSTER_GUARDIAN], extrarange, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_num, tbl_monster[MONSTER_GUARDIAN], num, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLSTBL(guardian_look, tbl_monster[MONSTER_GUARDIAN], look, NUMTYPE_U8, 0, NUM_SHIPLOOKS - 1), DEFNUMITEMLSTBL(guardian_pulsar, tbl_monster[MONSTER_GUARDIAN], pulsar, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_stream, tbl_monster[MONSTER_GUARDIAN], stream, NUMTYPE_U8, 0, 0xff), DEFNUMITEMLSTBL(guardian_sbmask, tbl_monster[MONSTER_GUARDIAN], sbmask, NUMTYPE_U16, 0, 0xffff), DEFNUMITEMLTBL(ngt_cm_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cm_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_COMPUTER], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_cn_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_CONSTRUCTION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_ff_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_FORCE_FIELD], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pl_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_PLANETOLOGY], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_pr_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_PROPULSION], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_human, game_num_ng_tech[RACE_HUMAN][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_mrrshan, game_num_ng_tech[RACE_MRRSHAN][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_silicoid, game_num_ng_tech[RACE_SILICOID][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_sakkra, game_num_ng_tech[RACE_SAKKRA][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_psilon, game_num_ng_tech[RACE_PSILON][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_alkari, game_num_ng_tech[RACE_ALKARI][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_klackon, game_num_ng_tech[RACE_KLACKON][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_bulrathi, game_num_ng_tech[RACE_BULRATHI][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_meklar, game_num_ng_tech[RACE_MEKLAR][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMITEMLTBL(ngt_we_darlok, game_num_ng_tech[RACE_DARLOK][TECH_FIELD_WEAPON], NUMTYPE_U8, 0, 0xff), DEFNUMEND }; /* -------------------------------------------------------------------------- */ static const struct numtbl_s *find_match(const char *numid, int i, int num) { const struct numtbl_s *s = &game_num_id_tbl[0]; while (s->numid) { if (strcmp(s->numid, numid) == 0) { if ((num > 0) && ((i + num) <= s->size)) { return s; } else { log_error("NUM: numid '%s' index %i+%i=%i > size %i\n", numid, i, num, i + num, s->size); return NULL; } } ++s; } log_error("NUM: unknown numid '%s'\n", numid); return NULL; } /* -------------------------------------------------------------------------- */ bool game_opt_fix_bugs = false; bool game_opt_fix_guardian_repair = false; bool game_opt_fix_starting_ships = false; void game_num_fix_bugs(void) { game_num_ng_tech[RACE_SILICOID][TECH_FIELD_PLANETOLOGY][24] = 1; game_num_ng_tech[RACE_SILICOID][TECH_FIELD_PLANETOLOGY][30] = 1; game_num_max_factories = 2700; game_num_accident_chk_factories = true; game_num_weapon_list_max = 64; game_num_aud_bounty_give = true; game_num_aud_update_tech = true; game_num_update_on_load = false; game_num_combat_trans_fix = true; game_num_eco_slider_slack = 0; game_num_reset_tform_to_max = false; } void game_num_fix_guardian_repair(void) { tbl_monster[MONSTER_GUARDIAN][3].special[1] = 16; tbl_monster[MONSTER_GUARDIAN][4].special[1] = 26; tbl_monster[MONSTER_GUARDIAN][4].repair = 30; } void game_num_fix_starting_ships(void) { tbl_startship[0].engines = 2; tbl_startship[1].engines = 27; tbl_startship[2].engines = 110; tbl_startship[3].engines = 85; tbl_startship[4].engines = 100; tbl_startship[0].cost = 8; tbl_startship[1].cost = 14; tbl_startship[2].cost = 74; tbl_startship[3].cost = 65; tbl_startship[4].cost = 570; } bool game_num_patch(const char *numid, const int32_t *patchnums, int first, int num) { const struct numtbl_s *s = find_match(numid, first, num); if (s) { void *p; bool is_signed; p = ((uint8_t *)s->ptr) + first * s->tstep; is_signed = NUMTYPE_IS_S(s->numtype); for (int i = 0; i < num; ++i) { int32_t v; v = patchnums[i]; if (0 || ((is_signed) && ((v < s->vmin) || (v > s->vmax))) || ((!is_signed) && ((((uint32_t)v) < s->vmin) || (((uint32_t)v) > s->vmax))) ) { log_error("NUM: numid '%s' %ssigned value %i (%u) outside range %i..%u\n", numid, is_signed ? "" : "un", v, (uint32_t)v, s->vmin, s->vmax); return false; } switch (s->numtype) { default: case NUMTYPE_S: *((int *)p) = v; break; case NUMTYPE_U: *((unsigned int *)p) = (unsigned int)v; break; case NUMTYPE_S8: *((int8_t *)p) = (int8_t)v; break; case NUMTYPE_U8: *((uint8_t *)p) = (uint8_t)v; break; case NUMTYPE_S16: *((int16_t *)p) = (int16_t)v; break; case NUMTYPE_U16: *((uint16_t *)p) = (uint16_t)v; break; case NUMTYPE_S32: *((int32_t *)p) = v; break; case NUMTYPE_U32: *((uint32_t *)p) = (uint32_t)v; break; case NUMTYPE_BOOL: *((bool *)p) = (v != 0); break; } p = ((uint8_t *)p) + s->tstep; } return true; } else { return false; } } void game_num_dump(void) { const struct numtbl_s *s = &game_num_id_tbl[0]; int prevmin = 1, prevmax = 0; log_message("# dump of all patchable game numbers\n"); while (s->numid) { void *p; p = s->ptr; if ((s->vmin != prevmin) || (s->vmax != prevmax)) { prevmin = s->vmin; prevmax = s->vmax; log_message("# %i..%u\n", prevmin, prevmax); } log_message("4,%s,0", s->numid); for (int i = 0; i < s->size; ++i) { int vs = 0; unsigned int vu = 0; switch (s->numtype) { default: case NUMTYPE_S: vs = *((int *)p); break; case NUMTYPE_U: vu = *((unsigned int *)p); break; case NUMTYPE_S8: vs = *((int8_t *)p); break; case NUMTYPE_U8: vu = *((uint8_t *)p); break; case NUMTYPE_S16: vs = *((int16_t *)p); break; case NUMTYPE_U16: vu = *((uint16_t *)p); break; case NUMTYPE_S32: vs = *((int32_t *)p); break; case NUMTYPE_U32: vu = *((uint32_t *)p); break; case NUMTYPE_BOOL: vs = *((bool *)p); break; } if (NUMTYPE_IS_S(s->numtype)) { log_message(",%i", vs); } else { log_message(",%u", vu); } p = ((uint8_t *)p) + s->tstep; } log_message("\n"); ++s; } } 1oom-1.11.2/src/game/game_nump.h000066400000000000000000000005571476061725400163130ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_NUMP_H #define INC_1OOM_GAME_NUMP_H #include "types.h" extern bool game_opt_fix_bugs; extern bool game_opt_fix_guardian_repair; extern bool game_opt_fix_starting_ships; extern void game_num_fix_bugs(void); extern void game_num_fix_guardian_repair(void); extern void game_num_fix_starting_ships(void); extern void game_num_dump(void); #endif 1oom-1.11.2/src/game/game_parsed.c000066400000000000000000000251411476061725400166010ustar00rootroot00000000000000#include "config.h" #include "game_parsed.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_num.h" #include "game_shipdesign.h" #include "game_shiptech.h" #include "game_tech.h" #include "game_techtypes.h" #include "lib.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define COPY_PROP(sp_, sd_, xyz_) sp_->xyz_ = sd->xyz_ #define COPY_PROP_TBL(sp_, sd_, xyz_, num_) do { for (int i_ = 0; i_ < num_; ++i_) { sp_->xyz_[i_] = sd->xyz_[i_]; } } while (0) #define COPY_MAX_SPECIAL(res_, sd_, xyz_) \ do { \ int smax_; smax_ = 0; \ for (int i_ = 0; i_ < SPECIAL_SLOT_NUM; ++i_) { \ int v_; v_ = tbl_shiptech_special[sd_->special[i_]].xyz_; \ SETMAX(smax_, v_); \ } \ res_ = smax_; \ } while (0) /* -------------------------------------------------------------------------- */ shipparsed_t tbl_monster[MONSTER_NUM][DIFFICULTY_NUM] = { { /* crystal */ { /* simple */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_BLACK_HOLE_GENERATOR, SHIP_SPECIAL_LIGHTNING_SHIELD, 0 }, { WEAPON_CRYSTAL_RAY, 0, 0, 0 }, { 10, 0, 0, 0 }, 3000, 2, 10, 1, 1, 5, 0, 100, 0, 0, 1/*num*/, 0x90, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) }, { /* easy */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_BLACK_HOLE_GENERATOR, SHIP_SPECIAL_LIGHTNING_SHIELD, 0 }, { WEAPON_CRYSTAL_RAY, 0, 0, 0 }, { 10, 0, 0, 0 }, 4000, 2, 10, 2, 2, 5, 0, 100, 0, 0, 1/*num*/, 0x90, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) }, { /* medium */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_BLACK_HOLE_GENERATOR, SHIP_SPECIAL_LIGHTNING_SHIELD, 0 }, { WEAPON_CRYSTAL_RAY, 0, 0, 0 }, { 10, 0, 0, 0 }, 5000, 2, 10, 3, 3, 5, 0, 100, 0, 0, 1/*num*/, 0x90, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) }, { /* hard */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_BLACK_HOLE_GENERATOR, SHIP_SPECIAL_LIGHTNING_SHIELD, 0 }, { WEAPON_CRYSTAL_RAY, 0, 0, 0 }, { 10, 0, 0, 0 }, 6000, 2, 10, 4, 4, 5, 0, 100, 0, 0, 1/*num*/, 0x90, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) }, { /* impossible */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_BLACK_HOLE_GENERATOR, SHIP_SPECIAL_LIGHTNING_SHIELD, 0 }, { WEAPON_CRYSTAL_RAY, 0, 0, 0 }, { 10, 0, 0, 0 }, 7000, 2, 10, 5, 5, 5, 0, 100, 0, 0, 1/*num*/, 0x90, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) } }, { /* amoeba */ { /* simple */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_NONE, 0, 0, { SHIP_SPECIAL_ADV_DAMAGE_CONTROL, 0, 0 }, { WEAPON_AMEOBA_STREAM, 0, 0, 0 }, { 1, 0, 0, 0 }, 1000, 2, 10, 1, 1, 0, 50, 0, 0, 0, 1/*num*/, 0x91, 0, 0, 0 }, { /* easy */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_NONE, 0, 0, { SHIP_SPECIAL_ADV_DAMAGE_CONTROL, 0, 0 }, { WEAPON_AMEOBA_STREAM, 0, 0, 0 }, { 1, 0, 0, 0 }, 2000, 2, 10, 2, 2, 0, 50, 0, 0, 0, 1/*num*/, 0x91, 0, 0, 0 }, { /* medium */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_NONE, 0, 0, { SHIP_SPECIAL_ADV_DAMAGE_CONTROL, 0, 0 }, { WEAPON_AMEOBA_STREAM, 0, 0, 0 }, { 1, 0, 0, 0 }, 3000, 2, 10, 3, 3, 0, 50, 0, 0, 0, 1/*num*/, 0x91, 0, 0, 0 }, { /* hard */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_NONE, 0, 0, { SHIP_SPECIAL_ADV_DAMAGE_CONTROL, 0, 0 }, { WEAPON_AMEOBA_STREAM, 0, 0, 0 }, { 1, 0, 0, 0 }, 4000, 2, 10, 4, 4, 0, 50, 0, 0, 0, 1/*num*/, 0x91, 0, 0, 0 }, { /* impossible */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, 0, SHIP_SHIELD_NONE, 0, 0, { SHIP_SPECIAL_ADV_DAMAGE_CONTROL, 0, 0 }, { WEAPON_AMEOBA_STREAM, 0, 0, 0 }, { 1, 0, 0, 0 }, 5000, 2, 10, 5, 5, 0, 50, 0, 0, 0, 1/*num*/, 0x91, 0, 0, 0 } }, { /* guardian */ { /* simple */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, SHIP_JAMMER_JAMMER_X, SHIP_SHIELD_CLASS_V, 0, 0, { SHIP_SPECIAL_HIGH_ENERGY_FOCUS, 0, SHIP_SPECIAL_LIGHTNING_SHIELD }, { WEAPON_SCATTER_PACK_X_5, WEAPON_DEATH_RAY, WEAPON_STELLAR_CONVERTER, WEAPON_PLASMA_TORPEDO }, { 5, 1, 5, 6 }, 2000, 2, 10, 1, 1, 5, 0, 100, 0, 3, 1/*num*/, 0x92, 0, 0, 0 }, { /* easy */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, SHIP_JAMMER_JAMMER_X, SHIP_SHIELD_CLASS_VI, 0, 0, { SHIP_SPECIAL_HIGH_ENERGY_FOCUS, 0, SHIP_SPECIAL_LIGHTNING_SHIELD }, { WEAPON_SCATTER_PACK_X_5, WEAPON_DEATH_RAY, WEAPON_STELLAR_CONVERTER, WEAPON_PLASMA_TORPEDO }, { 25, 1, 15, 9 }, 4000, 2, 10, 3, 3, 6, 0, 100, 0, 3, 1/*num*/, 0x92, 0, 0, 0 }, { /* medium */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, SHIP_JAMMER_JAMMER_X, SHIP_SHIELD_CLASS_VII, 0, 0, { SHIP_SPECIAL_HIGH_ENERGY_FOCUS, 0, SHIP_SPECIAL_LIGHTNING_SHIELD }, { WEAPON_SCATTER_PACK_X_5, WEAPON_DEATH_RAY, WEAPON_STELLAR_CONVERTER, WEAPON_PLASMA_TORPEDO }, { 45, 1, 25, 12 }, 6000, 2, 10, 5, 5, 7, 0, 100, 0, 3, 1/*num*/, 0x92, 0, 0, 0 }, { /* hard */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, SHIP_JAMMER_JAMMER_X, SHIP_SHIELD_CLASS_IX, 0, 0, { SHIP_SPECIAL_HIGH_ENERGY_FOCUS, SHIP_SPECIAL_ADV_DAMAGE_CONTROL, SHIP_SPECIAL_LIGHTNING_SHIELD }, { WEAPON_SCATTER_PACK_X_5, WEAPON_DEATH_RAY, WEAPON_STELLAR_CONVERTER, WEAPON_PLASMA_TORPEDO }, { 65, 1, 35, 15 }, 8000, 2, 10, 7, 7, 8, 15, 100, 0, 3, 1/*num*/, 0x92, 0, 0, 0 }, { /* impossible */ "", SHIP_HULL_HUGE, SHIP_COMP_MARK_X, SHIP_JAMMER_JAMMER_X, SHIP_SHIELD_CLASS_XI, 0, 0, { SHIP_SPECIAL_HIGH_ENERGY_FOCUS, 0, SHIP_SPECIAL_LIGHTNING_SHIELD }, { WEAPON_SCATTER_PACK_X_5, WEAPON_DEATH_RAY, WEAPON_STELLAR_CONVERTER, WEAPON_PLASMA_TORPEDO }, { 85, 1, 45, 18 }, 10000, 2, 10, 9, 9, 9, 0, 100, 0, 3, 1/*num*/, 0x92, 0, 0, 0 } } }; static uint8_t get_best_armor(const struct game_s *g, player_id_t owner) { const empiretechorbit_t *e = &(g->eto[owner]); const shipresearch_t *srd = &(g->srd[owner]); uint8_t best = 0; for (int i = 0; i <= e->tech.completed[TECH_FIELD_CONSTRUCTION]; ++i) { switch (srd->researchcompleted[TECH_FIELD_CONSTRUCTION][i]) { case TECH_CONS_DURALLOY_ARMOR: best = 1; break; case TECH_CONS_ZORTIUM_ARMOR: best = 2; break; case TECH_CONS_ANDRIUM_ARMOR: best = 3; break; case TECH_CONS_TRITANIUM_ARMOR: best = 4; break; case TECH_CONS_ADAMANTIUM_ARMOR: best = 5; break; case TECH_CONS_NEUTRONIUM_ARMOR: best = 6; break; default: break; } } return best; } /* -------------------------------------------------------------------------- */ void game_parsed_from_design(shipparsed_t *sp, const shipdesign_t *sd, int num) { uint8_t extraman; lib_strcpy(sp->name, sd->name, SHIP_NAME_LEN); COPY_PROP(sp, sd, hull); COPY_PROP(sp, sd, comp); COPY_PROP(sp, sd, jammer); COPY_PROP(sp, sd, shield); COPY_PROP(sp, sd, armor); COPY_PROP(sp, sd, engine); COPY_PROP_TBL(sp, sd, special, SPECIAL_SLOT_NUM); sp->pshield = 0; COPY_PROP_TBL(sp, sd, wpnt, WEAPON_SLOT_NUM); COPY_PROP_TBL(sp, sd, wpnn, WEAPON_SLOT_NUM); COPY_PROP(sp, sd, hp); COPY_MAX_SPECIAL(sp->repair, sd, repair); COPY_MAX_SPECIAL(extraman, sd, extraman); sp->man = (sd->man + 3) / 2 + extraman / 2; sp->complevel = tbl_shiptech_comp[sd->comp].level; sp->defense = sd->man + tbl_shiptech_hull[sd->hull].defense + extraman + 1; sp->misdefense = sp->defense + tbl_shiptech_jammer[sd->jammer].level; sp->absorb = tbl_shiptech_shield[sd->shield].absorb; COPY_MAX_SPECIAL(sp->misshield, sd, misshield); COPY_MAX_SPECIAL(sp->extrarange, sd, extrarange); sp->num = num; COPY_PROP(sp, sd, look); COPY_MAX_SPECIAL(sp->pulsar, sd, pulsar); COPY_MAX_SPECIAL(sp->stream, sd, stream); { uint16_t m = 0; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { m |= tbl_shiptech_special[sd->special[i]].boolmask; } sp->sbmask = m; if (m & (1 << SHIP_SPECIAL_BOOL_SCANNER)) { ++sp->complevel; } } } void game_parsed_from_planet(shipparsed_t *sp, const struct game_s *g, const struct planet_s *p) { const empiretechorbit_t *e = &(g->eto[p->owner]); memset(sp, 0, sizeof(*sp)); lib_strcpy(sp->name, p->name, SHIP_NAME_LEN); sp->comp = e->base_comp + 1; sp->complevel = sp->comp; if (e->race == RACE_MRRSHAN) { sp->complevel += 4; } sp->shield = e->base_shield; sp->absorb = tbl_shiptech_shield[e->base_shield].absorb; sp->hp = game_num_base_hp[get_best_armor(g, p->owner)]; sp->defense = 1; sp->misdefense = game_get_best_jammer(g, p->owner, e->tech.percent[TECH_FIELD_COMPUTER]) + 1; if (p->missile_bases > 0) { uint16_t m = (1 << SHIP_SPECIAL_BOOL_SCANNER); sp->num = p->missile_bases; if (e->have_sub_space_int) { m |= (1 << SHIP_SPECIAL_BOOL_SUBSPACE); } sp->sbmask = m; } sp->pulsar = e->antidote; /* HACK */ sp->look = p->infogfx; sp->pshield = p->shield; sp->wpnt[0] = e->base_weapon; sp->wpnn[0] = 3; sp->wpnt[1] = game_get_base_weapon_2(g, p->owner, e->tech.percent[TECH_FIELD_WEAPON], e->base_weapon); sp->wpnn[1] = 3; if (p->battlebg == 0) { sp->pshield = 0; sp->absorb = 0; sp->shield = 0; } } 1oom-1.11.2/src/game/game_parsed.h000066400000000000000000000023131476061725400166020ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_PARSED_H #define INC_1OOM_GAME_PARSED_H #include "game_shipdesign.h" #include "game_shiptech.h" #include "game_types.h" #include "types.h" typedef struct shipparsed_s { char name[SHIP_NAME_LEN]; ship_hull_t hull; ship_comp_t comp; ship_jammer_t jammer; ship_shield_t shield; ship_armor_t armor; ship_engine_t engine; ship_special_t special[SPECIAL_SLOT_NUM]; weapon_t wpnt[WEAPON_SLOT_NUM]; /* weapon type */ uint8_t wpnn[WEAPON_SLOT_NUM]; /* weapon num */ uint16_t hp; /* hit points */ uint8_t man; /* maneuverability */ uint8_t complevel; uint8_t defense; uint8_t misdefense; uint8_t absorb; uint8_t repair; uint8_t misshield; uint8_t pshield; uint8_t extrarange; shipcount_t num; uint8_t look; uint8_t pulsar; /* also antidote for planets */ uint8_t stream; uint16_t sbmask; } shipparsed_t; struct game_s; struct planet_s; extern void game_parsed_from_design(shipparsed_t *sp, const shipdesign_t *sd, int num); extern void game_parsed_from_planet(shipparsed_t *sp, const struct game_s *g, const struct planet_s *p); extern shipparsed_t tbl_monster[MONSTER_NUM][DIFFICULTY_NUM]; #endif 1oom-1.11.2/src/game/game_planet.c000066400000000000000000000474551476061725400166220ustar00rootroot00000000000000#include "config.h" #include #include #include "game_planet.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "rnd.h" #include "types.h" /* -------------------------------------------------------------------------- */ static void tenths_2str(struct strbuild_s *str, int num) { strbuild_catf(str, "%i", num / 10); if ((num < 100) && ((num % 10) != 0)) { strbuild_catf(str, ".%i", num % 10); } } /* -------------------------------------------------------------------------- */ void game_planet_destroy(struct game_s *g, uint8_t planet_i, player_id_t attacker) { planet_t *p = &(g->planet[planet_i]); player_id_t owner = p->owner; if (IS_PLAYER(g, owner)) { /* g->seen is not used by classical AI, so the original skips this for AI. */ g->seen[owner][planet_i].owner = PLAYER_NONE; g->seen[owner][planet_i].pop = 0; g->seen[owner][planet_i].bases = 0; g->seen[owner][planet_i].factories = 0; } if (IS_HUMAN(g, owner)) { /* WASBUG there was an unreliable mess here */ g->gaux->human_killer = attacker; } p->rebels = 0; p->unrest = 0; p->reserve = 0; p->prev_owner = owner; p->owner = PLAYER_NONE; p->bc_to_ecoproj = 0; p->pop = 0; p->pop_prev = 0; p->prod_after_maint = 0; p->bc_to_ship = 0; for (int i = 0; i < PLAYER_NUM; ++i) { p->inbound[i] = 0; } p->buildship = 0; for (int i = 0; i < PLANET_SLIDER_NUM; ++i) { p->slider[i] = 0; p->slider_lock[i] = 0; } p->slider[PLANET_SLIDER_IND] = 100; p->reloc = planet_i; p->missile_bases = 0; p->bc_upgrade_base = 0; p->bc_to_base = 0; p->trans_num = 0; p->bc_to_ship = 0; p->bc_to_factory = 0; p->have_stargate = false; p->shield = 0; p->bc_to_shield = 0; BOOLVEC_CLEAR(p->finished, FINISHED_NUM); if (game_num_extended_reloc_range) { return; } for (int i = 0; i < g->galaxy_stars; ++i) { p = &(g->planet[i]); if (p->reloc == planet_i) { p->reloc = i; } } } uint8_t game_planet_get_random(struct game_s *g, player_id_t owner) { uint8_t tbl[PLANETS_MAX]; int num = 0; for (int i = 0; i < g->galaxy_stars; ++i) { if (g->planet[i].owner == owner) { tbl[num++] = i; } } if (num == 0) { return PLANET_NONE; } else { return tbl[rnd_0_nm1(num, &g->seed)]; } } void game_planet_adjust_percent2(struct game_s *g, uint8_t planet_i, planet_slider_i_t si, uint8_t percent, bool respect_locks) { planet_t *p = &(g->planet[planet_i]); if (respect_locks && p->slider_lock[si]) return; for (planet_slider_i_t j = 0; j < PLANET_SLIDER_NUM; ++j) { if (respect_locks && p->slider_lock[j]) continue; if (si == j) continue; int diff = 0; if (j == PLANET_SLIDER_ECO) { int w = game_planet_get_waste_percent(NULL, g, p, true); if (w < p->slider[j]) { diff = (p->slider[j] - w) * percent / 100; } } else { diff = (p->slider[j] * percent) / 100; } p->slider[si] += diff; p->slider[j] -= diff; } } void game_planet_adjust_percent(struct game_s *g, player_id_t owner, planet_slider_i_t si, uint8_t percent, int growth) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == owner) { if (0 || (growth == 0) || ((growth == 1) && (p->growth > PLANET_GROWTH_HOSTILE)) || ((growth == 2) && (p->growth == PLANET_GROWTH_HOSTILE)) ) { int sum, slider_increase; /* Summing up all sliders except for the one that is going to be increased * and ECO, because ECO is set to the minimum for waste cleanup before this * function is called. SHIP and TECH are never increased in this function. */ sum = p->slider[PLANET_SLIDER_SHIP] + p->slider[PLANET_SLIDER_TECH]; if (si != PLANET_SLIDER_DEF) { sum += p->slider[PLANET_SLIDER_DEF]; } if (si != PLANET_SLIDER_IND) { sum += p->slider[PLANET_SLIDER_IND]; } if (game_num_newtech_adjust_fix && (si != PLANET_SLIDER_ECO)) { int eco = p->slider[PLANET_SLIDER_ECO] - game_planet_get_waste_percent(NULL, g, p, false); SETMAX(eco, 0); sum += eco; p->slider[PLANET_SLIDER_ECO] -= (eco * percent) / 100; } slider_increase = (sum * percent) / 100; p->slider[PLANET_SLIDER_SHIP] = (p->slider[PLANET_SLIDER_SHIP] * (100 - percent)) / 100; if (si == PLANET_SLIDER_DEF) { p->slider[PLANET_SLIDER_DEF] += slider_increase; } else { p->slider[PLANET_SLIDER_DEF] = (p->slider[PLANET_SLIDER_DEF] * (100 - percent)) / 100; } if (si == PLANET_SLIDER_IND) { p->slider[PLANET_SLIDER_IND] += slider_increase; } else { p->slider[PLANET_SLIDER_IND] = (p->slider[PLANET_SLIDER_IND] * (100 - percent)) / 100; } if (si == PLANET_SLIDER_ECO) { p->slider[PLANET_SLIDER_ECO] += slider_increase; } p->slider[PLANET_SLIDER_TECH] = 100 - p->slider[PLANET_SLIDER_SHIP] - p->slider[PLANET_SLIDER_ECO] - p->slider[PLANET_SLIDER_DEF] - p->slider[PLANET_SLIDER_IND]; SETMAX(p->slider[PLANET_SLIDER_TECH], 0); } } } } int game_planet_get_waste_percent(int *r_waste, const struct game_s *g, const planet_t *p, bool subtract_transports) { const empiretechorbit_t *e; int w, fact, waste, prod, pop; if (p->owner == PLAYER_NONE) { return 0; } e = &(g->eto[p->owner]); fact = p->factories; pop = p->pop; if (subtract_transports) { pop -= p->trans_num; } SETMIN(fact, pop * game_planet_get_pop_oper_fact(g, p)); waste = (e->race == RACE_SILICOID) ? 0 : (((fact * e->ind_waste_scale) / 10 + p->waste) / e->have_eco_restoration_n); prod = p->prod_after_maint; if (prod == 0) { prod = 1000; } w = ((waste * 100) + prod - 1) / prod; SETRANGE(w, 0, 100); if (r_waste != NULL) { *r_waste = waste; } return w; } bool game_planet_can_terraform(const struct game_s *g, const planet_t *p, player_id_t active_player, bool soilatmos) { const empiretechorbit_t *e = &(g->eto[active_player]); if (soilatmos) { if (e->have_atmos_terra && (p->growth == PLANET_GROWTH_HOSTILE)) { return true; } if (e->have_soil_enrich && (p->growth == PLANET_GROWTH_NORMAL)) { return true; } if (e->have_adv_soil_enrich && ((p->growth == PLANET_GROWTH_NORMAL) || (p->growth == PLANET_GROWTH_FERTILE))) { return true; } } return ((p->max_pop2 + e->have_terraform_n) > p->max_pop3) && (p->max_pop3 < game_num_max_pop); } void game_planet_update_home(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); player_id_t pi; pi = p->owner; if ((pi != PLAYER_NONE) && (g->evn.home[pi] == PLANET_NONE)) { g->evn.home[pi] = i; /* WASBUG? MOO1 sets to 0 which affects rebellion event check */ } } } const char *game_planet_get_finished_text(const struct game_s *g, const planet_t *p, planet_finished_t type, char *buf, size_t bufsize) { int num; switch (type) { case FINISHED_FACT: num = p->max_pop3 * g->eto[p->owner].colonist_oper_factories; lib_sprintf(buf, bufsize, "%s %s %s %i %s. %s", p->name, game_str_sm_hasreached, game_str_sm_indmaxof, num, game_str_sm_factories, game_str_sm_extrares); break; case FINISHED_POPMAX: num = p->max_pop3; lib_sprintf(buf, bufsize, "%s %s %s %i %s. %s", p->name, game_str_sm_hasreached, game_str_sm_popmaxof, num, game_str_sm_colonists, game_str_sm_extrares); break; case FINISHED_SOILATMOS: lib_sprintf(buf, bufsize, "%s %s %s %s %s%s.", p->name, game_str_sm_hasterraf, game_str_tbl_sm_terraf[p->growth - 1], game_str_sm_envwith, game_str_tbl_sm_envmore[p->growth - 1], game_str_sm_stdgrow); break; case FINISHED_STARGATE: lib_sprintf(buf, bufsize, "%s %s.", p->name, game_str_sm_hasfsgate); break; case FINISHED_SHIELD: lib_sprintf(buf, bufsize, "%s %s %s %s.", p->name, game_str_sm_hasfshield, game_str_tbl_roman[p->shield], game_str_sm_planshield); break; default: lib_sprintf(buf, bufsize, "BUG: invalid finished tyoe %i at '%s'", type, p->name); break; } return buf; } int game_planet_get_slider_text(const struct game_s *g, const planet_t *p, planet_slider_i_t si, char *buf, size_t bufsize) { player_id_t player = p->owner; const empiretechorbit_t *e = &(g->eto[player]); int retval = -1; switch (si) { case PLANET_SLIDER_SHIP: { int vthis, vtotal, cost; vthis = game_adjust_prod_by_special((p->prod_after_maint * p->slider[PLANET_SLIDER_SHIP]) / 100, p->special); vtotal = vthis + p->bc_to_ship; if (p->buildship == BUILDSHIP_STARGATE) { cost = game_num_stargate_cost; } else { cost = g->srd[player].design[p->buildship].cost; } if ((vtotal < cost) || (p->buildship == BUILDSHIP_STARGATE)) { if (vthis < 1) { lib_strcpy(buf, game_str_sm_prodnone, bufsize); retval = 0; } else { int num = 0, over; over = cost - p->bc_to_ship; while (over > 0) { over -= vthis; ++num; } SETMAX(num, 1); lib_sprintf(buf, bufsize, "%i %s", num, game_str_sm_prod_y); if (p->buildship != BUILDSHIP_STARGATE) { retval = 1; } } } else { int num; /* TODO this adjusted sd->cost directly! */ SETMAX(cost, 1); num = vtotal / cost; lib_sprintf(buf, bufsize, "1 %s", game_str_sm_prod_y); retval = num; } } break; case PLANET_SLIDER_DEF: { int vthis, vtotal, cost, v8, va; cost = game_get_base_cost(g, player); vthis = game_adjust_prod_by_special((p->prod_after_maint * p->slider[PLANET_SLIDER_DEF]) / 100, p->special); vtotal = vthis + p->bc_to_base; v8 = p->bc_upgrade_base; if (vthis == 0) { lib_strcpy(buf, game_str_sm_prodnone, bufsize); } else if (vtotal <= v8) { lib_strcpy(buf, game_str_sm_defupg, bufsize); } else { vtotal -= v8; SETMAX(vtotal, 0); va = e->planet_shield_cost - p->bc_to_shield; if (p->battlebg == 0) { va = 0; } SETMAX(va, 0); if (vtotal <= va) { lib_strcpy(buf, game_str_sm_defshld, bufsize); } else { int num, over; vtotal -= va; SETMAX(vtotal, 0); if ((cost * 2) > vtotal) { num = 1; over = cost - vtotal; while (over > 0) { over -= vthis; ++num; } lib_sprintf(buf, bufsize, "%i %s", num, game_str_sm_prod_y); } else { num = vtotal / cost; lib_sprintf(buf, bufsize, "%i/%s", num, game_str_sm_prod_y); } } } } break; case PLANET_SLIDER_IND: { const char *str = NULL; int vthis, cost; cost = game_planet_get_fact_adj_cost(g, p); vthis = game_adjust_prod_by_special((p->prod_after_maint * p->slider[PLANET_SLIDER_IND]) / 100, p->special); if (vthis != 0) { int v20; v20 = (vthis * 10) / cost; if ((v20 / 10 + p->factories) >= ((p->pop - p->trans_num) * p->pop_oper_fact)) { if (p->pop_oper_fact < e->colonist_oper_factories) { if (e->race != RACE_MEKLAR) { str = game_str_sm_refit; if (game_num_factory_cost_fix) { /* FIXME: Doesn't always match the result */ str = game_str_sm_irc[p->pop_oper_fact - 1]; } } else { struct strbuild_s strbuild = strbuild_init(buf, bufsize); tenths_2str(&strbuild, v20); strbuild_catf(&strbuild, "/%s", game_str_sm_prod_y); } } else { str = game_str_sm_indres; if (p->factories < (p->max_pop3 * e->colonist_oper_factories)) { str = game_str_sm_indmax; } } } else { struct strbuild_s strbuild = strbuild_init(buf, bufsize); tenths_2str(&strbuild, v20); strbuild_catf(&strbuild, "/%s", game_str_sm_prod_y); } } else { str = game_str_sm_prodnone; } if (str) { lib_strcpy(buf, str, bufsize); } } break; case PLANET_SLIDER_ECO: retval = game_planet_get_slider_text_eco(g, p, false, buf, bufsize); break; case PLANET_SLIDER_TECH: { int v = game_get_tech_prod(p->prod_after_maint, p->slider[PLANET_SLIDER_TECH], e->race, p->special); lib_sprintf(buf, bufsize, "%i", v); retval = v; } break; default: *buf = '\0'; break; } return retval; } int game_planet_get_slider_text_eco(const struct game_s *g, const planet_t *p, bool flag_tenths, char *buf, size_t bufsize) { player_id_t player = p->owner; const empiretechorbit_t *e = &(g->eto[player]); int retval = -1; const char *str = NULL; int vthis, adjwaste = 0, tform_cost; bool flag_ecoproj = false; vthis = (p->prod_after_maint * p->slider[PLANET_SLIDER_ECO]) / 100; game_planet_get_waste_percent(&adjwaste, g, p, true); if ((vthis < adjwaste) || (vthis == 0)) { str = (vthis < adjwaste) ? game_str_sm_ecowaste : game_str_sm_prodnone; } else { SUBSAT0(vthis, adjwaste); if ((vthis > 0) && e->have_atmos_terra && (p->growth == PLANET_GROWTH_HOSTILE)) { vthis -= game_num_atmos_cost - p->bc_to_ecoproj; if (vthis < 0) { flag_ecoproj = true; str = game_str_sm_ecoatmos; } } if ((vthis > 0) && e->have_soil_enrich && (p->growth == PLANET_GROWTH_NORMAL)) { vthis -= game_num_soil_cost - p->bc_to_ecoproj; if (vthis < 0) { flag_ecoproj = true; str = game_str_sm_ecosoil; } } if ((vthis > 0) && e->have_adv_soil_enrich && ((p->growth == PLANET_GROWTH_NORMAL) || (p->growth == PLANET_GROWTH_FERTILE))) { vthis -= game_num_adv_soil_cost - p->bc_to_ecoproj; if (vthis < 0) { flag_ecoproj = true; str = game_str_sm_ecogaia; } } if (vthis > 0) { if (p->max_pop3 < game_num_max_pop) { /* WASBUG In MOO 1.3, if you conquered a planet from a race * with more advanced terraforming than you, a negative * terraforming cost would be calculated here. This affected * the displayed pop growth estimate but not actual growth. */ tform_cost = (p->max_pop2 + (e->have_terraform_n - p->max_pop3)) * e->terraform_cost_per_inc; SETMAX(tform_cost, 0); } else { tform_cost = 0; } if (vthis < tform_cost) { str = game_str_sm_ecotform; } else { int growth, growth2, max_pop; bool max = false; bool flag_tform = false; max_pop = p->max_pop3; if (tform_cost > 0) { if (vthis < tform_cost) { flag_tform = true; } else if (flag_tenths) { /* keep same +N as MOO1 for developing planets on -nouiextra */ max_pop = p->max_pop2 + e->have_terraform_n; } } vthis -= tform_cost; growth = game_get_pop_growth_max(g, p, max_pop) + p->pop_tenths; if (!flag_tenths) { if (((p->pop - p->trans_num) + (growth / 10)) > max_pop) { growth = (max_pop - (p->pop - p->trans_num)) * 10; } growth2 = game_get_pop_growth_for_eco(g, p, vthis) + growth; if (((p->pop - p->trans_num) + (growth2 / 10)) > max_pop) { growth2 = (max_pop - (p->pop - p->trans_num)) * 10; } growth = growth2 / 10 - growth / 10; } else { if (((p->pop - p->trans_num) * 10 + growth) > (max_pop * 10)) { growth = (max_pop - (p->pop - p->trans_num)) * 10; if (!game_num_pop_tenths_fix) { growth += p->pop_tenths; } } growth2 = game_get_pop_growth_for_eco(g, p, vthis) + growth; if (((p->pop - p->trans_num) * 10 + growth2) >= (max_pop * 10)) { growth2 = (max_pop - (p->pop - p->trans_num)) * 10; if (!game_num_pop_tenths_fix) { growth2 += p->pop_tenths; } max = (growth != growth2); } growth = growth2 - growth; } if (growth <= 0) { str = flag_tform ? game_str_sm_ecotform : game_str_sm_ecoclean; } else if (max) { str = game_str_sm_max; } else { retval = growth; str = game_str_sm_ecopop; } } } else { if ((flag_ecoproj == false) && (e->race != RACE_SILICOID)) { str = game_str_sm_ecoclean; } } } if (str) { lib_strcpy(buf, str, bufsize); } return retval; } 1oom-1.11.2/src/game/game_planet.h000066400000000000000000000124711476061725400166150ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_PLANET_H #define INC_1OOM_GAME_PLANET_H #include "boolvec.h" #include "game_types.h" #include "types.h" typedef enum planet_type_e { PLANET_TYPE_NOT_HABITABLE = 0, PLANET_TYPE_RADIATED, /*1*/ PLANET_TYPE_TOXIC, /*2*/ PLANET_TYPE_INFERNO, /*3*/ PLANET_TYPE_DEAD, /*4*/ PLANET_TYPE_TUNDRA, /*5*/ PLANET_TYPE_BARREN, /*6*/ PLANET_TYPE_MINIMAL, /*7*/ PLANET_TYPE_DESERT, /*8*/ PLANET_TYPE_STEPPE, /*9*/ PLANET_TYPE_ARID, /*a*/ PLANET_TYPE_OCEAN, /*b*/ PLANET_TYPE_JUNGLE, /*c*/ PLANET_TYPE_TERRAN, /*d*/ PLANET_TYPE_NUM } planet_type_t; typedef enum planet_growth_e { PLANET_GROWTH_HOSTILE = 0, PLANET_GROWTH_NORMAL, /*1*/ PLANET_GROWTH_FERTILE, /*2*/ PLANET_GROWTH_GAIA, /*3*/ PLANET_GROWTH_NUM } planet_growth_t; typedef enum planet_special_e { PLANET_SPECIAL_ULTRA_POOR = 0, PLANET_SPECIAL_POOR, /*1*/ PLANET_SPECIAL_NORMAL, /*2*/ PLANET_SPECIAL_ARTIFACTS, /*3*/ PLANET_SPECIAL_RICH, /*4*/ PLANET_SPECIAL_ULTRA_RICH, /*5*/ PLANET_SPECIAL_4XTECH, /*6*/ PLANET_SPECIAL_NUM } planet_special_t; typedef enum { PLANET_SLIDER_SHIP = 0, PLANET_SLIDER_DEF, /*1*/ PLANET_SLIDER_IND, /*2*/ PLANET_SLIDER_ECO, /*3*/ PLANET_SLIDER_TECH, /*4*/ PLANET_SLIDER_NUM } planet_slider_i_t; typedef enum { PLANET_UNREST_NORMAL = 0, PLANET_UNREST_UNREST, /*1*/ PLANET_UNREST_HMM2, /*2*/ PLANET_UNREST_REBELLION, /*3*/ PLANET_UNREST_RESOLVED /*4*/ } planet_unrest_t; typedef enum { STAR_TYPE_YELLOW = 0, STAR_TYPE_RED, /*1*/ STAR_TYPE_GREEN, /*2*/ STAR_TYPE_WHITE, /*3*/ STAR_TYPE_BLUE, /*4*/ STAR_TYPE_NEUTRON, /*5*/ STAR_TYPE_NUM /*6*/ } star_type_t; typedef enum { PLANET_ROCKS_NONE = 0, PLANET_ROCKS_SOME, /*1*/ PLANET_ROCKS_MANY /*2*/ } planet_rocks_t; typedef enum { FINISHED_FACT, /*0*/ FINISHED_POPMAX, /*1*/ FINISHED_SOILATMOS, /*2*/ FINISHED_STARGATE, /*3*/ FINISHED_SHIELD, /*4*/ FINISHED_SHIP, /*5*/ FINISHED_NUM } planet_finished_t; #define PLANET_NAME_LEN 12 typedef struct planet_s { char name[PLANET_NAME_LEN]; uint16_t x; uint16_t y; star_type_t star_type; uint8_t look; /* 0, 6 */ uint8_t frame; /* 0..49 */ planet_rocks_t rocks; int16_t max_pop1; /* Base size */ int16_t max_pop2; /* Size adjusted by soil enrichment tech */ int16_t max_pop3; /* Maximum population */ planet_type_t type; uint8_t battlebg; /* 0..4 ; 0 implies planet is in nebula */ uint8_t infogfx; /* index to planets.lbx */ planet_growth_t growth; planet_special_t special; int16_t bc_to_ecoproj; uint16_t bc_to_ship; uint8_t bc_to_factory; uint32_t reserve; int16_t waste; player_id_t owner; player_id_t prev_owner; player_id_t claim; int16_t pop; int16_t pop_prev; int16_t factories; uint16_t prod_after_maint; uint16_t total_prod; int16_t slider[PLANET_SLIDER_NUM]; /* FIXME? could be int8_t but uiobj uses uint16_t */ uint16_t slider_lock[PLANET_SLIDER_NUM]; /* FIXME should be boolvec but uiobj uses uint16_t */ uint8_t buildship; /* 0..NUM_SHIPDESIGNS-1 or BUILDSHIP_STARGATE */ uint8_t reloc; /* planet i to relocate produced ships (== planet's own index if no relocation) */ uint16_t missile_bases; uint16_t bc_to_base; uint16_t bc_upgrade_base; bool have_stargate; uint8_t shield; /* 0, 10, 15, 20 */ uint16_t bc_to_shield; uint16_t trans_num; uint8_t trans_dest; int8_t pop_tenths; BOOLVEC_DECLARE(explored, PLAYER_NUM); BOOLVEC_DECLARE(within_srange, PLAYER_NUM); /* scanner range covers planet */ uint8_t within_frange[PLAYER_NUM]; /* fuel range reaches planet: 0=no, 1=yes, 2=with reserve fuel */ uint8_t pop_oper_fact; uint16_t bc_to_refit; int16_t rebels; planet_unrest_t unrest; bool unrest_reported; BOOLVEC_DECLARE(unrefuel, PLAYER_NUM); BOOLVEC_DECLARE(finished, FINISHED_NUM); /* remaining variables used only during game_turn_process */ uint16_t inbound[PLAYER_NUM]; uint16_t total_inbound[PLAYER_NUM]; player_id_t artifact_looter; } planet_t; #define PLANET_NONE 255 struct game_s; extern void game_planet_destroy(struct game_s *g, uint8_t planet_i, player_id_t attacker); extern uint8_t game_planet_get_random(struct game_s *g, player_id_t owner); extern void game_planet_adjust_percent2(struct game_s *g, uint8_t planet_i, planet_slider_i_t si, uint8_t percent, bool respect_locks); extern void game_planet_adjust_percent(struct game_s *g, player_id_t owner, planet_slider_i_t si, uint8_t percent, int growth); extern int game_planet_get_waste_percent(int *r_waste, const struct game_s *g, const planet_t *p, bool subtract_transports); extern bool game_planet_can_terraform(const struct game_s *g, const planet_t *p, player_id_t active_player, bool soilatmos); extern void game_planet_update_home(struct game_s *g); extern const char *game_planet_get_finished_text(const struct game_s *g, const planet_t *p, planet_finished_t type, char *buf, size_t bufsize); extern int game_planet_get_slider_text(const struct game_s *g, const planet_t *p, planet_slider_i_t si, char *buf, size_t bufsize); extern int game_planet_get_slider_text_eco(const struct game_s *g, const planet_t *p, bool flag_tenths, char *buf, size_t bufsize); #endif 1oom-1.11.2/src/game/game_save.c000066400000000000000000001121471476061725400162640ustar00rootroot00000000000000/* NOTE! If the save format changes, increase GAME_SAVE_VERSION and implement a converter in 1oom_saveconv. The format is not to be changed without a very good reason. */ #include "config.h" #include #include #include #include "game_nebula.h" #include "game_save.h" #include "bits.h" #include "game.h" #include "game_aux.h" #include "game_endecode.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define GAME_SAVE_HDR_SIZE 64 #define GAME_SAVE_MAGIC "1oomSAVE" #define GAME_SAVE_END 0x646e450a/*dnE\n*/ #define GAME_SAVE_OFFS_VERSION 8 #define GAME_SAVE_OFFS_NAME 16 #define GAME_SAVE_VERSION 0 /* -------------------------------------------------------------------------- */ bool game_save_tbl_have_save[NUM_ALL_SAVES]; char game_save_tbl_name[NUM_ALL_SAVES][SAVE_NAME_LEN]; /* -------------------------------------------------------------------------- */ /* * HACK: Nebula types are not stored in the save file format, but can be inferred * from the bounding boxes. */ static bool game_save_nebula_match(uint16_t x, uint16_t y, const uint16_t *x0, const uint16_t *y0, const uint16_t *x1, const uint16_t *y1, const uint8_t nebula_data[4][4]) { for (int i = 0; i < 4; ++i) { if (x0[i] != x + nebula_data[0][i]) { return false; } if (y0[i] != y + nebula_data[1][i]) { return false; } if (x1[i] != x + nebula_data[2][i]) { return false; } if (y1[i] != y + nebula_data[3][i]) { return false; } } return true; } static int game_save_infer_nebula_type(const struct game_s *g, uint32_t index) { uint16_t x = g->nebula_x[index]; uint16_t y = g->nebula_y[index]; const uint16_t *x0 = g->nebula_x0[index]; const uint16_t *y0 = g->nebula_y0[index]; const uint16_t *x1 = g->nebula_x1[index]; const uint16_t *y1 = g->nebula_y1[index]; for (int t = 0; t < NEBULA_TYPE_NUM; ++t) { if (game_save_nebula_match(x, y, x0, y0, x1, y1, tbl_nebula_data[t])) { return t; } } return -1; } static int game_save_encode_planet(uint8_t *buf, int pos, const planet_t *p, int pnum, uint32_t version) { SG_1OOM_EN_TBL_U8(p->name, PLANET_NAME_LEN); SG_1OOM_EN_U16(p->x); SG_1OOM_EN_U16(p->y); SG_1OOM_EN_U8(p->star_type); SG_1OOM_EN_U8(p->look); SG_1OOM_EN_U8(p->frame); SG_1OOM_EN_U8(p->rocks); SG_1OOM_EN_U16(p->max_pop1); SG_1OOM_EN_U16(p->max_pop2); SG_1OOM_EN_U16(p->max_pop3); SG_1OOM_EN_U8(p->type); SG_1OOM_EN_U8(p->battlebg); SG_1OOM_EN_U8(p->infogfx); SG_1OOM_EN_U8(p->growth); SG_1OOM_EN_U8(p->special); SG_1OOM_EN_U16(p->bc_to_ecoproj); SG_1OOM_EN_U16(p->bc_to_ship); SG_1OOM_EN_U16(p->bc_to_factory); SG_1OOM_EN_U32(p->reserve); SG_1OOM_EN_U16(p->waste); SG_1OOM_EN_U8(p->owner); SG_1OOM_EN_U8(p->prev_owner); SG_1OOM_EN_U8(p->claim); SG_1OOM_EN_U16(p->pop); SG_1OOM_EN_U16(p->pop_prev); SG_1OOM_EN_U16(p->factories); SG_1OOM_EN_TBL_U16(p->slider, PLANET_SLIDER_NUM); SG_1OOM_EN_TBL_U8(p->slider_lock, PLANET_SLIDER_NUM); SG_1OOM_EN_U8(p->buildship); SG_1OOM_EN_U8(p->reloc); SG_1OOM_EN_U16(p->missile_bases); SG_1OOM_EN_U16(p->bc_to_base); SG_1OOM_EN_U16(p->bc_upgrade_base); SG_1OOM_EN_U8(p->have_stargate); SG_1OOM_EN_U8(p->shield); SG_1OOM_EN_U16(p->bc_to_shield); SG_1OOM_EN_U16(p->trans_num); SG_1OOM_EN_U8(p->trans_dest); SG_1OOM_EN_U8(p->pop_tenths); SG_1OOM_EN_BV(p->explored, PLAYER_NUM); SG_1OOM_EN_BV(p->unrefuel, PLAYER_NUM); SG_1OOM_EN_DUMMY(4); SG_1OOM_EN_U8(p->pop_oper_fact); SG_1OOM_EN_U16(p->bc_to_refit); SG_1OOM_EN_U16(p->rebels); SG_1OOM_EN_U8(p->unrest); SG_1OOM_EN_U8(p->unrest_reported); SG_1OOM_EN_BV(p->finished, FINISHED_NUM); SG_1OOM_EN_DUMMY(5); return pos; } static int game_save_decode_planet(const uint8_t *buf, int pos, planet_t *p, int pnum, uint32_t version) { SG_1OOM_DE_TBL_U8(p->name, PLANET_NAME_LEN); SG_1OOM_DE_U16(p->x); SG_1OOM_DE_U16(p->y); SG_1OOM_DE_U8(p->star_type); SG_1OOM_DE_U8(p->look); SG_1OOM_DE_U8(p->frame); SG_1OOM_DE_U8(p->rocks); SG_1OOM_DE_U16(p->max_pop1); SG_1OOM_DE_U16(p->max_pop2); SG_1OOM_DE_U16(p->max_pop3); SG_1OOM_DE_U8(p->type); SG_1OOM_DE_U8(p->battlebg); SG_1OOM_DE_U8(p->infogfx); SG_1OOM_DE_U8(p->growth); SG_1OOM_DE_U8(p->special); SG_1OOM_DE_U16(p->bc_to_ecoproj); SG_1OOM_DE_U16(p->bc_to_ship); SG_1OOM_DE_U16(p->bc_to_factory); SG_1OOM_DE_U32(p->reserve); SG_1OOM_DE_U16(p->waste); SG_1OOM_DE_U8(p->owner); SG_1OOM_DE_U8(p->prev_owner); SG_1OOM_DE_U8(p->claim); SG_1OOM_DE_U16(p->pop); SG_1OOM_DE_U16(p->pop_prev); SG_1OOM_DE_U16(p->factories); SG_1OOM_DE_TBL_U16(p->slider, PLANET_SLIDER_NUM); SG_1OOM_DE_TBL_U8(p->slider_lock, PLANET_SLIDER_NUM); SG_1OOM_DE_U8(p->buildship); SG_1OOM_DE_U8(p->reloc); SG_1OOM_DE_U16(p->missile_bases); SG_1OOM_DE_U16(p->bc_to_base); SG_1OOM_DE_U16(p->bc_upgrade_base); SG_1OOM_DE_U8(p->have_stargate); SG_1OOM_DE_U8(p->shield); SG_1OOM_DE_U16(p->bc_to_shield); SG_1OOM_DE_U16(p->trans_num); SG_1OOM_DE_U8(p->trans_dest); SG_1OOM_DE_U8(p->pop_tenths); SG_1OOM_DE_BV(p->explored, PLAYER_NUM); SG_1OOM_DE_BV(p->unrefuel, PLAYER_NUM); SG_1OOM_DE_DUMMY(4); SG_1OOM_DE_U8(p->pop_oper_fact); SG_1OOM_DE_U16(p->bc_to_refit); SG_1OOM_DE_U16(p->rebels); SG_1OOM_DE_U8(p->unrest); SG_1OOM_DE_U8(p->unrest_reported); SG_1OOM_DE_BV(p->finished, FINISHED_NUM); SG_1OOM_DE_DUMMY(5); return pos; } static int game_save_encode_enroute(uint8_t *buf, int pos, const fleet_enroute_t *r) { SG_1OOM_EN_U8(r->owner); SG_1OOM_EN_U16(r->x); SG_1OOM_EN_U16(r->y); SG_1OOM_EN_U8(r->dest); { uint8_t v = r->speed; if (r->retreat) { v |= 0x80; } SG_1OOM_EN_U8(v); } SG_1OOM_EN_TBL_U16(r->ships, NUM_SHIPDESIGNS); return pos; } static int game_save_decode_enroute(const uint8_t *buf, int pos, fleet_enroute_t *r) { SG_1OOM_DE_U8(r->owner); SG_1OOM_DE_U16(r->x); SG_1OOM_DE_U16(r->y); SG_1OOM_DE_U8(r->dest); { uint8_t v; SG_1OOM_DE_U8(v); r->speed = v & 0x7f; r->retreat = ((v & 0x80) != 0); } SG_1OOM_DE_TBL_U16(r->ships, NUM_SHIPDESIGNS); return pos; } static int game_save_encode_transport(uint8_t *buf, int pos, const transport_t *r) { SG_1OOM_EN_U8(r->owner); SG_1OOM_EN_U16(r->x); SG_1OOM_EN_U16(r->y); SG_1OOM_EN_U8(r->dest); SG_1OOM_EN_U8(r->speed); SG_1OOM_EN_U16(r->pop); return pos; } static int game_save_decode_transport(const uint8_t *buf, int pos, transport_t *r) { SG_1OOM_DE_U8(r->owner); SG_1OOM_DE_U16(r->x); SG_1OOM_DE_U16(r->y); SG_1OOM_DE_U8(r->dest); SG_1OOM_DE_U8(r->speed); SG_1OOM_DE_U16(r->pop); return pos; } static int game_save_encode_orbits(uint8_t *buf, int pos, const fleet_orbit_t *o, int planets) { for (uint8_t i = 0; i < planets; ++i) { bool any_ships; any_ships = false; for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { if (o[i].ships[j] != 0) { any_ships = true; break; } } if (any_ships) { SG_1OOM_EN_U8(i); SG_1OOM_EN_TBL_U16(o[i].ships, NUM_SHIPDESIGNS); } } SG_1OOM_EN_U8(PLANET_NONE); return pos; } static int game_save_decode_orbits(const uint8_t *buf, int pos, fleet_orbit_t *o, int planets) { for (int loops = 0; loops <= planets; ++loops) { uint8_t i; SG_1OOM_DE_U8(i); if (i == PLANET_NONE) { return pos; } else if (i >= planets) { log_error("Save: decode orbit planet %i >= %i max\n", i, planets); return -1; } SG_1OOM_DE_TBL_U16(o[i].ships, NUM_SHIPDESIGNS); } log_error("Save: decode orbit terminator missing\n"); return -1; } static int game_save_encode_eto(uint8_t *buf, int pos, const empiretechorbit_t *e, int pnum, int planets, uint32_t version) { SG_1OOM_EN_U8(e->race); SG_1OOM_EN_U8(e->banner); SG_1OOM_EN_U8(e->trait1); SG_1OOM_EN_U8(e->trait2); SG_1OOM_EN_U8(e->ai_p3_countdown); SG_1OOM_EN_U8(e->ai_p2_countdown); SG_1OOM_EN_BV(e->contact, PLAYER_NUM); SG_1OOM_EN_BV(e->contact_broken, PLAYER_NUM); SG_1OOM_EN_DUMMY(4); SG_1OOM_EN_TBL_U16(e->relation1, pnum); SG_1OOM_EN_TBL_U16(e->relation2, pnum); SG_1OOM_EN_TBL_U8(e->diplo_type, pnum); SG_1OOM_EN_TBL_U16(e->diplo_val, pnum); SG_1OOM_EN_TBL_U16(e->diplo_p1, pnum); SG_1OOM_EN_TBL_U16(e->diplo_p2, pnum); SG_1OOM_EN_TBL_U16(e->trust, pnum); SG_1OOM_EN_TBL_U8(e->broken_treaty, pnum); SG_1OOM_EN_TBL_U16(e->blunder, pnum); SG_1OOM_EN_TBL_U8(e->tribute_field, pnum); SG_1OOM_EN_TBL_U8(e->tribute_tech, pnum); SG_1OOM_EN_TBL_U16(e->mood_treaty, pnum); SG_1OOM_EN_TBL_U16(e->mood_trade, pnum); SG_1OOM_EN_TBL_U16(e->mood_tech, pnum); SG_1OOM_EN_TBL_U16(e->mood_peace, pnum); SG_1OOM_EN_TBL_U8(e->treaty, pnum); SG_1OOM_EN_TBL_U16(e->trade_bc, pnum); SG_1OOM_EN_TBL_U16(e->trade_percent, pnum); SG_1OOM_EN_TBL_U8(e->spymode_next, pnum); SG_1OOM_EN_TBL_U8(e->offer_field, pnum); SG_1OOM_EN_TBL_U8(e->offer_tech, pnum); SG_1OOM_EN_TBL_U16(e->offer_bc, pnum); { /* HACK Fit 5 tables into 2 while not breaking old versions. */ uint16_t tbl[PLAYER_NUM]; for (player_id_t i = pnum; i < PLAYER_NUM; ++i) { tbl[i] = 0; /* keep compiler happy */ } /* Old attack_bounty. The attack_gift_* are irrelevant if attack_bounty is PLAYER_NONE. */ for (player_id_t i = 0; i < pnum; ++i) { uint16_t v; if (e->attack_gift_bc[i] != 0) { v = e->attack_gift_bc[i]; /* multiple of 50, always even */ } else if (e->attack_gift_tech[i] != 0) { v = (((uint16_t)e->attack_gift_tech[i]) << 8) | (e->attack_gift_field[i] << 1) | 1; } else { v = 0; } tbl[i] = v; } SG_1OOM_EN_TBL_U16(tbl, pnum); /* Old bounty_collect. attack_bounty[0] is never 0, and thus tbl[0] is never PLAYER_NONE (but typically (PLAYER_NONE << 8) | PLAYER_NONE). bounty_collect[0] is always PLAYER_NONE. Old code reading this to bounty_collect will get != PLAYER_NONE and reset attack_bounty on next turn. */ for (player_id_t i = 0; i < pnum; ++i) { tbl[i] = (((uint16_t)e->attack_bounty[i]) << 8) | e->bounty_collect[i]; } SG_1OOM_EN_TBL_U16(tbl, pnum); } SG_1OOM_EN_TBL_U16(e->hatred, pnum); SG_1OOM_EN_TBL_U16(e->have_met, pnum); SG_1OOM_EN_TBL_U16(e->trade_established_bc, pnum); SG_1OOM_EN_TBL_U16(e->spying, pnum); SG_1OOM_EN_TBL_U16(e->spyfund, pnum); SG_1OOM_EN_TBL_U8(e->spymode, pnum); SG_1OOM_EN_U16(e->security); SG_1OOM_EN_TBL_U16(e->spies, pnum); SG_1OOM_EN_U32(e->reserve_bc); SG_1OOM_EN_U16(e->tax); SG_1OOM_EN_U8(e->base_shield); SG_1OOM_EN_U8(e->base_comp); SG_1OOM_EN_U8(e->base_weapon); SG_1OOM_EN_U8(e->colonist_oper_factories); SG_1OOM_EN_TBL_U8(e->tech.percent, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U16(e->tech.slider, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U8(e->tech.slider_lock, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U32(e->tech.investment, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U8(e->tech.project, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U32(e->tech.cost, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U16(e->tech.completed, TECH_FIELD_NUM); SG_1OOM_EN_U8(e->shipdesigns_num); pos = game_save_encode_orbits(buf, pos, e->orbit, planets); SG_1OOM_EN_TBL_TBL_U8(e->spyreportfield, pnum, TECH_FIELD_NUM); SG_1OOM_EN_TBL_U16(e->spyreportyear, pnum); SG_1OOM_EN_U8(e->shipi_colony); SG_1OOM_EN_U8(e->shipi_bomber); return pos; } static int game_save_decode_eto(const uint8_t *buf, int pos, empiretechorbit_t *e, int pnum, int planets, uint32_t version) { SG_1OOM_DE_U8(e->race); SG_1OOM_DE_U8(e->banner); SG_1OOM_DE_U8(e->trait1); SG_1OOM_DE_U8(e->trait2); SG_1OOM_DE_U8(e->ai_p3_countdown); SG_1OOM_DE_U8(e->ai_p2_countdown); SG_1OOM_DE_BV(e->contact, PLAYER_NUM); SG_1OOM_DE_BV(e->contact_broken, PLAYER_NUM); SG_1OOM_DE_DUMMY(4); SG_1OOM_DE_TBL_U16(e->relation1, pnum); SG_1OOM_DE_TBL_U16(e->relation2, pnum); SG_1OOM_DE_TBL_U8(e->diplo_type, pnum); SG_1OOM_DE_TBL_U16(e->diplo_val, pnum); SG_1OOM_DE_TBL_U16(e->diplo_p1, pnum); SG_1OOM_DE_TBL_U16(e->diplo_p2, pnum); SG_1OOM_DE_TBL_U16(e->trust, pnum); SG_1OOM_DE_TBL_U8(e->broken_treaty, pnum); SG_1OOM_DE_TBL_U16(e->blunder, pnum); SG_1OOM_DE_TBL_U8(e->tribute_field, pnum); SG_1OOM_DE_TBL_U8(e->tribute_tech, pnum); SG_1OOM_DE_TBL_U16(e->mood_treaty, pnum); SG_1OOM_DE_TBL_U16(e->mood_trade, pnum); SG_1OOM_DE_TBL_U16(e->mood_tech, pnum); SG_1OOM_DE_TBL_U16(e->mood_peace, pnum); SG_1OOM_DE_TBL_U8(e->treaty, pnum); SG_1OOM_DE_TBL_U16(e->trade_bc, pnum); SG_1OOM_DE_TBL_U16(e->trade_percent, pnum); SG_1OOM_DE_TBL_U8(e->spymode_next, pnum); SG_1OOM_DE_TBL_U8(e->offer_field, pnum); SG_1OOM_DE_TBL_U8(e->offer_tech, pnum); SG_1OOM_DE_TBL_U16(e->offer_bc, pnum); { uint16_t ab[PLAYER_NUM]; uint16_t bc[PLAYER_NUM]; for (player_id_t i = pnum; i < PLAYER_NUM; ++i) { /* keep compiler happy */ ab[i] = 0; bc[i] = 0; } SG_1OOM_DE_TBL_U16(ab, pnum); SG_1OOM_DE_TBL_U16(bc, pnum); if (bc[0] != PLAYER_NONE) { /* New save, demangle the data. */ for (player_id_t i = 0; i < pnum; ++i) { uint16_t v; v = bc[i]; e->attack_bounty[i] = (v >> 8) & 0xf; e->bounty_collect[i] = v & 0xf; v = ab[i]; if (v & 1) { e->attack_gift_tech[i] = (v >> 8) & 0xff; e->attack_gift_field[i] = (v >> 1) & 0xf; } else { e->attack_gift_bc[i] = v; } } } else { /* Old save, simply copy the tables. */ for (player_id_t i = 0; i < pnum; ++i) { e->attack_bounty[i] = ab[i]; e->bounty_collect[i] = bc[i]; } } } SG_1OOM_DE_TBL_U16(e->hatred, pnum); SG_1OOM_DE_TBL_U16(e->have_met, pnum); SG_1OOM_DE_TBL_U16(e->trade_established_bc, pnum); SG_1OOM_DE_TBL_U16(e->spying, pnum); SG_1OOM_DE_TBL_U16(e->spyfund, pnum); SG_1OOM_DE_TBL_U8(e->spymode, pnum); SG_1OOM_DE_U16(e->security); SG_1OOM_DE_TBL_U16(e->spies, pnum); SG_1OOM_DE_U32(e->reserve_bc); SG_1OOM_DE_U16(e->tax); SG_1OOM_DE_U8(e->base_shield); SG_1OOM_DE_U8(e->base_comp); SG_1OOM_DE_U8(e->base_weapon); SG_1OOM_DE_U8(e->colonist_oper_factories); SG_1OOM_DE_TBL_U8(e->tech.percent, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U16(e->tech.slider, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U8(e->tech.slider_lock, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U32(e->tech.investment, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U8(e->tech.project, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U32(e->tech.cost, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U16(e->tech.completed, TECH_FIELD_NUM); SG_1OOM_DE_U8(e->shipdesigns_num); if ((e->shipdesigns_num > NUM_SHIPDESIGNS)) { log_error("Save: decode invalid number of ship designs %i\n", e->shipdesigns_num); return -1; } pos = game_save_decode_orbits(buf, pos, e->orbit, planets); if (pos < 0) { return -1; } SG_1OOM_DE_TBL_TBL_U8(e->spyreportfield, pnum, TECH_FIELD_NUM); SG_1OOM_DE_TBL_U16(e->spyreportyear, pnum); SG_1OOM_DE_U8(e->shipi_colony); SG_1OOM_DE_U8(e->shipi_bomber); return pos; } static int game_save_encode_sd(uint8_t *buf, int pos, const shipdesign_t *sd) { SG_1OOM_EN_TBL_U8(sd->name, SHIP_NAME_LEN); SG_1OOM_EN_U16(sd->cost); SG_1OOM_EN_U16(sd->space); SG_1OOM_EN_U8(sd->hull); SG_1OOM_EN_U8(sd->look); SG_1OOM_EN_TBL_U8(sd->wpnt, WEAPON_SLOT_NUM); SG_1OOM_EN_TBL_U8(sd->wpnn, WEAPON_SLOT_NUM); SG_1OOM_EN_U8(sd->engine); SG_1OOM_EN_U32(sd->engines); SG_1OOM_EN_TBL_U8(sd->special, SPECIAL_SLOT_NUM); SG_1OOM_EN_U8(sd->shield); SG_1OOM_EN_U8(sd->jammer); SG_1OOM_EN_U8(sd->comp); SG_1OOM_EN_U8(sd->armor); SG_1OOM_EN_U8(sd->man); SG_1OOM_EN_U16(sd->hp); return pos; } static int game_save_decode_sd(const uint8_t *buf, int pos, shipdesign_t *sd) { SG_1OOM_DE_TBL_U8(sd->name, SHIP_NAME_LEN); SG_1OOM_DE_U16(sd->cost); SG_1OOM_DE_U16(sd->space); SG_1OOM_DE_U8(sd->hull); SG_1OOM_DE_U8(sd->look); SG_1OOM_DE_TBL_U8(sd->wpnt, WEAPON_SLOT_NUM); SG_1OOM_DE_TBL_U8(sd->wpnn, WEAPON_SLOT_NUM); SG_1OOM_DE_U8(sd->engine); SG_1OOM_DE_U32(sd->engines); SG_1OOM_DE_TBL_U8(sd->special, SPECIAL_SLOT_NUM); SG_1OOM_DE_U8(sd->shield); SG_1OOM_DE_U8(sd->jammer); SG_1OOM_DE_U8(sd->comp); SG_1OOM_DE_U8(sd->armor); SG_1OOM_DE_U8(sd->man); SG_1OOM_DE_U16(sd->hp); return pos; } static int game_save_encode_srd(uint8_t *buf, int pos, const shipresearch_t *srd, int sdnum, uint32_t version) { for (int i = 0; i < sdnum; ++i) { pos = game_save_encode_sd(buf, pos, &(srd->design[i])); } for (int f = 0; f < TECH_FIELD_NUM; ++f) { SG_1OOM_EN_TBL_TBL_U8(srd->researchlist[f], TECH_TIER_NUM, 3); } SG_1OOM_EN_TBL_TBL_U8(srd->researchcompleted, TECH_FIELD_NUM, TECH_PER_FIELD); SG_1OOM_EN_DUMMY(NUM_SHIPDESIGNS); SG_1OOM_EN_TBL_U16(srd->year, NUM_SHIPDESIGNS); SG_1OOM_EN_DUMMY(NUM_SHIPDESIGNS * 4); return pos; } static int game_save_decode_srd(const uint8_t *buf, int pos, shipresearch_t *srd, int sdnum, uint32_t version) { for (int i = 0; i < sdnum; ++i) { pos = game_save_decode_sd(buf, pos, &(srd->design[i])); } for (int f = 0; f < TECH_FIELD_NUM; ++f) { SG_1OOM_DE_TBL_TBL_U8(srd->researchlist[f], TECH_TIER_NUM, 3); } SG_1OOM_DE_TBL_TBL_U8(srd->researchcompleted, TECH_FIELD_NUM, TECH_PER_FIELD); SG_1OOM_DE_DUMMY(NUM_SHIPDESIGNS); SG_1OOM_DE_TBL_U16(srd->year, NUM_SHIPDESIGNS); SG_1OOM_DE_DUMMY(NUM_SHIPDESIGNS * 4); return pos; } static int game_save_encode_monster(uint8_t *buf, int pos, const monster_t *m) { SG_1OOM_EN_U8(m->exists); SG_1OOM_EN_U16(m->x); SG_1OOM_EN_U16(m->y); SG_1OOM_EN_U8(m->killer); SG_1OOM_EN_U8(m->dest); SG_1OOM_EN_U8(m->counter); SG_1OOM_EN_U8(m->nuked); return pos; } static int game_save_decode_monster(const uint8_t *buf, int pos, monster_t *m) { SG_1OOM_DE_U8(m->exists); SG_1OOM_DE_U16(m->x); SG_1OOM_DE_U16(m->y); SG_1OOM_DE_U8(m->killer); SG_1OOM_DE_U8(m->dest); SG_1OOM_DE_U8(m->counter); SG_1OOM_DE_U8(m->nuked); return pos; } static int game_save_encode_evn(uint8_t *buf, int pos, const gameevents_t *ev, int pnum, uint32_t version) { SG_1OOM_EN_U16(ev->year); SG_1OOM_EN_BV(ev->done, GAME_EVENT_TBL_NUM); SG_1OOM_EN_U8(ev->diplo_msg_subtype); SG_1OOM_EN_DUMMY(16); SG_1OOM_EN_U8(ev->have_plague); SG_1OOM_EN_U8(ev->plague_player); SG_1OOM_EN_U8(ev->plague_planet_i); SG_1OOM_EN_U32(ev->plague_val); SG_1OOM_EN_U8(ev->have_nova); SG_1OOM_EN_U8(ev->nova_player); SG_1OOM_EN_U8(ev->nova_planet_i); SG_1OOM_EN_U8(ev->nova_years); SG_1OOM_EN_U32(ev->nova_val); SG_1OOM_EN_U8(ev->have_accident); SG_1OOM_EN_U8(ev->accident_planet_i); SG_1OOM_EN_U8(ev->have_comet); SG_1OOM_EN_U8(ev->comet_player); SG_1OOM_EN_U8(ev->comet_planet_i); SG_1OOM_EN_U8(ev->comet_years); SG_1OOM_EN_U16(ev->comet_hp); SG_1OOM_EN_U16(ev->comet_dmg); SG_1OOM_EN_U8(ev->have_pirates); SG_1OOM_EN_U8(ev->pirates_planet_i); SG_1OOM_EN_U16(ev->pirates_hp); pos = game_save_encode_monster(buf, pos, &(ev->crystal)); pos = game_save_encode_monster(buf, pos, &(ev->amoeba)); SG_1OOM_EN_U8(ev->planet_orion_i); SG_1OOM_EN_U8(ev->have_guardian); SG_1OOM_EN_TBL_U8(ev->home, pnum); SG_1OOM_EN_U8(ev->report_stars); SG_1OOM_EN_TBL_TBL_U32(ev->new_ships, pnum, NUM_SHIPDESIGNS); SG_1OOM_EN_TBL_TBL_U16(ev->spies_caught, pnum, pnum); SG_1OOM_EN_TBL_TBL_U16(ev->ceasefire, pnum, pnum); for (int i = 0; i < pnum; ++i) { SG_1OOM_EN_BV(ev->help_shown[i], HELP_SHOWN_NUM); SG_1OOM_EN_DUMMY(14); } SG_1OOM_EN_TBL_U16(ev->build_finished_num, pnum); SG_1OOM_EN_TBL_U8(ev->voted, pnum); SG_1OOM_EN_TBL_U8(ev->best_ecorestore, pnum); SG_1OOM_EN_TBL_U8(ev->best_wastereduce, pnum); SG_1OOM_EN_TBL_U8(ev->best_roboctrl, pnum); SG_1OOM_EN_TBL_U8(ev->best_terraform, pnum); return pos; } static int game_save_decode_evn(const uint8_t *buf, int pos, gameevents_t *ev, int pnum, uint32_t version) { SG_1OOM_DE_U16(ev->year); SG_1OOM_DE_BV(ev->done, GAME_EVENT_TBL_NUM); SG_1OOM_DE_U8(ev->diplo_msg_subtype); SG_1OOM_DE_DUMMY(16); SG_1OOM_DE_U8(ev->have_plague); SG_1OOM_DE_U8(ev->plague_player); SG_1OOM_DE_U8(ev->plague_planet_i); SG_1OOM_DE_U32(ev->plague_val); SG_1OOM_DE_U8(ev->have_nova); SG_1OOM_DE_U8(ev->nova_player); SG_1OOM_DE_U8(ev->nova_planet_i); SG_1OOM_DE_U8(ev->nova_years); SG_1OOM_DE_U32(ev->nova_val); SG_1OOM_DE_U8(ev->have_accident); SG_1OOM_DE_U8(ev->accident_planet_i); SG_1OOM_DE_U8(ev->have_comet); SG_1OOM_DE_U8(ev->comet_player); SG_1OOM_DE_U8(ev->comet_planet_i); SG_1OOM_DE_U8(ev->comet_years); SG_1OOM_DE_U16(ev->comet_hp); SG_1OOM_DE_U16(ev->comet_dmg); SG_1OOM_DE_U8(ev->have_pirates); SG_1OOM_DE_U8(ev->pirates_planet_i); SG_1OOM_DE_U16(ev->pirates_hp); pos = game_save_decode_monster(buf, pos, &(ev->crystal)); pos = game_save_decode_monster(buf, pos, &(ev->amoeba)); SG_1OOM_DE_U8(ev->planet_orion_i); SG_1OOM_DE_U8(ev->have_guardian); SG_1OOM_DE_TBL_U8(ev->home, pnum); SG_1OOM_DE_U8(ev->report_stars); SG_1OOM_DE_TBL_TBL_U32(ev->new_ships, pnum, NUM_SHIPDESIGNS); SG_1OOM_DE_TBL_TBL_U16(ev->spies_caught, pnum, pnum); SG_1OOM_DE_TBL_TBL_U16(ev->ceasefire, pnum, pnum); for (int i = 0; i < pnum; ++i) { SG_1OOM_DE_BV(ev->help_shown[i], HELP_SHOWN_NUM); SG_1OOM_DE_DUMMY(14); } SG_1OOM_DE_TBL_U16(ev->build_finished_num, pnum); SG_1OOM_DE_TBL_U8(ev->voted, pnum); SG_1OOM_DE_TBL_U8(ev->best_ecorestore, pnum); SG_1OOM_DE_TBL_U8(ev->best_wastereduce, pnum); SG_1OOM_DE_TBL_U8(ev->best_roboctrl, pnum); SG_1OOM_DE_TBL_U8(ev->best_terraform, pnum); return pos; } static int game_save_encode(uint8_t *buf, int buflen, const struct game_s *g, uint32_t version) { int pos = 0; if (buflen < sizeof(*g)) { log_error("Save: BUG: encode expected len > %i, got %i\n", sizeof(*g), buflen); return -1; } SG_1OOM_EN_U8(g->players); SG_1OOM_EN_BV(g->is_ai, PLAYER_NUM); SG_1OOM_EN_BV(g->refuse, PLAYER_NUM); SG_1OOM_EN_U8(g->ai_id); SG_1OOM_EN_DUMMY(3); SG_1OOM_EN_U8(g->active_player); SG_1OOM_EN_U8(g->difficulty); SG_1OOM_EN_U8(g->galaxy_size); SG_1OOM_EN_U8(g->galaxy_w); SG_1OOM_EN_U8(g->galaxy_h); SG_1OOM_EN_U8(g->galaxy_stars); SG_1OOM_EN_U16(g->galaxy_maxx); SG_1OOM_EN_U16(g->galaxy_maxy); SG_1OOM_EN_U32(g->galaxy_seed); SG_1OOM_EN_U32(g->seed); SG_1OOM_EN_U16(g->year); SG_1OOM_EN_U16(g->enroute_num); SG_1OOM_EN_U16(g->transport_num); SG_1OOM_EN_U8(g->end); SG_1OOM_EN_U8(g->winner); SG_1OOM_EN_U8(g->election_held); SG_1OOM_EN_U8(g->nebula_num); SG_1OOM_EN_TBL_U16(g->nebula_x, g->nebula_num); SG_1OOM_EN_TBL_U16(g->nebula_y, g->nebula_num); SG_1OOM_EN_TBL_TBL_U16(g->nebula_x0, g->nebula_num, 4); SG_1OOM_EN_TBL_TBL_U16(g->nebula_x1, g->nebula_num, 4); SG_1OOM_EN_TBL_TBL_U16(g->nebula_y0, g->nebula_num, 4); SG_1OOM_EN_TBL_TBL_U16(g->nebula_y1, g->nebula_num, 4); SG_1OOM_EN_TBL_TBL_U8(g->emperor_names, g->players, EMPEROR_NAME_LEN); SG_1OOM_EN_TBL_U8(g->planet_focus_i, g->players); for (int i = 0; i < g->galaxy_stars; ++i) { pos = game_save_encode_planet(buf, pos, &(g->planet[i]), g->players, version); } for (int j = 0; j < g->players; ++j) { for (int i = 0; i < g->galaxy_stars; ++i) { const seen_t *s = &(g->seen[j][i]); SG_1OOM_EN_U8(s->owner); SG_1OOM_EN_U16(s->pop); SG_1OOM_EN_U16(s->bases); SG_1OOM_EN_U16(s->factories); } } for (int i = 0; i < g->enroute_num; ++i) { pos = game_save_encode_enroute(buf, pos, &(g->enroute[i])); } for (int i = 0; i < g->transport_num; ++i) { pos = game_save_encode_transport(buf, pos, &(g->transport[i])); } for (int i = 0; i < g->players; ++i) { pos = game_save_encode_eto(buf, pos, &(g->eto[i]), g->players, g->galaxy_stars, version); } for (int i = 0; i < g->players; ++i) { pos = game_save_encode_srd(buf, pos, &(g->srd[i]), g->eto[i].shipdesigns_num, version); } for (int i = 0; i < g->players; ++i) { pos = game_save_encode_sd(buf, pos, &(g->current_design[i])); } pos = game_save_encode_evn(buf, pos, &(g->evn), g->players, version); SG_1OOM_EN_U32(GAME_SAVE_END); return pos; } static int game_save_decode(const uint8_t *buf, int buflen, struct game_s *g, uint32_t version) { int pos = 0; if (buflen < 512) { log_error("Save: decode expected len > %i, got %i\n", 512, buflen); return -1; } { struct game_aux_s *ga; ga = g->gaux; memset(g, 0, sizeof(*g)); g->gaux = ga; } SG_1OOM_DE_U8(g->players); if ((g->players < 2) || (g->players > 6)) { log_error("Save: decode invalid number of players %i\n", g->players); return -1; } SG_1OOM_DE_BV(g->is_ai, PLAYER_NUM); SG_1OOM_DE_BV(g->refuse, PLAYER_NUM); SG_1OOM_DE_U8(g->ai_id); SG_1OOM_DE_DUMMY(3); SG_1OOM_DE_U8(g->active_player); SG_1OOM_DE_U8(g->difficulty); if ((g->difficulty < 0) || (g->difficulty >= DIFFICULTY_NUM)) { log_error("Save: decode invalid difficulty value %i\n", g->difficulty); return -1; } SG_1OOM_DE_U8(g->galaxy_size); SG_1OOM_DE_U8(g->galaxy_w); SG_1OOM_DE_U8(g->galaxy_h); SG_1OOM_DE_U8(g->galaxy_stars); if ((g->galaxy_stars > PLANETS_MAX)) { log_error("Save: decode invalid number of stars %i\n", g->galaxy_stars); return -1; } SG_1OOM_DE_U16(g->galaxy_maxx); SG_1OOM_DE_U16(g->galaxy_maxy); SG_1OOM_DE_U32(g->galaxy_seed); SG_1OOM_DE_U32(g->seed); SG_1OOM_DE_U16(g->year); SG_1OOM_DE_U16(g->enroute_num); if ((g->enroute_num > FLEET_ENROUTE_MAX)) { log_error("Save: decode invalid number of fleets %i\n", g->enroute_num); return -1; } SG_1OOM_DE_U16(g->transport_num); if ((g->transport_num > TRANSPORT_MAX)) { log_error("Save: decode invalid number of transports %i\n", g->transport_num); return -1; } SG_1OOM_DE_U8(g->end); SG_1OOM_DE_U8(g->winner); SG_1OOM_DE_U8(g->election_held); SG_1OOM_DE_U8(g->nebula_num); if ((g->nebula_num > NEBULA_MAX)) { log_error("Save: decode invalid number of nebula %i\n", g->nebula_num); return -1; } SG_1OOM_DE_TBL_U16(g->nebula_x, g->nebula_num); SG_1OOM_DE_TBL_U16(g->nebula_y, g->nebula_num); SG_1OOM_DE_TBL_TBL_U16(g->nebula_x0, g->nebula_num, 4); SG_1OOM_DE_TBL_TBL_U16(g->nebula_x1, g->nebula_num, 4); SG_1OOM_DE_TBL_TBL_U16(g->nebula_y0, g->nebula_num, 4); SG_1OOM_DE_TBL_TBL_U16(g->nebula_y1, g->nebula_num, 4); for (int i = 0; i < g->nebula_num; ++i) { g->nebula_type[i] = game_save_infer_nebula_type(g, i); if (g->nebula_type[i] < 0) { log_error("Save: unknown nebula type for nebula %i\n", i); return -1; } } SG_1OOM_DE_TBL_TBL_U8(g->emperor_names, g->players, EMPEROR_NAME_LEN); SG_1OOM_DE_TBL_U8(g->planet_focus_i, g->players); for (int i = 0; i < g->galaxy_stars; ++i) { pos = game_save_decode_planet(buf, pos, &(g->planet[i]), g->players, version); } for (int j = 0; j < g->players; ++j) { for (int i = 0; i < g->galaxy_stars; ++i) { seen_t *s = &(g->seen[j][i]); SG_1OOM_DE_U8(s->owner); SG_1OOM_DE_U16(s->pop); SG_1OOM_DE_U16(s->bases); SG_1OOM_DE_U16(s->factories); } } for (int i = 0; i < g->enroute_num; ++i) { pos = game_save_decode_enroute(buf, pos, &(g->enroute[i])); } for (int i = 0; i < g->transport_num; ++i) { pos = game_save_decode_transport(buf, pos, &(g->transport[i])); } for (int i = 0; i < g->players; ++i) { pos = game_save_decode_eto(buf, pos, &(g->eto[i]), g->players, g->galaxy_stars, version); if (pos < 0) { return -1; } } for (int i = 0; i < g->players; ++i) { pos = game_save_decode_srd(buf, pos, &(g->srd[i]), g->eto[i].shipdesigns_num, version); } for (int i = 0; i < g->players; ++i) { pos = game_save_decode_sd(buf, pos, &(g->current_design[i])); } pos = game_save_decode_evn(buf, pos, &(g->evn), g->players, version); { uint32_t v; SG_1OOM_DE_U32(v); if (pos > buflen) { log_error("Save: decode read len %i > got %i\n", pos, buflen); return -1; } if (v != GAME_SAVE_END) { log_error("Save: invalid end mark 0x%08x != 0x%08x at %i!\n", v, GAME_SAVE_END, pos); return -1; } } if (pos < buflen) { log_warning("Save: decode read len %i < got %i (left %i)\n", pos, buflen, buflen - pos); } /* generate g->refuse if needed */ if ((g->end == GAME_END_FINAL_WAR) && BOOLVEC_IS_CLEAR(g->refuse, PLAYER_NUM)) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (IS_HUMAN(g, i) && IS_ALIVE(g, i)) { BOOLVEC_SET1(g->refuse, i); } } } g->guardian_killer = PLAYER_NONE; return 0; } /* -------------------------------------------------------------------------- */ static void game_save_make_header(uint8_t *buf, const char *savename, uint32_t version) { memset(buf, 0, GAME_SAVE_HDR_SIZE); memcpy(buf, (const uint8_t *)GAME_SAVE_MAGIC, 8); SET_LE_32(&buf[GAME_SAVE_OFFS_VERSION], version); strncpy((char *)&buf[GAME_SAVE_OFFS_NAME], savename, SAVE_NAME_LEN); } static int game_save_do_save_do(const char *filename, const char *savename, const struct game_s *g, int savei, uint32_t version) { FILE *fd; uint8_t hdr[GAME_SAVE_HDR_SIZE]; int res = -1, len; if ((len = game_save_encode(g->gaux->savebuf, g->gaux->savebuflen, g, version)) <= 0) { return -1; } if (os_make_path_for(filename)) { log_error("Save: failed to create path for '%s'\n", filename); } game_save_make_header(hdr, savename, version); fd = game_save_open_check_header(filename, -1, false, 0, 0); if (fd) { /* file exists */ fclose(fd); fd = NULL; } if ((savei >= 0) && (savei < (NUM_SAVES + 1))) { game_save_tbl_have_save[savei] = false; game_save_tbl_name[savei][0] = '\0'; } fd = fopen(filename, "wb+"); if (0 || (!fd) || (fwrite(hdr, GAME_SAVE_HDR_SIZE, 1, fd) != 1) || (fwrite(g->gaux->savebuf, len, 1, fd) != 1) ) { log_error("Save: failed to save '%s'\n", filename); unlink(filename); goto done; } if ((savei >= 0) && (savei < (NUM_SAVES + 1))) { game_save_tbl_have_save[savei] = true; memcpy(game_save_tbl_name[savei], &hdr[GAME_SAVE_OFFS_NAME], SAVE_NAME_LEN); } log_message("Save: save '%s' '%s'\n", filename, savename); res = 0; done: if (fd) { fclose(fd); fd = NULL; } return res; } static int game_save_do_load_do(const char *filename, struct game_s *g, int savei, char *savename) { FILE *fd = NULL; int res = -1, len = 0; uint32_t version; fd = game_save_open_check_header(filename, savei, true, savename, &version); if ((!fd) || ((len = fread(g->gaux->savebuf, 1, g->gaux->savebuflen, fd)) == 0) || (!feof(fd))) { log_error("Save: failed to load '%s'\n", filename); } else if (game_save_decode(g->gaux->savebuf, len, g, version) != 0) { log_error("Save: invalid data on load '%s'\n", filename); } else { log_message("Save: load '%s'\n", filename); res = 0; } if (fd) { fclose(fd); fd = NULL; } return res; } /* -------------------------------------------------------------------------- */ void *game_save_open_check_header(const char *filename, int i, bool update_table, char *savename, uint32_t *versionptr) { uint8_t hdr[GAME_SAVE_HDR_SIZE]; FILE *fd; if ((i < 0) || (i >= NUM_ALL_SAVES)) { update_table = false; } if (update_table) { game_save_tbl_have_save[i] = false; game_save_tbl_name[i][0] = '\0'; } if (savename) { savename[0] = '\0'; } fd = fopen(filename, "rb"); if (0 || (!fd) || (fread(hdr, GAME_SAVE_HDR_SIZE, 1, fd) != 1) || (memcmp(hdr, (const uint8_t *)GAME_SAVE_MAGIC, 8) != 0) ) { goto fail; } else { uint32_t version = GET_LE_32(&hdr[GAME_SAVE_OFFS_VERSION]); if (versionptr) { *versionptr = version; } if (version > GAME_SAVE_VERSION) { goto fail; } if (update_table) { game_save_tbl_have_save[i] = true; memcpy(game_save_tbl_name[i], &hdr[GAME_SAVE_OFFS_NAME], SAVE_NAME_LEN); game_save_tbl_name[i][SAVE_NAME_LEN - 1] = '\0'; } if (savename) { memcpy(savename, &hdr[GAME_SAVE_OFFS_NAME], SAVE_NAME_LEN); savename[SAVE_NAME_LEN - 1] = '\0'; } } return fd; fail: if (fd) { fclose(fd); fd = NULL; } return NULL; } int game_save_get_slot_fname(char *buf, int buflen, int i) { const char *path = os_get_path_user(); char namebuf[16]; int res; if (!os_get_fname_save_slot(namebuf, sizeof(namebuf), i + 1)) { lib_sprintf(namebuf, sizeof(namebuf), "1oom_save%i.bin", i + 1); } res = util_concat_buf(buf, buflen, path, FSDEV_DIR_SEP_STR, namebuf, NULL); if (res < 0) { log_error("Save: BUG: save name buffer too small by %i bytes\n", -res); return -1; } return 0; } int game_save_get_year_fname(char *buf, int buflen, int year) { const char *path = os_get_path_user(); char namebuf[32]; int res; if (!os_get_fname_save_year(namebuf, sizeof(namebuf), year)) { lib_sprintf(namebuf, sizeof(namebuf), "1oom_save_%i.bin", year); } res = util_concat_buf(buf, buflen, path, FSDEV_DIR_SEP_STR, namebuf, NULL); if (res < 0) { log_error("Save: BUG: save name buffer too small by %i bytes\n", -res); return -1; } return 0; } int game_save_check_saves(char *fnamebuf, int buflen) { FILE *fd; for (int i = 0; i < NUM_ALL_SAVES; ++i) { game_save_get_slot_fname(fnamebuf, buflen, i); fd = game_save_open_check_header(fnamebuf, i, true, 0, 0); if (fd) { fclose(fd); } } return 0; } int game_save_do_load_fname(const char *filename, char *savename, struct game_s *g) { return game_save_do_load_do(filename, g, -1, savename); } int game_save_do_save_fname(const char *filename, const char *savename, const struct game_s *g, uint32_t version) { if (version > GAME_SAVE_VERSION) { log_error("Save: BUG: invalid version %i > %i\n", version, GAME_SAVE_VERSION); return -1; } return game_save_do_save_do(filename, savename, g, -1, version); } int game_save_do_load_i(int savei, struct game_s *g) { int res; char *filename = g->gaux->savenamebuf; game_save_get_slot_fname(filename, g->gaux->savenamebuflen, savei); res = game_save_do_load_do(filename, g, savei, 0); return res; } int game_save_do_save_i(int savei, const char *savename, const struct game_s *g) { int res; char *filename = g->gaux->savenamebuf; if (os_make_path_user()) { log_error("Save: failed to create user path '%s'\n", os_get_path_user()); } game_save_get_slot_fname(filename, g->gaux->savenamebuflen, savei); res = game_save_do_save_do(filename, savename, g, savei, GAME_SAVE_VERSION); return res; } int game_save_do_load_year(int year, char *savename, struct game_s *g) { int res; char *filename = g->gaux->savenamebuf; game_save_get_year_fname(filename, g->gaux->savenamebuflen, year); res = game_save_do_load_do(filename, g, -1, savename); return res; } int game_save_do_save_year(const char *savename, const struct game_s *g) { int res; char *filename = g->gaux->savenamebuf; char buf[SAVE_NAME_LEN]; if (os_make_path_user()) { log_error("Save: failed to create user path '%s'\n", os_get_path_user()); } game_save_get_year_fname(filename, g->gaux->savenamebuflen, g->year + YEAR_BASE); if (!savename) { lib_sprintf(buf, sizeof(buf), "Year %i", g->year + YEAR_BASE); savename = buf; } res = game_save_do_save_do(filename, savename, g, -1, GAME_SAVE_VERSION); return res; } 1oom-1.11.2/src/game/game_save.h000066400000000000000000000025371476061725400162720ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_SAVE_H #define INC_1OOM_GAME_SAVE_H #include "types.h" #define NUM_SAVES 6 #define NUM_ALL_SAVES (NUM_SAVES + 1/*continue game*/ + 1/*undo*/ + 1/*init*/) #define SAVE_NAME_LEN 20 #define GAME_SAVE_I_CONTINUE (7 - 1) #define GAME_SAVE_I_UNDO (8 - 1) #define GAME_SAVE_I_INIT (9 - 1) extern bool game_save_tbl_have_save[NUM_ALL_SAVES]; extern char game_save_tbl_name[NUM_ALL_SAVES][SAVE_NAME_LEN]; extern void *game_save_open_check_header(const char *filename, int i, bool update_table, char *savename, uint32_t *versionptr); extern int game_save_get_slot_fname(char *fnamebuf, int buflen, int i); extern int game_save_get_year_fname(char *fnamebuf, int buflen, int year); extern int game_save_check_saves(char *fnamebuf, int buflen); struct game_s; extern int game_save_do_load_fname(const char *filename, char *savename, struct game_s *g); extern int game_save_do_save_fname(const char *filename, const char *savename, const struct game_s *g, uint32_t version); extern int game_save_do_load_i(int savei/*0..NUM_ALL_SAVES-1*/, struct game_s *g); extern int game_save_do_save_i(int savei/*0..NUM_ALL_SAVES-1*/, const char *savename, const struct game_s *g); extern int game_save_do_load_year(int year, char *savename, struct game_s *g); extern int game_save_do_save_year(const char *savename, const struct game_s *g); #endif 1oom-1.11.2/src/game/game_save_moo13.c000066400000000000000000000421721476061725400173020ustar00rootroot00000000000000#include "config.h" #include "bits.h" #include "comp.h" #include "game.h" #include "game_save_moo13.h" #include "lib.h" #include "log.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define SAVE_MOO13_LEN 59036 /* -------------------------------------------------------------------------- */ static uint8_t *savebuf = NULL; static uint32_t savelen = 0; /* -------------------------------------------------------------------------- */ #define M13_GET_8(item_, addr_) item_ = savebuf[addr_] #define M13_GET_16(item_, addr_) item_ = GET_LE_16(&savebuf[addr_]) #define M13_GET_32(item_, addr_) item_ = GET_LE_32(&savebuf[addr_]) #define M13_GET_16_OWNER(item_, addr_) \ do { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[addr_]); \ if (t_ == 0xffff) { t_ = PLAYER_NONE; }; \ item_ = t_; \ } while (0) #define M13_GET_16_KILLER(item_, addr_) \ do { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[addr_]); \ if (t_ == 0) { t_ = PLAYER_NONE; } else { --t_; } \ item_ = t_; \ } while (0) #define M13_GET_16_CHECK(item_, addr_, l_, h_) \ do { \ int t_; \ t_ = GET_LE_16(&savebuf[addr_]); \ if ((t_ < l_) || (t_ > h_)) { \ log_error( #item_ " at 0x%04x is %i and not in range %i..%i\n", addr_, t_, l_, h_); \ return -1; \ } \ item_ = t_; \ } while (0) #define M13_GET_TBL_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ item_[i_] = GET_LE_16(&savebuf[(addr_) + i_ * 2]); \ } \ } while (0) #define M13_GET_TBL_16_OWNER(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[(addr_) + i_ * 2]); \ if (t_ == 0xffff) { t_ = PLAYER_NONE; }; \ item_[i_] = t_; \ } \ } while (0) #define M13_GET_TBL_16_HATED(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[(addr_) + i_ * 2]); \ if (t_ == 0) { t_ = PLAYER_NONE; } \ item_[i_] = t_; \ } \ } while (0) #define M13_GET_TBL_BVN_8(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ if (savebuf[(addr_) + i_]) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_BV_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < PLAYER_NUM; ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[(addr_) + i_ * 2]); \ if (t_) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_BVN_16(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&savebuf[(addr_) + i_ * 2]); \ if (t_) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_32(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ item_[i_] = GET_LE_32(&savebuf[(addr_) + i_ * 4]); \ } \ } while (0) static int savetype_de_moo13_sd(shipdesign_t *sd, int sb) { memcpy(sd->name, &savebuf[sb + 0x00], 11); M13_GET_16(sd->cost, sb + 0x14); M13_GET_16(sd->space, sb + 0x16); M13_GET_16(sd->hull, sb + 0x18); M13_GET_16(sd->look, sb + 0x1a); M13_GET_TBL_16(sd->wpnt, sb + 0x1c); M13_GET_TBL_16(sd->wpnn, sb + 0x24); M13_GET_16(sd->engine, sb + 0x2c); M13_GET_32(sd->engines, sb + 0x2e); M13_GET_TBL_16(sd->special, sb + 0x32); M13_GET_16(sd->shield, sb + 0x38); M13_GET_16(sd->jammer, sb + 0x3a); M13_GET_16(sd->comp, sb + 0x3c); M13_GET_16(sd->armor, sb + 0x3e); M13_GET_16(sd->man, sb + 0x40); M13_GET_16(sd->hp, sb + 0x42); return 0; } int game_save_de_moo13(struct game_s *g, const char *fname) { savebuf = NULL; savelen = 0; savebuf = util_file_load(fname, &savelen); if (savelen != SAVE_MOO13_LEN) { log_error("loading MOO1 v1.3 save '%s' (got %i != %i bytes)\n", fname, savelen, SAVE_MOO13_LEN); if (savebuf) { lib_free(savebuf); savebuf = NULL; } return -1; } { void *t = g->gaux; memset(g, 0, sizeof(*g)); g->gaux = t; } M13_GET_16_CHECK(g->players, 0xe2d2, 2, 6); g->is_ai[0] = ((1 << g->players) - 1) & ~1; g->active_player = PLAYER_0; M13_GET_16_CHECK(g->difficulty, 0xe2d4, 0, 4); M13_GET_16_CHECK(g->galaxy_size, 0xe2d8, 0, 3); M13_GET_16_CHECK(g->nebula_num, 0xe238, 0, 4); M13_GET_16_CHECK(g->galaxy_stars, 0xe2d6, 24, 108); M13_GET_16(g->galaxy_w, 0xe2da); M13_GET_16(g->galaxy_h, 0xe2dc); M13_GET_16(g->galaxy_maxx, 0xe2de); M13_GET_16(g->galaxy_maxy, 0xe2e0); M13_GET_16(g->year, 0xe232); M13_GET_16_CHECK(g->enroute_num, 0xe1b6, 0, 259); M13_GET_16_CHECK(g->transport_num, 0xe1b8, 0, 99); M13_GET_16(g->end, 0xe686); g->refuse[0] = (!g->end) ? 0 : 1; M13_GET_16_OWNER(g->winner, 0xe688); M13_GET_16(g->election_held, 0xe68c); for (int i = 0; i < g->nebula_num; ++i) { M13_GET_16(g->nebula_type[i], 0xe23a + i * 2); M13_GET_16(g->nebula_x[i], 0xe242 + i * 2); M13_GET_16(g->nebula_y[i], 0xe24a + i * 2); for (int j = 0; j < 4; ++j) { M13_GET_16(g->nebula_x0[i][j], 0xe252 + (i * 4 + j) * 2); M13_GET_16(g->nebula_x1[i][j], 0xe272 + (i * 4 + j) * 2); M13_GET_16(g->nebula_y0[i][j], 0xe292 + (i * 4 + j) * 2); M13_GET_16(g->nebula_y1[i][j], 0xe2b2 + (i * 4 + j) * 2); } } for (int i = 0; i < g->players; ++i) { memcpy(g->emperor_names[i], &savebuf[0xe1ba + i * 15], EMPEROR_NAME_LEN - 1); } M13_GET_16(g->planet_focus_i[0], 0xe236); for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); int pb; pb = i * 0xb8; memcpy(p->name, &savebuf[pb], PLANET_NAME_LEN - 1); M13_GET_16(p->x, pb + 0xc); M13_GET_16(p->y, pb + 0xe); M13_GET_16(p->star_type, pb + 0x10); M13_GET_16(p->look, pb + 0x12); M13_GET_16(p->frame, pb + 0x14); M13_GET_16(p->rocks, pb + 0x18); M13_GET_16(p->max_pop1, pb + 0x1a); M13_GET_16(p->max_pop2, pb + 0x1c); M13_GET_16(p->max_pop3, pb + 0x1e); M13_GET_16(p->type, pb + 0x20); M13_GET_16(p->battlebg, pb + 0x22); M13_GET_16(p->infogfx, pb + 0x24); M13_GET_16(p->growth, pb + 0x26); M13_GET_16(p->special, pb + 0x28); M13_GET_16(p->bc_to_ecoproj, pb + 0x2a); M13_GET_16(p->bc_to_ship, pb + 0x2c); M13_GET_16(p->bc_to_factory, pb + 0x2e); M13_GET_32(p->reserve, pb + 0x30); M13_GET_16(p->waste, pb + 0x34); M13_GET_16_OWNER(p->owner, pb + 0x36); M13_GET_16_OWNER(p->prev_owner, pb + 0x38); M13_GET_16_OWNER(p->claim, pb + 0xa0); M13_GET_16(p->pop, pb + 0x3a); M13_GET_16(p->pop_prev, pb + 0x3c); M13_GET_16(p->factories, pb + 0x3e); M13_GET_TBL_16(p->slider, pb + 0x50); M13_GET_TBL_16(p->slider_lock, pb + 0x72); M13_GET_16(p->buildship, pb + 0x5a); M13_GET_16(p->reloc, pb + 0x5c); M13_GET_16(p->missile_bases, pb + 0x5e); M13_GET_16(p->bc_to_base, pb + 0x60); M13_GET_16(p->bc_upgrade_base, pb + 0x62); M13_GET_16(p->have_stargate, pb + 0x64); M13_GET_16(p->shield, pb + 0x68); M13_GET_16(p->bc_to_shield, pb + 0x6a); M13_GET_16(p->trans_num, pb + 0x6c); M13_GET_16(p->trans_dest, pb + 0x6e); M13_GET_8(p->pop_tenths, pb + 0x70); M13_GET_TBL_BV_16(p->explored, pb + 0x7c); M13_GET_16(p->pop_oper_fact, pb + 0xae); M13_GET_16(p->bc_to_refit, pb + 0xb0); M13_GET_16(p->rebels, pb + 0xb2); M13_GET_16(p->unrest, pb + 0xb4); M13_GET_16(p->unrest_reported, pb + 0xb6); } for (int i = 0; i < g->galaxy_stars; ++i) { seen_t *s = &(g->seen[PLAYER_0][i]); M13_GET_16_OWNER(s->owner, 0xe2e2 + i * 2); M13_GET_16(s->pop, 0xe3ba + i * 2); M13_GET_16(s->bases, 0xe492 + i * 2); M13_GET_16(s->factories, 0xe56a + i * 2); } for (int j = PLAYER_1; j < g->players; ++j) { for (int i = 0; i < g->galaxy_stars; ++i) { seen_t *s = &(g->seen[j][i]); s->owner = PLAYER_NONE; } } for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); int rb; rb = 0x4da0 + i * 0x1c; M13_GET_16_OWNER(r->owner, rb + 0x00); M13_GET_16(r->x, rb + 0x02); M13_GET_16(r->y, rb + 0x04); M13_GET_16(r->dest, rb + 0x06); M13_GET_8(r->speed, rb + 0x08); M13_GET_TBL_16(r->ships, rb + 0x0a); } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); int rb; rb = 0x6a10 + i * 0x12; M13_GET_16_OWNER(r->owner, rb + 0x00); M13_GET_16(r->x, rb + 0x02); M13_GET_16(r->y, rb + 0x04); M13_GET_16(r->dest, rb + 0x06); M13_GET_8(r->speed, rb + 0x10); M13_GET_16(r->pop, rb + 0x08); } for (int i = 0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); int eb; eb = 0x7118 + i * 0xdd4; M13_GET_8(e->race, eb + 0x000); M13_GET_8(e->banner, eb + 0x002); M13_GET_8(e->trait1, eb + 0x004); M13_GET_8(e->trait2, eb + 0x006); M13_GET_16(e->ai_p3_countdown, eb + 0x008); M13_GET_16(e->ai_p2_countdown, eb + 0x00a); M13_GET_TBL_BV_16(e->contact, eb + 0x00c); M13_GET_TBL_16(e->relation1, eb + 0x018); M13_GET_TBL_16(e->relation2, eb + 0x024); M13_GET_TBL_16(e->diplo_type, eb + 0x030); M13_GET_TBL_16(e->diplo_val, eb + 0x03c); M13_GET_TBL_16(e->diplo_p1, eb + 0x048); M13_GET_TBL_16(e->diplo_p2, eb + 0x054); M13_GET_TBL_16(e->trust, eb + 0x06c); M13_GET_TBL_16(e->broken_treaty, eb + 0x078); M13_GET_TBL_16(e->blunder, eb + 0x084); M13_GET_TBL_16(e->tribute_field, eb + 0x090); M13_GET_TBL_16(e->tribute_tech, eb + 0x09c); M13_GET_TBL_16(e->mood_treaty, eb + 0x0a8); M13_GET_TBL_16(e->mood_trade, eb + 0x0b4); M13_GET_TBL_16(e->mood_tech, eb + 0x0c0); M13_GET_TBL_16(e->mood_peace, eb + 0x0cc); M13_GET_TBL_16(e->treaty, eb + 0x0d8); M13_GET_TBL_16(e->trade_bc, eb + 0x0e4); M13_GET_TBL_16(e->trade_percent, eb + 0x0f0); M13_GET_TBL_16(e->spymode_next, eb + 0x0fc); M13_GET_TBL_16(e->offer_field, eb + 0x1d4); M13_GET_TBL_16(e->offer_tech, eb + 0x1e0); M13_GET_TBL_16(e->offer_bc, eb + 0x1ec); M13_GET_TBL_16_HATED(e->attack_bounty, eb + 0x21c); M13_GET_TBL_16_HATED(e->bounty_collect, eb + 0x228); M13_GET_TBL_16(e->attack_gift_field, eb + 0x234); M13_GET_TBL_16(e->attack_gift_tech, eb + 0x240); M13_GET_TBL_16(e->attack_gift_bc, eb + 0x24c); M13_GET_TBL_16(e->hatred, eb + 0x270); M13_GET_TBL_16(e->have_met, eb + 0x27c); M13_GET_TBL_16(e->trade_established_bc, eb + 0x288); M13_GET_TBL_16(e->spying, eb + 0x2a4); M13_GET_TBL_16(e->spyfund, eb + 0x2b0); M13_GET_TBL_16(e->spymode, eb + 0x2c8); M13_GET_16(e->security, eb + 0x2d4); M13_GET_TBL_16(e->spies, eb + 0x2d6); M13_GET_32(e->reserve_bc, eb + 0x2fc); M13_GET_16(e->tax, eb + 0x300); M13_GET_16(e->base_shield, eb + 0x302); M13_GET_16(e->base_comp, eb + 0x304); M13_GET_16(e->base_weapon, eb + 0x306); M13_GET_16(e->colonist_oper_factories, eb + 0x326); M13_GET_TBL_16(e->tech.percent, eb + 0x332 + 0x00); M13_GET_TBL_16(e->tech.slider, eb + 0x332 + 0x0c); M13_GET_TBL_16(e->tech.slider_lock, eb + 0x332 + 0x60); M13_GET_TBL_32(e->tech.investment, eb + 0x332 + 0x18); M13_GET_TBL_16(e->tech.project, eb + 0x332 + 0x30); M13_GET_TBL_32(e->tech.cost, eb + 0x332 + 0x3c); M13_GET_TBL_16(e->tech.completed, eb + 0x332 + 0x54); M13_GET_16_CHECK(e->shipdesigns_num, eb + 0x3a0, 0, 6); for (int j = 0; j < g->galaxy_stars; ++j) { fleet_orbit_t *r = &(e->orbit[j]); int ob; ob = eb + 0x3a2 + j * 0x18; M13_GET_TBL_16(r->ships, ob + 0x0c); } M13_GET_TBL_16(g->eto[PLAYER_0].spyreportfield[i], eb + 0xdc2); M13_GET_16(g->eto[PLAYER_0].spyreportyear[i], eb + 0xdce); M13_GET_16(e->shipi_colony, eb + 0xdd0); M13_GET_16(e->shipi_bomber, eb + 0xdd2); } for (int i = 0; i < g->players; ++i) { shipresearch_t *srd = &(g->srd[i]); int srdb, pos; srdb = 0xc410 + i * 0x468; for (int j = 0; j < g->eto[i].shipdesigns_num; ++j) { if (savetype_de_moo13_sd(&(srd->design[j]), srdb + j * 0x44) != 0) { if (savebuf) { lib_free(savebuf); savebuf = NULL; } return -1; } } pos = srdb + 0x228; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int t = 0; t < TECH_TIER_NUM; ++t) { for (int j = 0; j < 3; ++j) { M13_GET_8(srd->researchlist[f][t][j], pos); ++pos; } } } pos = srdb + 0x2dc; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int j = 0; j < TECH_PER_FIELD; ++j) { M13_GET_8(srd->researchcompleted[f][j], pos); ++pos; } } M13_GET_TBL_16(srd->year, srdb + 0x450); } if (savetype_de_moo13_sd(&(g->current_design[PLAYER_0]), 0xe642) != 0) { if (savebuf) { lib_free(savebuf); savebuf = NULL; } return -1; } { gameevents_t *ev = &(g->evn); const int evb = 0xde80; M13_GET_16(ev->year, evb + 0x000); M13_GET_TBL_BVN_16(ev->done, evb + 0x004, 20); M13_GET_16(ev->have_plague, evb + 0x02c); M13_GET_16(ev->plague_player, evb + 0x02e); M13_GET_16(ev->plague_planet_i, evb + 0x030); M13_GET_16(ev->plague_val, evb + 0x032); M13_GET_16(ev->have_nova, evb + 0x03a); M13_GET_16(ev->nova_player, evb + 0x03c); M13_GET_16(ev->nova_planet_i, evb + 0x03e); M13_GET_16(ev->nova_years, evb + 0x040); M13_GET_16(ev->nova_val, evb + 0x042); M13_GET_16(ev->have_accident, evb + 0x044); M13_GET_16(ev->accident_planet_i, evb + 0x048); M13_GET_16(ev->have_comet, evb + 0x056); M13_GET_16(ev->comet_player, evb + 0x058); M13_GET_16(ev->comet_planet_i, evb + 0x05a); M13_GET_16(ev->comet_years, evb + 0x05c); M13_GET_16(ev->comet_hp, evb + 0x05e); M13_GET_16(ev->comet_dmg, evb + 0x060); M13_GET_16(ev->have_pirates, evb + 0x062); M13_GET_16(ev->pirates_planet_i, evb + 0x066); M13_GET_16(ev->pirates_hp, evb + 0x068); M13_GET_16(ev->crystal.exists, evb + 0x06e); M13_GET_16(ev->crystal.x, evb + 0x070); M13_GET_16(ev->crystal.y, evb + 0x072); M13_GET_16_KILLER(ev->crystal.killer, evb + 0x076); M13_GET_16(ev->crystal.dest, evb + 0x078); M13_GET_16(ev->crystal.counter, evb + 0x074); M13_GET_16(ev->crystal.nuked, evb + 0x07a); M13_GET_16(ev->amoeba.exists, evb + 0x07c); M13_GET_16(ev->amoeba.x, evb + 0x07e); M13_GET_16(ev->amoeba.y, evb + 0x080); M13_GET_16_KILLER(ev->amoeba.killer, evb + 0x084); M13_GET_16(ev->amoeba.dest, evb + 0x086); M13_GET_16(ev->amoeba.counter, evb + 0x082); M13_GET_16(ev->amoeba.nuked, evb + 0x088); M13_GET_8(ev->planet_orion_i, evb + 0x09c); M13_GET_8(ev->have_guardian, evb + 0x09e); M13_GET_TBL_16(ev->home, evb + 0x0a0); M13_GET_8(ev->report_stars, evb + 0x0ac); for (int i = 1; i < g->players; ++i) { M13_GET_16(ev->spies_caught[i][PLAYER_0], evb + 0x1f2 + i * 2); } M13_GET_TBL_16(ev->spies_caught[PLAYER_0], evb + 0x1fe); M13_GET_TBL_16(ev->ceasefire[PLAYER_0], evb + 0x28e); M13_GET_TBL_BVN_8(ev->help_shown[PLAYER_0], evb + 0x2e2, 16); /* TODO build_finished ; is it even possible to save before clicking them away? */ M13_GET_TBL_16_OWNER(ev->voted, evb + 0x320); M13_GET_16(ev->best_ecorestore[PLAYER_0], evb + 0x32c); M13_GET_16(ev->best_wastereduce[PLAYER_0], evb + 0x32e); M13_GET_16(ev->best_roboctrl[PLAYER_0], evb + 0x332); M13_GET_16(ev->best_terraform[PLAYER_0], evb + 0x334); } { uint8_t v = 0; int a = 0xe68e; for (int i = 0; i < g->galaxy_stars; ++i) { if ((i & 7) == 0) { M13_GET_8(v, a); ++a; } if (v & (1 << (i & 7))) { BOOLVEC_SET1(g->planet[i].finished, FINISHED_SHIP); } } } g->guardian_killer = PLAYER_NONE; if (savebuf) { lib_free(savebuf); savebuf = NULL; } return 0; } 1oom-1.11.2/src/game/game_save_moo13.h000066400000000000000000000002621476061725400173010ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_SAVE_M13_H #define INC_1OOM_GAME_SAVE_M13_H #include "types.h" struct game_s; extern int game_save_de_moo13(struct game_s *g, const char *fname); #endif 1oom-1.11.2/src/game/game_shipdesign.c000066400000000000000000000026601476061725400174610ustar00rootroot00000000000000#include "config.h" #include "game_shipdesign.h" #include "game_shiptech.h" #include "types.h" /* -------------------------------------------------------------------------- */ int16_t startship_num = 5; shipdesign_t tbl_startship[NUM_SHIPDESIGNS] = { { /* SCOUT */ "", 10, 0, SHIP_HULL_SMALL, 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 10, { SHIP_SPECIAL_RESERVE_FUEL_TANKS, 0, 0 }, 0, 0, 0, 0, 0, 3 }, { /* FIGHTER */ "", 15, 0, SHIP_HULL_SMALL, 1, { WEAPON_LASER, 0, 0, 0 }, { 1, 0, 0, 0 }, 0, 30, { 0, 0, 0 }, 0, 0, 0, 0, 0, 3 }, { /* DESTROYER */ "", 66, 0, SHIP_HULL_MEDIUM, 6, { WEAPON_NUCLEAR_MISSILE_2, WEAPON_LASER, 0, 0 }, { 1, 3, 0, 0 }, 0, 115, { 0, 0, 0 }, 0, 0, 0, 0, 0, 18 }, { /* BOMBER */ "", 86, 0, SHIP_HULL_MEDIUM, 7, { WEAPON_NUCLEAR_BOMB, WEAPON_LASER, 0, 0 }, { 2, 2, 0, 0 }, 0, 90, { 0, 0, 0 }, 0, 0, 0, 0, 0, 18 }, { /* COLONY SHIP */ "", 591, 0, SHIP_HULL_LARGE, 12, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 205, { SHIP_SPECIAL_STANDARD_COLONY_BASE, 0, 0 }, 0, 0, 0, 0, 0, 100 }, { /* (unused) */ "", 10, 0, SHIP_HULL_SMALL, 0, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 10, { 0, 0, 0 }, 0, 0, 0, 0, 0, 3 } }; shipcount_t startfleet_ships[NUM_SHIPDESIGNS] = { 2, 0, 0, 0, 1, 0 }; 1oom-1.11.2/src/game/game_shipdesign.h000066400000000000000000000017121476061725400174630ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_SHIPDESIGN_H #define INC_1OOM_GAME_SHIPDESIGN_H #include "game_shiptech.h" #include "game_types.h" #include "types.h" #define SHIP_NAME_LEN 12 #define SHIP_LOOK_PER_HULL 6 #define SHIP_LOOK_PER_BANNER 24 #define WEAPON_SLOT_NUM 4 #define SPECIAL_SLOT_NUM 3 typedef struct shipdesign_s { char name[SHIP_NAME_LEN]; uint16_t cost; uint16_t space; ship_hull_t hull; uint8_t look; weapon_t wpnt[WEAPON_SLOT_NUM]; /* weapon type */ uint8_t wpnn[WEAPON_SLOT_NUM]; /* weapon num */ ship_engine_t engine; uint32_t engines; ship_special_t special[SPECIAL_SLOT_NUM]; ship_shield_t shield; ship_jammer_t jammer; ship_comp_t comp; ship_armor_t armor; uint8_t man; /* maneuverability */ uint16_t hp; /* hit points */ } shipdesign_t; extern int16_t startship_num; extern shipdesign_t tbl_startship[NUM_SHIPDESIGNS]; extern shipcount_t startfleet_ships[NUM_SHIPDESIGNS]; #endif 1oom-1.11.2/src/game/game_shiptech.c000066400000000000000000001045541476061725400171400ustar00rootroot00000000000000#include "config.h" #include "game_shiptech.h" #include "game_str.h" #include "game_techtypes.h" #include "types.h" static const char *strspace = " "; static const char *strempty = ""; struct shiptech_weap_s tbl_shiptech_weap[WEAPON_NUM] = { { /* NONE */ &game_str_st_none, &strspace, 0, 0, 0, 0, false, false, false, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0, 0 }, 0, 0 }, { /* NUCLEAR BOMB */ &game_str_tbl_st_weap[0], &game_str_tbl_st_weapx[0], 3, 12, 1, 0, false, true, false, 0, 1, 1, 10, 30, 40, 10, false, TECH_WEAP_LASERS, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* LASER */ &game_str_tbl_st_weap[1], &game_str_tbl_st_weapx[1], 1, 4, 1, 0, false, false, false, 0, 1, 1, -1, 30, 10, 25, false, TECH_WEAP_LASERS, 0, { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }, 0x7, 0 }, { /* NUCLEAR MISSILE */ &game_str_tbl_st_weap[2], &game_str_tbl_st_weapx[2], 4, 4, 6, 0, false, false, false, 0, 1, 1, 2, 70, 50, 20, false, TECH_WEAP_LASERS, 2, { 0x60, 0x0, 0x0, 0x6, 0x50, 0x0, 0x0 }, 0x8, 1 }, { /* NUCLEAR MISSILE */ &game_str_tbl_st_weap[3], &game_str_tbl_st_weapx[3], 4, 4, 4, 0, false, false, false, 0, 1, 1, 5, 105, 75, 30, false, TECH_WEAP_LASERS, 2, { 0x40, 0x0, 0x0, 0x6, 0x50, 0x0, 0x0 }, 0x8, 1 }, { /* HEAVY LASER */ &game_str_tbl_st_weap[4], &game_str_tbl_st_weapx[4], 1, 7, 2, 0, false, false, false, 0, 1, 1, -1, 90, 30, 75, false, TECH_WEAP_LASERS, 0, { 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46 }, 0xa, 0 }, { /* HYPER-V ROCKET */ &game_str_tbl_st_weap[5], &game_str_tbl_st_weapx[5], 6, 6, 7, 0, false, false, false, 0, 1, 1, 2, 90, 70, 20, false, TECH_WEAP_HYPER_V_ROCKETS, 2, { 0x70, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* HYPER-V ROCKET */ &game_str_tbl_st_weap[6], &game_str_tbl_st_weapx[6], 6, 6, 5, 0, false, false, false, 0, 1, 1, 5, 135, 105, 30, false, TECH_WEAP_HYPER_V_ROCKETS, 2, { 0x50, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* GATLING LASER */ &game_str_tbl_st_weap[7], &game_str_tbl_st_weapx[7], 1, 4, 1, 0, false, false, false, 0, 1, 4, -1, 90, 20, 70, false, TECH_WEAP_GATLING_LASER, 0, { 0x43, 0x41, 0x3f, 0x25, 0x3f, 0x41, 0x43 }, 0x1, 0 }, { /* NEUTRON PELLET GUN */ &game_str_tbl_st_weap[8], &game_str_tbl_st_weapx[8], 2, 5, 1, 0, true, false, false, 0, 1, 1, -1, 30, 15, 25, false, TECH_WEAP_NEUTRON_PELLET_GUN, 0, { 0x0, 0xae, 0x0, 0x0, 0x0, 0xae, 0x0 }, 0x1, 0 }, { /* HYPER-X ROCKET */ &game_str_tbl_st_weap[9], &game_str_tbl_st_weapx[9], 8, 8, 7, 1, false, false, false, 0, 1, 1, 2, 120, 100, 20, false, TECH_WEAP_HYPER_X_ROCKETS, 2, { 0x60, 0x0, 0x0, 0x6, 0x50, 0x0, 0x0 }, 0x8, 1 }, { /* HYPER-X ROCKET */ &game_str_tbl_st_weap[10], &game_str_tbl_st_weapx[10], 8, 8, 5, 1, false, false, false, 0, 1, 1, 5, 180, 150, 30, false, TECH_WEAP_HYPER_X_ROCKETS, 2, { 0x50, 0x0, 0x0, 0x6, 0x50, 0x0, 0x0 }, 0x8, 1 }, { /* FUSION BOMB */ &game_str_tbl_st_weap[11], &game_str_tbl_st_weapx[11], 5, 20, 1, 0, false, true, false, 0, 1, 1, 10, 30, 50, 10, false, TECH_WEAP_FUSION_BOMB, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* ION CANNON */ &game_str_tbl_st_weap[12], &game_str_tbl_st_weapx[12], 3, 8, 1, 0, false, false, false, 0, 1, 1, -1, 40, 15, 35, false, TECH_WEAP_ION_CANNON, 1, { 0xe4, 0xe5, 0xe6, 0xe7, 0xe6, 0xe5, 0xe4 }, 0x10, 0 }, { /* HEAVY ION CANNON */ &game_str_tbl_st_weap[13], &game_str_tbl_st_weapx[13], 3, 15, 2, 0, false, false, false, 0, 1, 1, -1, 110, 45, 105, false, TECH_WEAP_ION_CANNON, 1, { 0xe4, 0xe5, 0xe6, 0xe7, 0xe6, 0xe5, 0xe4 }, 0xf, 0 }, { /* SCATTER PACK V */ &game_str_tbl_st_weap[14], &game_str_tbl_st_weapx[14], 6, 6, 7, 1, false, false, false, 0, 1, 1, 2, 180, 115, 50, false, TECH_WEAP_SCATTER_PACK_V_ROCKETS, 2, { 0x60, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x3, 5 }, { /* SCATTER PACK V */ &game_str_tbl_st_weap[15], &game_str_tbl_st_weapx[15], 6, 6, 5, 1, false, false, false, 0, 1, 1, 5, 270, 170, 80, false, TECH_WEAP_SCATTER_PACK_V_ROCKETS, 2, { 0x50, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x3, 5 }, { /* DEATH SPORES */ &game_str_tbl_st_weap[16], &game_str_tbl_st_weapx[16], 1, 1, 1, 0, false, true, false, 0, 1, 1, 5, 100, 100, 10, true, TECH_PLAN_DEATH_SPORES, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* MASS DRIVER */ &game_str_tbl_st_weap[17], &game_str_tbl_st_weapx[17], 5, 8, 1, 0, true, false, false, 0, 1, 1, -1, 90, 55, 50, false, TECH_WEAP_MASS_DRIVER, 0, { 0x0, 0xc, 0x0, 0x0, 0x0, 0xc, 0x0 }, 0x17, 0 }, { /* MERCULITE MISSILE */ &game_str_tbl_st_weap[18], &game_str_tbl_st_weapx[18], 10, 10, 8, 2, false, false, false, 0, 1, 1, 2, 130, 105, 20, false, TECH_WEAP_MERCULITE_MISSILES, 2, { 0x80, 0x0, 0x0, 0x4, 0x78, 0x0, 0x0 }, 0x8, 1 }, { /* MERCULITE MISSILE */ &game_str_tbl_st_weap[19], &game_str_tbl_st_weapx[19], 10, 10, 6, 2, false, false, false, 0, 1, 1, 5, 195, 155, 30, false, TECH_WEAP_MERCULITE_MISSILES, 2, { 0x60, 0x0, 0x0, 0x4, 0x78, 0x0, 0x0 }, 0x8, 1 }, { /* NEUTRON BLASTER */ &game_str_tbl_st_weap[20], &game_str_tbl_st_weapx[20], 3, 12, 1, 0, false, false, false, 0, 1, 1, -1, 60, 20, 60, false, TECH_WEAP_NEUTRON_BLASTER, 0, { 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9 }, 0xa, 0 }, { /* HEAVY BLAST CANNON */ &game_str_tbl_st_weap[21], &game_str_tbl_st_weapx[21], 3, 24, 2, 0, false, false, false, 0, 1, 1, -1, 180, 60, 180, false, TECH_WEAP_NEUTRON_BLASTER, 0, { 0xcf, 0xce, 0xcd, 0xcc, 0xcb, 0xca, 0xc9 }, 0x12, 0 }, { /* ANTI-MATTER BOMB */ &game_str_tbl_st_weap[22], &game_str_tbl_st_weapx[22], 10, 40, 1, 0, false, true, false, 0, 1, 1, 10, 50, 75, 10, false, TECH_WEAP_ANTI_MATTER_BOMB, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* GRAVITON BEAM */ &game_str_tbl_st_weap[23], &game_str_tbl_st_weapx[23], 1, 15, 1, 0, false, false, false, 0, 1, 1, -1, 60, 20, 50, false, TECH_WEAP_GRAVITON_BEAM, 2, { 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7 }, 0x0, 1 }, { /* STINGER MISSILE */ &game_str_tbl_st_weap[24], &game_str_tbl_st_weapx[24], 15, 15, 9, 3, false, false, false, 0, 1, 1, 2, 190, 155, 30, false, TECH_WEAP_STINGER_MISSILES, 2, { 0x90, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* STINGER MISSILE */ &game_str_tbl_st_weap[25], &game_str_tbl_st_weapx[25], 15, 15, 7, 3, false, false, false, 0, 1, 1, 5, 270, 230, 45, false, TECH_WEAP_STINGER_MISSILES, 2, { 0x70, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* HARD BEAM */ &game_str_tbl_st_weap[26], &game_str_tbl_st_weapx[26], 8, 12, 1, 0, true, false, false, 0, 1, 1, -1, 120, 50, 100, false, TECH_WEAP_HARD_BEAM, 0, { 0xa1, 0x96, 0xa1, 0x96, 0xa1, 0x96, 0xa1 }, 0x1, 0 }, { /* FUSION BEAM */ &game_str_tbl_st_weap[27], &game_str_tbl_st_weapx[27], 4, 16, 1, 0, false, false, false, 0, 1, 1, -1, 70, 20, 75, false, TECH_WEAP_FUSION_BEAM, 0, { 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 }, 0xb, 0 }, { /* HEAVY FUSION BEAM */ &game_str_tbl_st_weap[28], &game_str_tbl_st_weapx[28], 4, 30, 2, 0, false, false, false, 0, 1, 1, -1, 210, 60, 225, false, TECH_WEAP_FUSION_BEAM, 0, { 0xb7, 0xb6, 0xb5, 0xb4, 0xb3, 0xb2, 0xb1 }, 0x19, 0 }, { /* OMEGA-V BOMB */ &game_str_tbl_st_weap[29], &game_str_tbl_st_weapx[29], 20, 50, 1, 0, false, true, false, 0, 1, 1, 10, 80, 140, 10, false, TECH_WEAP_OMEGA_V_BOMB, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* ANTI-MATTER TORP */ &game_str_tbl_st_weap[30], &game_str_tbl_st_weapx[30], 30, 30, 8, 4, false, false, false, 1, 1, 1, -1, 300, 75, 300, false, TECH_WEAP_ANTI_MATTER_TORPEDOES, 2, { 0x80, 0x0, 0x0, 0x3, 0xa0, 0x0, 0x0 }, 0x11, 1 }, { /* MEGABOLT CANNON */ &game_str_tbl_st_weap[31], &game_str_tbl_st_weapx[31], 2, 20, 1, 3, false, false, false, 0, 1, 1, -1, 80, 30, 65, false, TECH_WEAP_MEGABOLT_CANNON, 3, { 0xaf, 0xd7, 0xae, 0xd7, 0xaf, 0xd7, 0xae }, 0x12, 0 }, { /* PHASOR */ &game_str_tbl_st_weap[32], &game_str_tbl_st_weapx[32], 5, 20, 1, 0, false, false, false, 0, 1, 1, -1, 90, 20, 90, false, TECH_WEAP_PHASOR, 1, { 0xdb, 0xdc, 0xdd, 0xde, 0xdd, 0xdc, 0xdb }, 0x1c, 0 }, { /* HEAVY PHASOR */ &game_str_tbl_st_weap[33], &game_str_tbl_st_weapx[33], 5, 40, 2, 0, false, false, false, 0, 1, 1, -1, 260, 60, 270, false, TECH_WEAP_PHASOR, 1, { 0xdb, 0xdc, 0xdd, 0xde, 0xdd, 0xdc, 0xdb }, 0x1a, 0 }, { /* SCATTER PACK VII */ &game_str_tbl_st_weap[34], &game_str_tbl_st_weapx[34], 10, 10, 8, 2, false, false, false, 0, 1, 1, 2, 280, 170, 50, false, TECH_WEAP_SCATTER_PACK_VII_MISSILES, 2, { 0x80, 0x0, 0x0, 0x4, 0x78, 0x0, 0x0 }, 0x3, 7 }, { /* SCATTER PACK VII */ &game_str_tbl_st_weap[35], &game_str_tbl_st_weapx[35], 10, 10, 6, 2, false, false, false, 0, 1, 1, 5, 420, 230, 80, false, TECH_WEAP_SCATTER_PACK_VII_MISSILES, 2, { 0x60, 0x0, 0x0, 0x4, 0x78, 0x0, 0x0 }, 0x3, 7 }, { /* DOOM VIRUS */ &game_str_tbl_st_weap[36], &game_str_tbl_st_weapx[36], 2, 2, 1, 0, false, true, false, 0, 1, 1, 5, 150, 200, 10, true, TECH_PLAN_DOOM_VIRUS, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x25, 0 }, { /* AUTO BLASTER */ &game_str_tbl_st_weap[37], &game_str_tbl_st_weapx[37], 4, 16, 1, 0, false, false, false, 0, 1, 3, -1, 140, 30, 90, false, TECH_WEAP_AUTO_BLASTER, 1, { 0xbe, 0xbd, 0xbc, 0xbb, 0xba, 0xb9, 0xb8 }, 0x1, 0 }, { /* PULSON MISSILE */ &game_str_tbl_st_weap[38], &game_str_tbl_st_weapx[38], 20, 20, 10, 4, false, false, false, 0, 1, 1, 2, 200, 160, 40, false, TECH_WEAP_PULSON_MISSILES, 2, { 0xa0, 0x0, 0x0, 0x4, 0xa0, 0x0, 0x0 }, 0x8, 1 }, { /* PULSON MISSILE */ &game_str_tbl_st_weap[39], &game_str_tbl_st_weapx[39], 20, 20, 8, 4, false, false, false, 0, 1, 1, 5, 300, 240, 60, false, TECH_WEAP_PULSON_MISSILES, 2, { 0x80, 0x0, 0x0, 0x4, 0xa0, 0x0, 0x0 }, 0x8, 1 }, { /* TACHYON BEAM */ &game_str_tbl_st_weap[40], &game_str_tbl_st_weapx[40], 1, 25, 1, 0, false, false, false, 0, 1, 1, -1, 90, 30, 70, false, TECH_WEAP_TACHYON_BEAM, 2, { 0x8e, 0x8c, 0x8b, 0x8a, 0x89, 0x88, 0x87 }, 0x1f, 1 }, { /* GAUSS AUTOCANON */ &game_str_tbl_st_weap[41], &game_str_tbl_st_weapx[41], 7, 10, 1, 0, true, false, false, 0, 1, 4, -1, 280, 105, 105, false, TECH_WEAP_GAUSS_AUTOCANNON, 0, { 0x0, 0xf, 0x0, 0x12, 0x0, 0x15, 0x0 }, 0x1, 0 }, { /* PARTICLE BEAM */ &game_str_tbl_st_weap[42], &game_str_tbl_st_weapx[42], 10, 20, 1, 0, true, false, false, 0, 1, 1, -1, 150, 90, 75, false, TECH_WEAP_PARTICLE_BEAM, 0, { 0x0, 0xf, 0x0, 0x12, 0x0, 0x15, 0x0 }, 0x21, 0 }, { /* HERCULAR MISSILE */ &game_str_tbl_st_weap[43], &game_str_tbl_st_weapx[43], 25, 25, 10, 5, false, false, false, 0, 1, 1, 2, 260, 220, 40, false, TECH_WEAP_HERCULAR_MISSILES, 2, { 0xb0, 0x0, 0x0, 0x6, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* HERCULAR MISSILE */ &game_str_tbl_st_weap[44], &game_str_tbl_st_weapx[44], 25, 25, 9, 5, false, false, false, 0, 1, 1, 5, 390, 330, 60, false, TECH_WEAP_HERCULAR_MISSILES, 2, { 0x90, 0x0, 0x0, 0x6, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* PLASMA CANNON */ &game_str_tbl_st_weap[45], &game_str_tbl_st_weapx[45], 6, 30, 1, 0, false, false, false, 0, 1, 1, -1, 120, 30, 100, false, TECH_WEAP_PLASMA_CANNON, 2, { 0x46, 0x45, 0x44, 0x43, 0x44, 0x45, 0x46 }, 0x1e, 0 }, { /* DISRUPTOR */ &game_str_tbl_st_weap[46], &game_str_tbl_st_weapx[46], 10, 40, 2, 0, false, false, false, 0, 1, 1, -1, 210, 70, 160, false, TECH_WEAP_DISRUPTOR, 0, { 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1 }, 0x1c, 0 }, { /* PULSE PHASOR */ &game_str_tbl_st_weap[47], &game_str_tbl_st_weapx[47], 5, 20, 1, 0, false, false, false, 0, 1, 3, -1, 250, 40, 120, false, TECH_WEAP_PULSE_PHASOR, 1, { 0xdb, 0xdc, 0xdd, 0xde, 0xdd, 0xdc, 0xdb }, 0x1, 0 }, { /* NEUTRONIUM BOMB */ &game_str_tbl_st_weap[48], &game_str_tbl_st_weapx[48], 40, 70, 1, 0, false, true, false, 0, 1, 1, 10, 90, 200, 10, false, TECH_WEAP_NEUTRONIUM_BOMB, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x14, 0 }, { /* BIO TERMINATOR */ &game_str_tbl_st_weap[49], &game_str_tbl_st_weapx[49], 3, 3, 1, 0, false, true, false, 0, 1, 1, 5, 200, 300, 10, true, TECH_PLAN_BIO_TERMINATOR, 0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, 0x14, 0 }, { /* HELLFIRE TORPEDO */ &game_str_tbl_st_weap[50], &game_str_tbl_st_weapx[50], 25, 25, 10, 6, false, false, false, 2, 4, 1, -1, 500, 150, 350, false, TECH_WEAP_HELLFIRE_TORPEDOES, 2, { 0xa0, 0x0, 0x0, 0x4, 0x8c, 0x0, 0x0 }, 0x11, 1 }, { /* ZEON MISSILE */ &game_str_tbl_st_weap[51], &game_str_tbl_st_weapx[51], 30, 30, 9, 6, false, false, false, 0, 1, 1, 2, 300, 250, 50, false, TECH_WEAP_ZEON_MISSILES, 2, { 0xc0, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* ZEON MISSILE */ &game_str_tbl_st_weap[52], &game_str_tbl_st_weapx[52], 30, 30, 7, 6, false, false, false, 0, 1, 1, 5, 450, 375, 75, false, TECH_WEAP_ZEON_MISSILES, 2, { 0xa0, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x8, 1 }, { /* PROTON TORPEDO */ &game_str_tbl_st_weap[53], &game_str_tbl_st_weapx[53], 75, 75, 10, 6, false, false, false, 3, 1, 1, -1, 500, 100, 400, false, TECH_WEAP_PROTON_TORPEDOES, 2, { 0xff, 0x0, 0x0, 0x3, 0xc8, 0x0, 0x0 }, 0x11, 1 }, { /* SCATTER PACK X */ &game_str_tbl_st_weap[54], &game_str_tbl_st_weapx[54], 15, 15, 10, 3, false, false, false, 0, 1, 1, 2, 300, 250, 50, false, TECH_WEAP_SCATTER_PACK_X_MISSILES, 2, { 0x90, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x3, 10 }, { /* SCATTER PACK X */ &game_str_tbl_st_weap[55], &game_str_tbl_st_weapx[55], 15, 15, 10, 3, false, false, false, 0, 1, 1, 5, 450, 420, 80, false, TECH_WEAP_SCATTER_PACK_X_MISSILES, 2, { 0x70, 0x0, 0x0, 0x5, 0x64, 0x0, 0x0 }, 0x3, 10 }, { /* TRI-FOCUS PLASMA */ &game_str_tbl_st_weap[56], &game_str_tbl_st_weapx[56], 20, 50, 1, 0, false, false, false, 0, 1, 1, -1, 250, 70, 180, false, TECH_WEAP_TRI_FOCUS_PLASMA_CANNON, 1, { 0x46, 0x45, 0x44, 0x43, 0x44, 0x45, 0x46 }, 0x1b, 0 }, { /* STELLAR CONVERTER */ &game_str_tbl_st_weap[57], &game_str_tbl_st_weapx[57], 10, 35, 3, 0, false, false, false, 0, 4, 1, -1, 500, 200, 300, false, TECH_WEAP_STELLAR_CONVERTER, 3, { 0x49, 0x56, 0x71, 0x46, 0x49, 0x56, 0x71 }, 0x15, 0 }, { /* MAULER DEVICE */ &game_str_tbl_st_weap[58], &game_str_tbl_st_weapx[58], 20, 100, 1, 0, false, false, false, 0, 1, 1, -1, 550, 150, 300, false, TECH_WEAP_MAULER_DEVICE, 4, { 0xbb, 0xbc, 0xbd, 0xbd, 0xbd, 0xbc, 0xbb }, 0x23, 0 }, { /* PLASMA TORPEDO */ &game_str_tbl_st_weap[59], &game_str_tbl_st_weapx[59], 150, 150, 10, 7, false, false, true, 4, 1, 1, -1, 600, 150, 450, false, TECH_WEAP_PLASMA_TORPEDOES, 2, { 0xc0, 0x0, 0x0, 0x3, 0xa0, 0x0, 0x0 }, 0x11, 1 }, { /* CRYSTAL RAY */ &game_str_tbl_st_weap[60], &game_str_tbl_st_weapx[60], 100, 300, 3, 0, false, false, false, 0, 4, 1, -1, 600, 200, 400, false, 101, 3, { 0xe, 0xc7, 0xe, 0xe, 0xef, 0xe, 0xc7 }, 0x18, 0 }, { /* DEATH RAY */ &game_str_tbl_st_weap[61], &game_str_tbl_st_weapx[61], 200, 1000, 1, 0, false, false, false, 0, 1, 1, -1, 1000, 2000, 2000, false, TECH_WEAP_DEATH_RAY, 4, { 0xcb, 0xc5, 0xc4, 0x46, 0xc4, 0xc5, 0xcb }, 0x1d, 0 }, { /* AMEOBA STREAM */ &game_str_tbl_st_weap[62], &game_str_tbl_st_weapx[62], 250, 1000, 3, 0, false, false, false, 0, 1, 1, -1, 600, 200, 400, false, 101, 2, { 0x46, 0x46, 0xdc, 0xdc, 0xdc, 0xd3, 0xd3 }, 0xc, 1 } }; struct shiptech_comp_s tbl_shiptech_comp[SHIP_COMP_NUM] = { { &game_str_st_none, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0 }, { &game_str_tbl_st_comp[0], { 5, 10, 20, 100 }, { 5, 10, 20, 100 }, { 40, 200, 1000, 5000 }, 1, 1 }, { &game_str_tbl_st_comp[1], { 7, 15, 30, 150 }, { 7, 15, 30, 150 }, { 50, 240, 1200, 6000 }, 5, 2 }, { &game_str_tbl_st_comp[2], { 10, 20, 40, 200 }, { 10, 20, 40, 200 }, { 60, 280, 1400, 7000 }, 10, 3 }, { &game_str_tbl_st_comp[3], { 12, 25, 50, 250 }, { 12, 25, 50, 250 }, { 70, 320, 1600, 8000 }, 15, 4 }, { &game_str_tbl_st_comp[4], { 15, 30, 60, 300 }, { 15, 30, 60, 300 }, { 80, 360, 1800, 9000 }, 20, 5 }, { &game_str_tbl_st_comp[5], { 17, 35, 70, 350 }, { 17, 35, 70, 350 }, { 90, 400, 2000, 10000 }, 25, 6 }, { &game_str_tbl_st_comp[6], { 20, 40, 80, 400 }, { 20, 40, 80, 400 }, { 100, 440, 2200, 11000 }, 30, 7 }, { &game_str_tbl_st_comp[7], { 22, 45, 90, 450 }, { 22, 45, 90, 450 }, { 110, 480, 2400, 12000 }, 35, 8 }, { &game_str_tbl_st_comp[8], { 25, 50, 100, 500 }, { 25, 50, 100, 500 }, { 120, 520, 2600, 13000 }, 40, 9 }, { &game_str_tbl_st_comp[9], { 27, 55, 110, 550 }, { 27, 55, 110, 550 }, { 130, 560, 2800, 14000 }, 45, 10 }, { &game_str_tbl_st_comp[10], { 30, 60, 120, 600 }, { 30, 60, 120, 600 }, { 140, 600, 3000, 15000 }, 50, 11 } }; struct shiptech_engine_s tbl_shiptech_engine[SHIP_ENGINE_NUM] = { { &game_str_tbl_st_engine[0], 10, 10, 20, 1, 1 }, { &game_str_tbl_st_engine[1], 20, 18, 40, 2, 6 }, { &game_str_tbl_st_engine[2], 30, 26, 60, 3, 12 }, { &game_str_tbl_st_engine[3], 40, 33, 80, 4, 18 }, { &game_str_tbl_st_engine[4], 50, 36, 100, 5, 24 }, { &game_str_tbl_st_engine[5], 60, 40, 120, 6, 30 }, { &game_str_tbl_st_engine[6], 70, 44, 140, 7, 36 }, { &game_str_tbl_st_engine[7], 80, 47, 160, 8, 42 }, { &game_str_tbl_st_engine[8], 90, 50, 180, 9, 48 } }; struct shiptech_armor_s tbl_shiptech_armor[SHIP_ARMOR_NUM] = { { &game_str_tbl_st_armor[0], { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 100, 1 }, { &game_str_tbl_st_armor[1], { 20, 100, 500, 2500 }, { 20, 80, 400, 2000 }, 150, 1 }, { &game_str_tbl_st_armor[2], { 20, 100, 600, 3000 }, { 2, 10, 60, 300 }, 150, 10 }, { &game_str_tbl_st_armor[3], { 30, 150, 900, 4500 }, { 25, 85, 425, 2100 }, 225, 10 }, { &game_str_tbl_st_armor[4], { 40, 200, 1000, 5000 }, { 4, 20, 100, 500 }, 200, 17 }, { &game_str_tbl_st_armor[5], { 60, 300, 1500, 7500 }, { 30, 100, 500, 2500 }, 300, 17 }, { &game_str_tbl_st_armor[6], { 60, 300, 1500, 7500 }, { 6, 30, 150, 750 }, 250, 26 }, { &game_str_tbl_st_armor[7], { 90, 450, 2250, 11250 }, { 35, 115, 575, 2875 }, 375, 26 }, { &game_str_tbl_st_armor[8], { 80, 400, 2000, 10000 }, { 8, 40, 200, 1000 }, 300, 34 }, { &game_str_tbl_st_armor[9], { 120, 600, 3000, 15000 }, { 40, 130, 650, 3250 }, 450, 34 }, { &game_str_tbl_st_armor[10], { 100, 500, 2500, 12500 }, { 10, 50, 250, 1250 }, 350, 42 }, { &game_str_tbl_st_armor[11], { 150, 750, 3750, 18750 }, { 45, 150, 750, 3750 }, 525, 42 }, { &game_str_tbl_st_armor[12], { 120, 600, 3000, 15000 }, { 12, 60, 300, 1500 }, 400, 50 }, { &game_str_tbl_st_armor[13], { 180, 900, 4500, 25000 }, { 50, 175, 875, 4375 }, 600, 50 } }; struct shiptech_shield_s tbl_shiptech_shield[SHIP_SHIELD_NUM] = { { &game_str_st_none, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0 }, { &game_str_tbl_st_shield[0], { 30, 190, 1200, 7500 }, { 5, 20, 60, 250 }, { 5, 20, 60, 250 }, 1, 1 }, { &game_str_tbl_st_shield[1], { 35, 220, 1400, 8750 }, { 10, 35, 90, 375 }, { 10, 35, 90, 375 }, 2, 4 }, { &game_str_tbl_st_shield[2], { 40, 250, 1600, 10000 }, { 15, 50, 120, 500 }, { 15, 50, 120, 500 }, 3, 10 }, { &game_str_tbl_st_shield[3], { 45, 280, 1800, 11250 }, { 20, 65, 150, 675 }, { 20, 65, 150, 675 }, 4, 14 }, { &game_str_tbl_st_shield[4], { 50, 310, 2000, 12500 }, { 25, 80, 180, 750 }, { 25, 80, 180, 750 }, 5, 20 }, { &game_str_tbl_st_shield[5], { 55, 340, 2200, 13750 }, { 30, 95, 210, 875 }, { 30, 95, 210, 875 }, 6, 24 }, { &game_str_tbl_st_shield[6], { 60, 370, 2400, 15000 }, { 35, 110, 240, 1000 }, { 35, 110, 240, 1000 }, 7, 30 }, { &game_str_tbl_st_shield[7], { 65, 400, 2600, 16250 }, { 40, 125, 270, 1125 }, { 40, 125, 270, 1125 }, 9, 34 }, { &game_str_tbl_st_shield[8], { 70, 430, 2800, 17500 }, { 45, 140, 300, 1250 }, { 45, 140, 300, 1250 }, 11, 40 }, { &game_str_tbl_st_shield[9], { 80, 460, 3000, 18750 }, { 50, 155, 330, 1375 }, { 50, 155, 330, 1375 }, 13, 44 }, { &game_str_tbl_st_shield[10], { 90, 490, 3200, 20000 }, { 55, 160, 360, 1500 }, { 55, 160, 360, 1500 }, 15, 50 } /* { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } */ }; struct shiptech_jammer_s tbl_shiptech_jammer[SHIP_JAMMER_NUM] = { { &game_str_st_none, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0 }, { &game_str_tbl_st_jammer[0], { 10, 20, 40, 170 }, { 10, 20, 40, 170 }, { 25, 150, 1000, 6250 }, 2, 1 }, { &game_str_tbl_st_jammer[1], { 15, 30, 60, 250 }, { 15, 30, 60, 250 }, { 27, 165, 1100, 6875 }, 7, 2 }, { &game_str_tbl_st_jammer[2], { 20, 40, 80, 330 }, { 20, 40, 80, 330 }, { 30, 180, 1200, 7500 }, 12, 3 }, { &game_str_tbl_st_jammer[3], { 25, 50, 100, 410 }, { 25, 50, 100, 410 }, { 32, 195, 1300, 8125 }, 17, 4 }, { &game_str_tbl_st_jammer[4], { 30, 60, 120, 490 }, { 30, 60, 120, 490 }, { 35, 210, 1400, 8750 }, 22, 5 }, { &game_str_tbl_st_jammer[5], { 35, 70, 140, 570 }, { 35, 70, 140, 570 }, { 37, 225, 1500, 9375 }, 27, 6 }, { &game_str_tbl_st_jammer[6], { 40, 80, 160, 650 }, { 40, 80, 160, 650 }, { 40, 240, 1600, 10000 }, 32, 7 }, { &game_str_tbl_st_jammer[7], { 45, 90, 180, 730 }, { 45, 90, 180, 730 }, { 42, 255, 1700, 10625 }, 37, 8 }, { &game_str_tbl_st_jammer[8], { 50, 100, 200, 810 }, { 50, 100, 200, 810 }, { 45, 270, 1800, 11250 }, 42, 9 }, { &game_str_tbl_st_jammer[9], { 55, 110, 220, 900 }, { 55, 110, 220, 900 }, { 50, 285, 1900, 11875 }, 47, 10 } }; struct shiptech_special_s tbl_shiptech_special[SHIP_SPECIAL_NUM] = { { /* NONE */ &game_str_st_none, &strempty, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0 }, { /* RESERVE FUEL TANKS */ &game_str_tbl_st_special[0], &game_str_tbl_st_specialx[0], { 20, 100, 500, 2500 }, { 20, 100, 500, 2500 }, { 0, 0, 0, 0 }, TECH_CONS_RESERVE_FUEL_TANKS, TECH_FIELD_CONSTRUCTION, 1, 0, 0, 0, 0, 0, 0, 0 }, { /* STANDARD COLONY BASE */ &game_str_tbl_st_special[1], &game_str_tbl_st_specialx[1], { 3500, 3500, 3500, 3500 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_ECOLOGICAL_RESTORATION, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* BARREN COLONY BASE */ &game_str_tbl_st_special[2], &game_str_tbl_st_specialx[2], { 3750, 3750, 3750, 3750 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_BARREN_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* TUNDRA COLONY BASE */ &game_str_tbl_st_special[3], &game_str_tbl_st_specialx[3], { 4000, 4000, 4000, 4000 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_TUNDRA_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* DEAD COLONY BASE */ &game_str_tbl_st_special[4], &game_str_tbl_st_specialx[4], { 4250, 4250, 4250, 4250 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_DEAD_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* INFERNO COLONY BASE */ &game_str_tbl_st_special[5], &game_str_tbl_st_specialx[5], { 4500, 4500, 4500, 4500 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_INFERNO_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* TOXIC COLONY BASE */ &game_str_tbl_st_special[6], &game_str_tbl_st_specialx[6], { 4750, 4750, 4750, 4750 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_TOXIC_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* RADIATED COLONY BASE */ &game_str_tbl_st_special[7], &game_str_tbl_st_specialx[7], { 5000, 5000, 5000, 5000 }, { 700, 700, 700, 700 }, { 0, 0, 0, 0 }, TECH_PLAN_CONTROLLED_RADIATED_ENVIRONMENT, TECH_FIELD_PLANETOLOGY, 2, 0, 0, 0, 0, 0, 0, 0 }, { /* BATTLE SCANNER */ &game_str_tbl_st_special[8], &game_str_tbl_st_specialx[8], { 300, 300, 300, 300 }, { 50, 50, 50, 50 }, { 50, 50, 50, 50 }, TECH_COMP_BATTLE_SCANNER, TECH_FIELD_COMPUTER, 3, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_SCANNER) }, { /* ANTI-MISSILE ROCKETS */ &game_str_tbl_st_special[9], &game_str_tbl_st_specialx[9], { 100, 100, 100, 100 }, { 2, 10, 50, 250 }, { 8, 40, 200, 1000 }, TECH_WEAP_ANTI_MISSILE_ROCKETS, TECH_FIELD_WEAPON, 4, 0, 0, 40, 0, 0, 0, 0 }, { /* REPULSOR BEAM */ &game_str_tbl_st_special[10], &game_str_tbl_st_specialx[10], { 550, 550, 550, 550 }, { 100, 100, 100, 100 }, { 200, 200, 200, 200 }, TECH_FFLD_REPULSOR_BEAM, TECH_FIELD_FORCE_FIELD, 5, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_REPULSOR) }, { /* WARP DISSIPATOR */ &game_str_tbl_st_special[11], &game_str_tbl_st_specialx[11], { 650, 650, 650, 650 }, { 100, 100, 100, 100 }, { 300, 300, 300, 300 }, TECH_PROP_WARP_DISSIPATOR, TECH_FIELD_PROPULSION, 6, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_WARPDIS) }, { /* ENERGY PULSAR */ &game_str_tbl_st_special[12], &game_str_tbl_st_specialx[12], { 750, 750, 750, 750 }, { 150, 150, 150, 150 }, { 250, 250, 250, 250 }, TECH_PROP_ENERGY_PULSAR, TECH_FIELD_PROPULSION, 7, 0, 0, 0, 0, 1, 0, 0 }, { /* INERTIAL STABILIZER */ &game_str_tbl_st_special[13], &game_str_tbl_st_specialx[13], { 20, 75, 500, 2700 }, { 4, 20, 100, 500 }, { 8, 40, 200, 1000 }, TECH_PROP_INERTIAL_STABILIZER, TECH_FIELD_PROPULSION, 8, 0, 2, 0, 0, 0, 0, 0 }, { /* ZYRO SHIELD */ &game_str_tbl_st_special[14], &game_str_tbl_st_specialx[14], { 50, 100, 200, 300 }, { 4, 20, 100, 500 }, { 12, 60, 300, 1500 }, TECH_FFLD_ZYRO_SHIELD, TECH_FIELD_FORCE_FIELD, 4, 0, 0, 75, 0, 0, 0, 0 }, { /* AUTOMATED REPAIR */ &game_str_tbl_st_special[15], &game_str_tbl_st_specialx[15], { 2, 8, 50, 300 }, { 3, 15, 100, 600 }, { 3, 10, 50, 300 }, TECH_CONS_AUTOMATED_REPAIR_SYSTEM, TECH_FIELD_CONSTRUCTION, 9, 15, 0, 0, 0, 0, 0, 0 }, { /* STASIS FIELD */ &game_str_tbl_st_special[16], &game_str_tbl_st_specialx[16], { 2500, 2500, 2500, 2500 }, { 200, 200, 200, 200 }, { 275, 275, 275, 275 }, TECH_FFLD_STASIS_FIELD, TECH_FIELD_FORCE_FIELD, 10, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_STASIS) }, { /* CLOAKING DEVICE */ &game_str_tbl_st_special[17], &game_str_tbl_st_specialx[17], { 30, 150, 750, 3750 }, { 5, 25, 120, 600 }, { 10, 50, 250, 1250 }, TECH_FFLD_CLOAKING_DEVICE, TECH_FIELD_FORCE_FIELD, 11, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_CLOAK) }, { /* ION STREAM PROJECTOR */ &game_str_tbl_st_special[18], &game_str_tbl_st_specialx[18], { 1000, 1000, 1000, 1000 }, { 250, 250, 250, 250 }, { 500, 500, 500, 500 }, TECH_WEAP_ION_STREAM_PROJECTOR, TECH_FIELD_WEAPON, 12, 0, 0, 0, 0, 0, 1, 0 }, { /* HIGH ENERGY FOCUS */ &game_str_tbl_st_special[19], &game_str_tbl_st_specialx[19], { 30, 135, 625, 3500 }, { 35, 100, 150, 500 }, { 65, 200, 350, 1000 }, TECH_PROP_HIGH_ENERGY_FOCUS, TECH_FIELD_PROPULSION, 13, 0, 0, 0, 3, 0, 0, 0 }, { /* IONIC PULSAR */ &game_str_tbl_st_special[20], &game_str_tbl_st_specialx[20], { 1500, 1500, 1500, 1500 }, { 400, 400, 400, 400 }, { 750, 750, 750, 750 }, TECH_PROP_IONIC_PULSAR, TECH_FIELD_PROPULSION, 7, 0, 0, 0, 0, 2, 0, 0 }, { /* BLACK HOLE GENERATOR */ &game_str_tbl_st_special[21], &game_str_tbl_st_specialx[21], { 2750, 2750, 2750, 2750 }, { 750, 750, 750, 750 }, { 750, 750, 750, 750 }, TECH_FFLD_BLACK_HOLE_GENERATOR, TECH_FIELD_FORCE_FIELD, 14, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_BLACKHOLE) }, { /* SUB SPACE TELEPORTER */ &game_str_tbl_st_special[22], &game_str_tbl_st_specialx[22], { 25, 100, 450, 2250 }, { 4, 20, 100, 500 }, { 16, 80, 400, 2000 }, TECH_PROP_SUB_SPACE_TELEPORTER, TECH_FIELD_PROPULSION, 15, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_SUBSPACE) }, { /* LIGHTNING SHIELD */ &game_str_tbl_st_special[23], &game_str_tbl_st_specialx[23], { 200, 300, 400, 500 }, { 6, 30, 150, 750 }, { 15, 70, 350, 1750 }, TECH_FFLD_LIGHTNING_SHIELD, TECH_FIELD_FORCE_FIELD, 4, 0, 0, 100, 0, 0, 0, 0 }, { /* NEUTRON STREAM PROJECTOR */ &game_str_tbl_st_special[24], &game_str_tbl_st_specialx[24], { 2000, 2000, 2000, 2000 }, { 500, 500, 500, 500 }, { 1250, 1250, 1250, 1250 }, TECH_WEAP_NEUTRON_STREAM_PROJECTOR, TECH_FIELD_WEAPON, 16, 0, 0, 0, 0, 0, 2, 0 }, { /* ADV DAMAGE CONTROL */ &game_str_tbl_st_special[25], &game_str_tbl_st_specialx[25], { 40, 200, 1000, 5000 }, { 9, 45, 300, 1800 }, { 9, 30, 150, 450 }, TECH_CONS_ADVANCED_DAMAGE_CONTROL, TECH_FIELD_CONSTRUCTION, 9, 30, 0, 0, 0, 0, 0, 0 }, { /* TECHNOLOGY NULLIFIER */ &game_str_tbl_st_special[26], &game_str_tbl_st_specialx[26], { 3000, 3000, 3000, 3000 }, { 750, 750, 750, 750 }, { 1000, 1000, 1000, 1000 }, TECH_COMP_TECHNOLOGY_NULLIFIER, TECH_FIELD_COMPUTER, 17, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_TECHNULL) }, { /* INERTIAL NULLIFIER */ &game_str_tbl_st_special[27], &game_str_tbl_st_specialx[27], { 60, 200, 1500, 5000 }, { 6, 30, 150, 750 }, { 12, 60, 300, 1500 }, TECH_PROP_INERTIAL_NULLIFIER, TECH_FIELD_PROPULSION, 8, 0, 4, 0, 0, 0, 0, 0 }, { /* ORACLE INTERFACE */ &game_str_tbl_st_special[28], &game_str_tbl_st_specialx[28], { 30, 150, 600, 2750 }, { 8, 40, 200, 1000 }, { 12, 60, 300, 1500 }, TECH_COMP_ORACLE_INTERFACE, TECH_FIELD_COMPUTER, 20, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_ORACLE) }, { /* DISPLACMENT DEVICE */ &game_str_tbl_st_special[29], &game_str_tbl_st_specialx[29], { 30, 150, 300, 2750 }, { 10, 50, 225, 1250 }, { 10, 50, 225, 1250 }, TECH_PROP_DISPLACEMENT_DEVICE, TECH_FIELD_PROPULSION, 21, 0, 0, 0, 0, 0, 0, (1 << SHIP_SPECIAL_BOOL_DISP) } }; struct shiptech_hull_s tbl_shiptech_hull[SHIP_HULL_NUM] = { { &game_str_tbl_st_hull[0], 60, 40, 3, 2, 2 }, { &game_str_tbl_st_hull[1], 360, 200, 18, 15, 1 }, { &game_str_tbl_st_hull[2], 2000, 1000, 100, 100, 0 }, { &game_str_tbl_st_hull[3], 12000, 5000, 600, 700, -1 } }; 1oom-1.11.2/src/game/game_shiptech.h000066400000000000000000000220041476061725400171320ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_SHIPTECH_H #define INC_1OOM_GAME_SHIPTECH_H #include "game_types.h" #include "types.h" typedef enum { WEAPON_NONE = 0, WEAPON_NUCLEAR_BOMB, /*1*/ WEAPON_LASER, /*2*/ WEAPON_NUCLEAR_MISSILE_2, /*3*/ WEAPON_NUCLEAR_MISSILE_5, /*4*/ WEAPON_HEAVY_LASER, /*5*/ WEAPON_HYPER_V_ROCKET_2, /*6*/ WEAPON_HYPER_V_ROCKET_5, /*7*/ WEAPON_GATLING_LASER, /*8*/ WEAPON_NEUTRON_PELLET_GUN, /*9*/ WEAPON_HYPER_X_ROCKET_2, /*10*/ WEAPON_HYPER_X_ROCKET_5, /*11*/ WEAPON_FUSION_BOMB, /*12*/ WEAPON_ION_CANNON, /*13*/ WEAPON_HEAVY_ION_CANNON, /*14*/ WEAPON_SCATTER_PACK_V_2, /*15*/ WEAPON_SCATTER_PACK_V_5, /*16*/ WEAPON_DEATH_SPORES, /*17*/ WEAPON_MASS_DRIVER, /*18*/ WEAPON_MERCULITE_MISSILE_2, /*19*/ WEAPON_MERCULITE_MISSILE_5, /*20*/ WEAPON_NEUTRON_BLASTER, /*21*/ WEAPON_HEAVY_BLAST_CANNON, /*22*/ WEAPON_ANTI_MATTER_BOMB, /*23*/ WEAPON_GRAVITON_BEAM, /*24*/ WEAPON_STINGER_MISSILE_2, /*25*/ WEAPON_STINGER_MISSILE_5, /*26*/ WEAPON_HARD_BEAM, /*27*/ WEAPON_FUSION_BEAM, /*28*/ WEAPON_HEAVY_FUSION_BEAM, /*29*/ WEAPON_OMEGA_V_BOMB, /*30*/ WEAPON_ANTI_MATTER_TORP, /*31*/ WEAPON_MEGABOLT_CANNON, /*32*/ WEAPON_PHASOR, /*33*/ WEAPON_HEAVY_PHASOR, /*34*/ WEAPON_SCATTER_PACK_VII_2, /*35*/ WEAPON_SCATTER_PACK_VII_5, /*36*/ WEAPON_DOOM_VIRUS, /*37*/ WEAPON_AUTO_BLASTER, /*38*/ WEAPON_PULSON_MISSILE_2, /*39*/ WEAPON_PULSON_MISSILE_5, /*40*/ WEAPON_TACHYON_BEAM, /*41*/ WEAPON_GAUSS_AUTOCANON, /*42*/ WEAPON_PARTICLE_BEAM, /*43*/ WEAPON_HERCULAR_MISSILE_2, /*44*/ WEAPON_HERCULAR_MISSILE_5, /*45*/ WEAPON_PLASMA_CANNON, /*46*/ WEAPON_DISRUPTOR, /*47*/ WEAPON_PULSE_PHASOR, /*48*/ WEAPON_NEUTRONIUM_BOMB, /*49*/ WEAPON_BIO_TERMINATOR, /*50*/ WEAPON_HELLFIRE_TORPEDO, /*51*/ WEAPON_ZEON_MISSILE, /*52*/ WEAPON_ZEON_MISSILE_5, /*53*/ WEAPON_PROTON_TORPEDO, /*54*/ WEAPON_SCATTER_PACK_X_2, /*55*/ WEAPON_SCATTER_PACK_X_5, /*56*/ WEAPON_TRI_FOCUS_PLASMA, /*57*/ WEAPON_STELLAR_CONVERTER, /*58*/ WEAPON_MAULER_DEVICE, /*59*/ WEAPON_PLASMA_TORPEDO, /*60*/ WEAPON_CRYSTAL_RAY, /*61*/ WEAPON_DEATH_RAY, /*62*/ WEAPON_AMEOBA_STREAM, /*63*/ WEAPON_NUM /*64*/ } weapon_t; typedef enum { SHIP_COMP_NONE = 0, SHIP_COMP_MARK_I, /*1*/ SHIP_COMP_MARK_II, /*2*/ SHIP_COMP_MARK_III, /*3*/ SHIP_COMP_MARK_IV, /*4*/ SHIP_COMP_MARK_V, /*5*/ SHIP_COMP_MARK_VI, /*6*/ SHIP_COMP_MARK_VII, /*7*/ SHIP_COMP_MARK_VIII, /*8*/ SHIP_COMP_MARK_IX, /*9*/ SHIP_COMP_MARK_X, /*10*/ SHIP_COMP_MARK_XI, /*11*/ SHIP_COMP_NUM /*12*/ } ship_comp_t; typedef enum { SHIP_ENGINE_RETROS = 0, SHIP_ENGINE_NUCLEAR, /*1*/ SHIP_ENGINE_SUB_LIGHT, /*2*/ SHIP_ENGINE_FUSION, /*3*/ SHIP_ENGINE_IMPULSE, /*4*/ SHIP_ENGINE_ION, /*5*/ SHIP_ENGINE_ANTI_MATTER, /*6*/ SHIP_ENGINE_INTERPHASED, /*7*/ SHIP_ENGINE_HYPERTHRUST, /*8*/ SHIP_ENGINE_NUM /*9*/ } ship_engine_t; typedef enum { SHIP_ARMOR_TITANIUM = 0, SHIP_ARMOR_TITANIUM_II, /*1*/ SHIP_ARMOR_DURALLOY, /*2*/ SHIP_ARMOR_DURALLOY_II, /*3*/ SHIP_ARMOR_ZORTRIUM, /*4*/ SHIP_ARMOR_ZORTRIUM_II, /*5*/ SHIP_ARMOR_ANDRIUM, /*6*/ SHIP_ARMOR_ANDRIUM_II, /*7*/ SHIP_ARMOR_TRITANIUM, /*8*/ SHIP_ARMOR_TRITANIUM_II, /*9*/ SHIP_ARMOR_ADAMANTIUM, /*10*/ SHIP_ARMOR_ADAMANTIUM_II, /*11*/ SHIP_ARMOR_NEUTRONIUM, /*12*/ SHIP_ARMOR_NEUTRONIUM_II, /*13*/ SHIP_ARMOR_NUM /*14*/ } ship_armor_t; typedef enum { SHIP_SHIELD_NONE = 0, SHIP_SHIELD_CLASS_I, /*1*/ SHIP_SHIELD_CLASS_II, /*2*/ SHIP_SHIELD_CLASS_III, /*3*/ SHIP_SHIELD_CLASS_IV, /*4*/ SHIP_SHIELD_CLASS_V, /*5*/ SHIP_SHIELD_CLASS_VI, /*6*/ SHIP_SHIELD_CLASS_VII, /*7*/ SHIP_SHIELD_CLASS_IX, /*8*/ SHIP_SHIELD_CLASS_XI, /*9*/ SHIP_SHIELD_CLASS_XIII, /*10*/ SHIP_SHIELD_CLASS_XV, /*11*/ SHIP_SHIELD_NUM /*12*/ } ship_shield_t; typedef enum { SHIP_JAMMER_NONE = 0, SHIP_JAMMER_JAMMER_I, /*1*/ SHIP_JAMMER_JAMMER_II, /*2*/ SHIP_JAMMER_JAMMER_III, /*3*/ SHIP_JAMMER_JAMMER_IV, /*4*/ SHIP_JAMMER_JAMMER_V, /*5*/ SHIP_JAMMER_JAMMER_VI, /*6*/ SHIP_JAMMER_JAMMER_VII, /*7*/ SHIP_JAMMER_JAMMER_VIII, /*8*/ SHIP_JAMMER_JAMMER_IX, /*9*/ SHIP_JAMMER_JAMMER_X, /*10*/ SHIP_JAMMER_NUM /*11*/ } ship_jammer_t; typedef enum { SHIP_SPECIAL_NONE = 0, SHIP_SPECIAL_RESERVE_FUEL_TANKS, /*1*/ SHIP_SPECIAL_STANDARD_COLONY_BASE, /*2*/ SHIP_SPECIAL_BARREN_COLONY_BASE, /*3*/ SHIP_SPECIAL_TUNDRA_COLONY_BASE, /*4*/ SHIP_SPECIAL_DEAD_COLONY_BASE, /*5*/ SHIP_SPECIAL_INFERNO_COLONY_BASE, /*6*/ SHIP_SPECIAL_TOXIC_COLONY_BASE, /*7*/ SHIP_SPECIAL_RADIATED_COLONY_BASE, /*8*/ SHIP_SPECIAL_BATTLE_SCANNER, /*9*/ SHIP_SPECIAL_ANTI_MISSILE_ROCKETS, /*10*/ SHIP_SPECIAL_REPULSOR_BEAM, /*11*/ SHIP_SPECIAL_WARP_DISSIPATOR, /*12*/ SHIP_SPECIAL_ENERGY_PULSAR, /*13*/ SHIP_SPECIAL_INERTIAL_STABILIZER, /*14*/ SHIP_SPECIAL_ZYRO_SHIELD, /*15*/ SHIP_SPECIAL_AUTOMATED_REPAIR, /*16*/ SHIP_SPECIAL_STASIS_FIELD, /*17*/ SHIP_SPECIAL_CLOAKING_DEVICE, /*18*/ SHIP_SPECIAL_ION_STREAM_PROJECTOR, /*19*/ SHIP_SPECIAL_HIGH_ENERGY_FOCUS, /*20*/ SHIP_SPECIAL_IONIC_PULSAR, /*21*/ SHIP_SPECIAL_BLACK_HOLE_GENERATOR, /*22*/ SHIP_SPECIAL_SUB_SPACE_TELEPORTER, /*23*/ SHIP_SPECIAL_LIGHTNING_SHIELD, /*24*/ SHIP_SPECIAL_NEUTRON_STREAM_PROJECTOR, /*25*/ SHIP_SPECIAL_ADV_DAMAGE_CONTROL, /*26*/ SHIP_SPECIAL_TECHNOLOGY_NULLIFIER, /*27*/ SHIP_SPECIAL_INERTIAL_NULLIFIER, /*28*/ SHIP_SPECIAL_ORACLE_INTERFACE, /*29*/ SHIP_SPECIAL_DISPLACMENT_DEVICE, /*30*/ SHIP_SPECIAL_NUM /*31*/ } ship_special_t; typedef enum { SHIP_HULL_SMALL = 0, SHIP_HULL_MEDIUM, /*1*/ SHIP_HULL_LARGE, /*2*/ SHIP_HULL_HUGE, /*3*/ SHIP_HULL_NUM /*4*/ } ship_hull_t; struct shiptech_weap_s { char const * const * const nameptr; char const * const * const extratextptr; uint16_t damagemin; /* damagemax != damagemin means beam or bomb weapon */ uint16_t damagemax; uint8_t range; uint8_t extraacc; bool halveshield; bool is_bomb; bool damagefade; uint8_t misstype; uint8_t damagemul; uint8_t numfire; int8_t numshots; uint16_t cost; uint16_t space; uint16_t power; bool is_bio; uint8_t tech_i; uint8_t v24; /* beam: ? ; missile: fuel */ uint8_t dtbl[7]; /* beam: color table ; missile: 0=speed */ uint8_t sound; uint8_t nummiss; /* beam: streaming */ }; struct shiptech_comp_s { char const * const * const nameptr; uint16_t power[SHIP_HULL_NUM]; uint16_t space[SHIP_HULL_NUM]; uint16_t cost[SHIP_HULL_NUM]; uint8_t tech_i; uint8_t level; }; struct shiptech_jammer_s { char const * const * const nameptr; uint16_t power[SHIP_HULL_NUM]; uint16_t space[SHIP_HULL_NUM]; uint16_t cost[SHIP_HULL_NUM]; uint8_t tech_i; uint8_t level; }; struct shiptech_engine_s { char const * const * const nameptr; uint16_t power; uint16_t space; uint16_t cost; uint8_t warp; uint8_t tech_i; }; struct shiptech_armor_s { char const * const * const nameptr; uint16_t cost[SHIP_HULL_NUM]; uint16_t space[SHIP_HULL_NUM]; uint16_t armor; uint8_t tech_i; }; struct shiptech_shield_s { char const * const * const nameptr; uint16_t cost[SHIP_HULL_NUM]; uint16_t space[SHIP_HULL_NUM]; uint16_t power[SHIP_HULL_NUM]; uint8_t absorb; uint8_t tech_i; }; typedef enum { SHIP_SPECIAL_BOOL_SCANNER = 0, SHIP_SPECIAL_BOOL_REPULSOR, /*1*/ SHIP_SPECIAL_BOOL_WARPDIS, /*2*/ SHIP_SPECIAL_BOOL_STASIS, /*3*/ SHIP_SPECIAL_BOOL_CLOAK, /*4*/ SHIP_SPECIAL_BOOL_BLACKHOLE, /*5*/ SHIP_SPECIAL_BOOL_SUBSPACE, /*6*/ SHIP_SPECIAL_BOOL_TECHNULL, /*7*/ SHIP_SPECIAL_BOOL_ORACLE, /*8*/ SHIP_SPECIAL_BOOL_DISP /*9*/ } ship_special_bool_i_t; struct shiptech_special_s { char const * const * const nameptr; char const * const * const extratextptr; uint16_t cost[SHIP_HULL_NUM]; uint16_t space[SHIP_HULL_NUM]; uint16_t power[SHIP_HULL_NUM]; uint8_t tech_i; tech_field_t field; uint8_t type; uint8_t repair; uint8_t extraman; uint8_t misshield; uint8_t extrarange; uint8_t pulsar; uint8_t stream; uint16_t boolmask; }; struct shiptech_hull_s { char const * const * const nameptr; uint16_t cost; /* BC*10*/ uint16_t space; uint16_t hits; uint16_t power; int16_t defense; }; extern struct shiptech_weap_s tbl_shiptech_weap[WEAPON_NUM]; extern struct shiptech_comp_s tbl_shiptech_comp[SHIP_COMP_NUM]; extern struct shiptech_engine_s tbl_shiptech_engine[SHIP_ENGINE_NUM]; extern struct shiptech_armor_s tbl_shiptech_armor[SHIP_ARMOR_NUM]; extern struct shiptech_shield_s tbl_shiptech_shield[SHIP_SHIELD_NUM]; extern struct shiptech_jammer_s tbl_shiptech_jammer[SHIP_JAMMER_NUM]; extern struct shiptech_special_s tbl_shiptech_special[SHIP_SPECIAL_NUM]; extern struct shiptech_hull_s tbl_shiptech_hull[SHIP_HULL_NUM]; #endif 1oom-1.11.2/src/game/game_spy.c000066400000000000000000000701571476061725400161450ustar00rootroot00000000000000#include "config.h" #include "game_spy.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_diplo.h" #include "game_misc.h" #include "game_tech.h" #include "game_techtypes.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ static uint8_t game_spy_esp_get_group_tier(struct game_s *g, tech_group_t group, tech_field_t field, uint16_t len, const uint8_t *research_completed) { int v = 0; for (int i = 0; i < len; ++i) { uint8_t techi; tech_group_t group2; techi = research_completed[i]; group2 = game_tech_get_group(g->gaux, field, techi); if (group == group2) { v = game_tech_get_tier(g->gaux, field, techi); } } return v; } static void game_spy_esp_sift_useful_techs_do(struct game_s *g, struct spy_esp_s *s, tech_field_t field, int target_len, const uint8_t *target_research_completed, int spy_len, const uint8_t *spy_research_completed) { for (int i = 0; i < target_len; ++i) { uint8_t techi, tier; tech_group_t group; bool have_tech; techi = target_research_completed[i]; group = game_tech_get_group(g->gaux, field, techi); tier = game_tech_get_tier(g->gaux, field, techi); have_tech = false; for (int j = 0; j < spy_len; ++j) { if (spy_research_completed[j] == techi) { have_tech = true; break; } } if (0 || (group == TECH_GROUP_IMPROVED_ROBOTIC_CONTROLS) || (group == TECH_GROUP_SPACE_SCANNER) || (group == TECH_GROUP_REDUCED_INDUSTRIAL_WASTE) || (group == TECH_GROUP_IMPROVED_INDUSTRIAL_TECH) || (group == TECH_GROUP_PLANETARY_SHIELD) || (group == TECH_GROUP_IMPROVED_TERRAFORMING) || (group == TECH_GROUP_CONTROLLED_ENVIRONMENT) || (group == TECH_GROUP_ECO_RESTORATION) || (group == TECH_GROUP_PERSONAL_ARMOR) || (group == TECH_GROUP_PERSONAL_SHIELD) || (group == TECH_GROUP_FUEL_CELLS) || (group == TECH_GROUP_PERSONAL_WEAPONS) ) { if (game_spy_esp_get_group_tier(g, group, field, spy_len, spy_research_completed) >= tier) { have_tech = true; } } /*632ff*/ if (g->eto[s->spy].race == RACE_SILICOID) { if (0 || (group == TECH_GROUP_REDUCED_INDUSTRIAL_WASTE) || (group == TECH_GROUP_CONTROLLED_ENVIRONMENT) || (group == TECH_GROUP_ECO_RESTORATION) ) { have_tech = true; } } if (!have_tech) { s->tbl_techi[field][s->tbl_num[field]++] = techi; } } } static int game_spy_esp_get_value(struct game_s *g, tech_field_t field, uint8_t techi, player_id_t player_i) { const empiretechorbit_t *es = &(g->eto[player_i]); const shipresearch_t *srds = &(g->srd[player_i]); uint8_t maxtier = 0, maxti = 0; tech_group_t group = game_tech_get_group(g->gaux, field, techi); int v; if (group & 0x80) { return 0; } for (int i = 0; i < es->tech.completed[field]; ++i) { uint8_t tier2, ti; tech_group_t group2; ti = srds->researchcompleted[field][i]; group2 = game_tech_get_group(g->gaux, field, ti); tier2 = game_tech_get_tier(g->gaux, field, ti); if ((group2 == group) && (tier2 > maxtier)) { maxtier = tier2; maxti = ti; } } #if 0 /* BUG v is uninitialized and overwritten anyway */ /*62e63*/ switch (field) { case TECH_FIELD_COMPUTER: if (es->trait2 == TRAIT2_INDUSTRIALIST) { v += v / 6; } break; case TECH_FIELD_CONSTRUCTION: if (es->trait2 == TRAIT2_INDUSTRIALIST) { v += v / 4; } break; case TECH_FIELD_FORCE_FIELD: if (es->trait2 == TRAIT2_MILITARIST) { v += v / 4; } break; case TECH_FIELD_PLANETOLOGY: if (es->trait2 == TRAIT2_ECOLOGIST) { v += v / 4; } break; case TECH_FIELD_PROPULSION: if (es->trait2 == TRAIT2_EXPANSIONIST) { v += v / 4; } break; case TECH_FIELD_WEAPON: if (es->trait2 == TRAIT2_MILITARIST) { v += v / 4; } break; default: break; } #endif /*62f24*/ v = techi * techi; if (group == TECH_GROUP_SINGULAR) { v *= 10; } if (group == TECH_GROUP_IMPROVED_ROBOTIC_CONTROLS) { v *= 6; } if (group == TECH_GROUP_REDUCED_INDUSTRIAL_WASTE) { v *= 3; } if (group == TECH_GROUP_ECO_RESTORATION) { v *= 3; } if (maxti > techi) { v /= 4; } if (maxti == techi) { v = 0; } if (es->race == RACE_SILICOID) { if (0 || (group == TECH_GROUP_REDUCED_INDUSTRIAL_WASTE) || (group == TECH_GROUP_CONTROLLED_ENVIRONMENT) || (group == TECH_GROUP_ECO_RESTORATION) ) { v = 0; } } if ((field == TECH_FIELD_WEAPON) && (techi == TECH_WEAP_DEATH_RAY)) { v = 30000; } return v; } static void game_spy_esp_sub5(struct spy_esp_s *s, int r) { for (int i = 0; i < s->tnum; ++i) { if (s->tbl_tech2[i] > r) { --s->tnum; for (int j = 0; j < s->tnum; ++j) { s->tbl_field[j] = s->tbl_field[j + 1]; s->tbl_tech2[j] = s->tbl_tech2[j + 1]; } --i; } } } static player_id_t game_spy_frame_random(struct game_s *g, player_id_t spy, player_id_t target) { const empiretechorbit_t *et = &(g->eto[target]); player_id_t tbl_scapegoat[PLAYER_NUM]; int n = 0; for (player_id_t i = 0; i < PLAYER_NUM; ++i) { if ((i != spy) && (i != target) && BOOLVEC_IS1(et->contact, i)) { tbl_scapegoat[n++] = i; } } return (n == 0) ? PLAYER_NONE : tbl_scapegoat[rnd_0_nm1(n, &g->seed)]; } static void game_spy_espionage(struct game_s *g, player_id_t spy, player_id_t target, bool flag_frame, int spies, bool flag_any_caught, struct spy_turn_s *st) { struct spy_esp_s s[1]; empiretechorbit_t *et = &(g->eto[target]); int spied = spies, rmax = 0, tmax = 0; for (int i = 0; i < spies; ++i) { int r; r = rnd_1_n(100, &g->seed); SETMAX(rmax, r); } for (int i = 0; i < TECH_FIELD_NUM; ++i) { SETMAX(tmax, et->tech.percent[i]); } rmax = (rmax * tmax) / 100; if (spies > 0) { s->target = target; s->spy = spy; game_spy_esp_sub1(g, s, 0, 0); /*81f0a*/ game_spy_esp_sub5(s, rmax); SETMIN(spied, s->tnum); if (s->tnum > 0) { g->evn.stolen_spy[target][spy] = flag_any_caught ? spy : PLAYER_NONE; if (IS_HUMAN(g, spy)) { /*81fd3*/ int v = 0; st->tbl_rmax[target][spy] = rmax; g->evn.spied_num[target][spy] = spied; g->evn.spied_spy[target][spy] = flag_frame ? -1 : spy; for (int i = 0; i < 5; ++i) { v += rnd_1_n(12, &g->seed); } if ((!flag_frame) && flag_any_caught) { g->evn.spied_spy[target][spy] = v; } } else if (IS_HUMAN(g, target)) { /*81f35*/ g->evn.stolen_field[target][spy] = s->tbl_field[0]; g->evn.stolen_tech[target][spy] = s->tbl_tech2[0]; if (flag_frame) { g->evn.stolen_spy[target][spy] = game_spy_frame_random(g, spy, target); } /*81fa7*/ game_tech_get_new(g, spy, s->tbl_field[0], s->tbl_tech2[0], TECHSOURCE_AI_SPY, 0, PLAYER_NONE, false); } else { /*8207f*/ game_tech_get_new(g, spy, s->tbl_field[0], s->tbl_tech2[0], TECHSOURCE_AI_SPY, 0, PLAYER_NONE, false); if (flag_frame && (rnd_0_nm1(2, &g->seed) == 0)) { player_id_t scapegoat[PLAYER_NUM]; player_id_t pi; int n = 0; for (pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != target) && IS_HUMAN(g, pi) && IS_ALIVE(g, pi) && BOOLVEC_IS1(et->contact, pi)) { scapegoat[n++] = pi; } } if (n > 0) { pi = scapegoat[(n > 1) ? rnd_0_nm1(n, &g->seed) : 0]; game_diplo_act(g, -(rnd_1_n(20, &g->seed) + 20), pi, target, 5, 0, s->tbl_field[0]); } } } /*820e6*/ } } } static void game_spy_sabotage(struct game_s *g, player_id_t spy, player_id_t target, bool flag_frame, int spies, bool flag_any_caught) { int rcaught, v8 = 0, pl; bool flag_bases; rcaught = flag_any_caught ? (rnd_1_n(20, &g->seed) + 20) : 0; { int num; num = ((g->eto[spy].tech.percent[TECH_FIELD_WEAPON] + 9) * spies) / 10; for (int i = 0; i < num; ++i) { v8 += rnd_1_n(5, &g->seed); } } flag_bases = (rnd_0_nm1(2, &g->seed) != 0); pl = game_planet_get_random(g, target); /* WASBUG? used a function that returned 0 on no planets */ if ((v8 > 0) && (pl != PLANET_NONE)) { planet_t *p = &(g->planet[pl]); g->evn.sabotage_spy[target][spy] = rcaught ? spy : PLAYER_NONE; if (IS_HUMAN(g, spy)) { /*82431*/ g->evn.sabotage_num[target][spy] = v8; g->evn.sabotage_spy[target][spy] = flag_frame ? -1 : rcaught; } else if (IS_HUMAN(g, target)) { if (rnd_0_nm1(4, &g->seed) == 0) { v8 = (p->pop * (v8 / 2)) / 100; SETMAX(v8, 1); SETMIN(v8, p->pop); p->rebels += v8; SETMIN(p->rebels, p->pop); if (p->rebels >= (p->pop / 2)) { p->unrest = PLANET_UNREST_REBELLION; p->unrest_reported = false; p->rebels = p->pop; } } else { /*822f6*/ if (!flag_bases) { SETMIN(v8, p->factories); } else { /*82328*/ v8 /= 5; SETMIN(v8, p->missile_bases); } /*8235e*/ if (v8 > 0) { g->evn.sabotage_is_bases[target][spy] = flag_bases; g->evn.sabotage_planet[target][spy] = pl; g->evn.sabotage_num[target][spy] = v8; if (flag_frame) { g->evn.sabotage_spy[target][spy] = game_spy_frame_random(g, spy, target); } if (flag_bases) { p->missile_bases -= v8; } else { p->factories -= v8; } } } } else { /*8247a*/ if (!flag_bases) { SUBSAT0(p->factories, v8); } else { /*82328*/ v8 /= 5; SUBSAT0(p->missile_bases, v8); } if (!flag_frame) { game_diplo_act(g, -rcaught, spy, target, 6, pl, flag_bases); } else { player_id_t p2 = game_spy_frame_random(g, spy, target); if (p2 != PLAYER_NONE) { int r = -(rnd_1_n(16, &g->seed) + rnd_1_n(16, &g->seed)); game_diplo_act(g, -r, p2, target, 7, pl, flag_bases); } } } } } /* -------------------------------------------------------------------------- */ int game_spy_esp_sub1(struct game_s *g, struct spy_esp_s *s, int a4, int a6) { s->tnum = 0; game_spy_esp_sub2(g, s, a6); for (int loops = 0; (loops < 500) && (s->tnum < TECH_SPY_MAX); ++loops) { tech_field_t field; field = rnd_0_nm1(TECH_FIELD_NUM, &g->seed); if (s->tbl_num[field] > 0) { int value; bool have_tech; uint8_t techi; techi = s->tbl_techi[field][rnd_0_nm1(s->tbl_num[field], &g->seed)]; have_tech = false; for (int i = 0; i < s->tnum; ++i) { /*63495*/ if ((s->tbl_field[i] == field) && (s->tbl_tech2[i] == techi)) { have_tech = true; } } value = game_spy_esp_get_value(g, field, techi, s->spy); if ((value == 0) || (value < a4)) { have_tech = true; } if (!have_tech) { int i; i = s->tnum; s->tbl_field[i] = field; s->tbl_tech2[i] = techi; s->tbl_value[i] = value; s->tnum = i + 1; } } } return s->tnum; } int game_spy_esp_sub2(struct game_s *g, struct spy_esp_s *s, int a4) { const empiretechorbit_t *es = &(g->eto[s->spy]); const empiretechorbit_t *et = &(g->eto[s->target]); const shipresearch_t *srds = &(g->srd[s->spy]); const shipresearch_t *srdt = &(g->srd[s->target]); int sum = 0; for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { s->tbl_num[f] = 0; } for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { game_spy_esp_sift_useful_techs_do(g, s, f, et->tech.completed[f] - a4, srdt->researchcompleted[f], es->tech.completed[f], srds->researchcompleted[f]); } for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { sum += s->tbl_num[f]; } return sum; } void game_spy_build(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); int spycost_base; spycost_base = e->tech.percent[TECH_FIELD_COMPUTER] * 2 + 25; if (e->race == RACE_DARLOK) { spycost_base /= 2; } for (player_id_t j = PLAYER_0; j < g->players; ++j) { if ((i != j) && (e->spying[j] != 0)) { int spyfund, spycost; spyfund = (e->total_production_bc * e->spying[j]) / 1000 + e->spyfund[j]; spycost = spycost_base; /* WASBUG MOO1 does not reset spycost between target players */ while (spyfund >= spycost) { ++e->spies[j]; spyfund -= spycost; spycost *= 2; } e->spyfund[j] = spyfund; } } } } void game_spy_report(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = PLAYER_0; j < g->players; ++j) { if ((i != j) && (e->spies[j] > 0)) { uint16_t *ntbl = &(g->eto[j].tech.completed[0]); shipresearch_t *srd = &(g->srd[j]); e->spyreportyear[j] = g->year; for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { e->spyreportfield[j][f] = srd->researchcompleted[f][ntbl[f] - 1]; } } } } } void game_spy_turn(struct game_s *g, struct spy_turn_s *st) { bool have_planet[PLAYER_NUM]; int comptech1[PLAYER_NUM], comptech2[PLAYER_NUM]; memset(st, 0, sizeof(*st)); for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); have_planet[i] = false; for (int j = 0; j < g->galaxy_stars; ++j) { if (g->planet[j].owner == i) { have_planet[i] = true; break; } } comptech1[i] = e->tech.percent[TECH_FIELD_COMPUTER]; comptech2[i] = e->tech.percent[TECH_FIELD_COMPUTER]; if (e->race == RACE_DARLOK) { comptech1[i] += 20; comptech2[i] += 30; } for (player_id_t j = PLAYER_0; j < g->players; ++j) { g->evn.spies_caught[j][i] = 0; g->evn.spies_caught[i][j] = 0; g->evn.stolen_field[j][i] = 0; g->evn.stolen_field[i][j] = 0; g->evn.stolen_tech[j][i] = 0; g->evn.stolen_tech[i][j] = 0; g->evn.stolen_spy[j][i] = 0; g->evn.stolen_spy[i][j] = 0; g->evn.spied_num[j][i] = 0; g->evn.spied_num[i][j] = 0; g->evn.spied_spy[j][i] = 0; g->evn.spied_spy[i][j] = 0; g->evn.sabotage_is_bases[j][i] = 0; g->evn.sabotage_is_bases[i][j] = 0; g->evn.sabotage_num[j][i] = 0; g->evn.sabotage_num[i][j] = 0; g->evn.sabotage_spy[j][i] = 0; g->evn.sabotage_spy[i][j] = 0; } } /*8af1*/ for (player_id_t spy = PLAYER_0; spy < g->players; ++spy) { empiretechorbit_t *es = &(g->eto[spy]); for (player_id_t target = PLAYER_0; target < g->players; ++target) { empiretechorbit_t *et = &(g->eto[target]); int spies, dt1, dt2, numcaught, numsuccess, numfail; bool flag_frame, flag_any_caught; if ((spy == target) || (!have_planet[spy]) || (!have_planet[target])) { continue; } spies = es->spies[target]; dt1 = comptech2[spy] - comptech1[target]; dt2 = comptech1[target] - comptech2[spy]; SETMAX(dt1, 0); SETMAX(dt2, 0); dt2 += et->security / 5; if (es->spymode[target] == SPYMODE_HIDE) { dt1 += 30; } numcaught = numsuccess = numfail = 0; flag_frame = flag_any_caught = false; if (es->spymode[target] == SPYMODE_HIDE) { for (int i = 0; i < spies; ++i) { if ((rnd_1_n(100, &g->seed) + dt2) > 85) { ++numcaught; } } spies = 0; } else { /*8c30*/ for (int i = 0; i < spies; ++i) { int r; r = rnd_1_n(100, &g->seed) + dt2; if (r > 99) { numcaught = spies; numfail = spies; flag_any_caught = true; break; } else if (r > 70) { ++numcaught; ++numfail; flag_any_caught = true; } else if (r > 50) { ++numfail; flag_any_caught = true; } else if (r > 50) { /* BUG never true */ flag_any_caught = true; } } } /*8c9e*/ SUBSAT0(spies, numfail); SETMIN(numcaught, es->spies[target]); es->spies[target] -= numcaught; { int r = rnd_1_n(100, &g->seed) + dt1; if (r > 84) { numsuccess = spies; } if (r > 100) { flag_frame = true; } } g->evn.spies_caught[target][spy] = numcaught; if (es->spymode[target] == SPYMODE_ESPIONAGE) { game_spy_espionage(g, spy, target, flag_frame, numsuccess, flag_any_caught, st); } else if (es->spymode[target] == SPYMODE_SABOTAGE) { game_spy_sabotage(g, spy, target, flag_frame, numsuccess, flag_any_caught); } } } } void game_spy_esp_human(struct game_s *g, struct spy_turn_s *st) { /* FIXME refactor for multiplayer */ for (player_id_t spy = PLAYER_0; spy < g->players; ++spy) { struct spy_esp_s s[1]; g->evn.newtech[spy].num = 0; if (IS_AI(g, spy)) { continue; } s->spy = spy; for (player_id_t target = PLAYER_0; target < g->players; ++target) { if ((spy != target) && (g->evn.spied_num[target][spy] > 0)) { uint8_t tbl_tech[TECH_FIELD_NUM]; uint8_t flags_field; s->target = target; flags_field = 0; for (int i = 0; i < TECH_FIELD_NUM; ++i) { tbl_tech[i] = 0; } for (int loops = 0; loops < 5; ++loops) { int num; num = game_spy_esp_sub1(g, s, 0, 0); game_spy_esp_sub5(s, st->tbl_rmax[target][spy]); for (int i = 0; i < num; ++i) { int field; field = s->tbl_field[i]; if (tbl_tech[field] == 0) { tbl_tech[field] = s->tbl_tech2[i]; flags_field |= (1 << field); } } } if (flags_field != 0) { int field; field = ui_spy_steal(g, spy, target, flags_field); if ((field >= 0) && (field < TECH_FIELD_NUM)) { bool framed; uint8_t planet; planet = game_planet_get_random(g, target); framed = (g->evn.spied_spy[target][spy] == -1); g->evn.stolen_field[target][spy] = field; g->evn.stolen_tech[target][spy] = tbl_tech[field]; game_tech_get_new(g, spy, field, tbl_tech[field], TECHSOURCE_SPY, planet, target, framed); if (!framed) { game_diplo_act(g, -g->evn.spied_spy[target][spy], spy, target, 4, 0, field); } game_tech_finish_new(g, spy); ui_newtech(g, spy); g->evn.newtech[spy].num = 0; } } } } } for (player_id_t player = PLAYER_0; player < g->players; ++player) { uint16_t tbl[PLAYER_NUM]; int n; if (IS_AI(g, player)) { continue; } n = 0; for (player_id_t spy = PLAYER_0; spy < g->players; ++spy) { uint8_t tech; tech = g->evn.stolen_tech[player][spy]; if ((spy != player) && (tech != 0)) { tbl[n++] = ((((uint16_t)g->evn.stolen_spy[player][spy])) << 12) | ((((uint16_t)g->evn.stolen_field[player][spy])) << 8) | tech; } } for (int loops = 0; loops < n; ++loops) { for (int i = 0; i < n - 1; ++i) { uint16_t v0, v1; v0 = tbl[i]; v1 = tbl[i + 1]; if (v0 > v1) { tbl[i + 1] = v0; tbl[i] = v1; } } } for (int i = 0; i < n; ++i) { uint16_t v; v = tbl[i]; ui_spy_stolen(g, player, (v >> 12) & 7, (v >> 8) & 7, v & 0xff); } } } void game_spy_sab_human(struct game_s *g) { /* FIXME refactor for multiplayer */ for (player_id_t player = PLAYER_0; player < g->players; ++player) { if (IS_AI(g, player)) { continue; } for (player_id_t target = PLAYER_0; target < g->players; ++target) { int snum; snum = g->evn.sabotage_num[target][player]; if ((player != target) && (snum > 0)) { ui_sabotage_t act; uint8_t planet; planet_t *p; player_id_t other1, other2; act = ui_spy_sabotage_ask(g, player, target, &planet); g->evn.sabotage_planet[target][player] = planet; p = &(g->planet[planet]); /*ui_spy_sabotage_ask:*/ switch (act) { case UI_SABOTAGE_FACT: /*0*/ SETMIN(snum, p->factories); p->factories -= snum; break; case UI_SABOTAGE_BASES: /*1*/ { int n; n = 0; for (int i = 0; i < snum; ++i) { if (!rnd_0_nm1(4, &g->seed)) { ++n; } } snum = n; } SETMIN(snum, p->missile_bases); p->missile_bases -= snum; break; case UI_SABOTAGE_REVOLT: /*2*/ snum = (p->pop * snum) / 200; if (p->pop < snum) { snum = p->pop - p->rebels; } SETMAX(snum, 1); p->rebels += snum; if (p->rebels >= (p->pop / 2)) { p->unrest = PLANET_UNREST_REBELLION; p->unrest_reported = false; p->rebels = p->pop / 2; /* FIXME BUG? AI cheat? */ } break; case UI_SABOTAGE_NONE: /*-1*/ default: break; } other1 = PLAYER_NONE; other2 = PLAYER_NONE; if ((act != UI_SABOTAGE_NONE) && (act != UI_SABOTAGE_REVOLT)) { if (g->evn.spied_spy[target][player] != -1) { game_diplo_act(g, -g->evn.spied_spy[target][player], player, target, 6, planet, act); } else if ((snum != 0) && (act > UI_SABOTAGE_FACT)) { const empiretechorbit_t *et; et = &(g->eto[target]); for (int i = 0; (i < g->players) && (other2 == PLAYER_NONE); ++i) { if ((i != player) && BOOLVEC_IS1(et->contact, i)) { if (other1 == PLAYER_NONE) { other1 = i; } else { other2 = i; } } } if (other2 == PLAYER_NONE) { other1 = PLAYER_NONE; } } } if (act != UI_SABOTAGE_NONE) { int other; BOOLVEC_SET1(p->explored, player); g->seen[player][planet].owner = p->owner; g->seen[player][planet].pop = p->pop; g->seen[player][planet].bases = p->missile_bases; g->seen[player][planet].factories = p->factories; other = ui_spy_sabotage_done(g, player, player, target, act, other1, other2, planet, snum); if ((other2 != PLAYER_NONE) && (other != PLAYER_NONE)) { int v; v = -(rnd_1_n(12, &g->seed) + rnd_1_n(12, &g->seed)); game_diplo_act(g, v, other, target, 7, planet, act); } } } } } for (player_id_t player = PLAYER_0; player < g->players; ++player) { if (IS_AI(g, player)) { continue; } for (player_id_t spy = PLAYER_0; spy < g->players; ++spy) { int snum; snum = g->evn.sabotage_num[player][spy]; if ((player != spy) && (snum > 0)) { ui_sabotage_t act; uint8_t planet; int spy2; planet = g->evn.sabotage_planet[player][spy]; spy2 = g->evn.sabotage_spy[player][spy]; if (spy2 == -1) { spy2 = PLAYER_NONE; } act = g->evn.sabotage_is_bases[player][spy] ? UI_SABOTAGE_BASES : UI_SABOTAGE_FACT; ui_spy_sabotage_done(g, player, spy2, player, act, PLAYER_NONE, PLAYER_NONE, planet, snum); } } } } 1oom-1.11.2/src/game/game_spy.h000066400000000000000000000016161476061725400161440ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_SPY_H #define INC_1OOM_GAME_SPY_H #include "game_types.h" struct spy_turn_s { int tbl_rmax[PLAYER_NUM][PLAYER_NUM]; /* [target][spy] */ }; struct spy_esp_s { player_id_t target; player_id_t spy; int tnum; int tbl_num[TECH_FIELD_NUM]; uint8_t tbl_techi[TECH_FIELD_NUM][50]; tech_field_t tbl_field[TECH_SPY_MAX]; uint8_t tbl_tech2[TECH_SPY_MAX]; int tbl_value[TECH_SPY_MAX]; }; struct game_s; extern int game_spy_esp_sub1(struct game_s *g, struct spy_esp_s *s, int a4, int a6); extern int game_spy_esp_sub2(struct game_s *g, struct spy_esp_s *s, int a4); extern void game_spy_build(struct game_s *g); extern void game_spy_report(struct game_s *g); extern void game_spy_turn(struct game_s *g, struct spy_turn_s *st); extern void game_spy_esp_human(struct game_s *g, struct spy_turn_s *st); extern void game_spy_sab_human(struct game_s *g); #endif 1oom-1.11.2/src/game/game_stat.c000066400000000000000000000067261476061725400163060ustar00rootroot00000000000000#include "config.h" #include "game_stat.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_num.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int game_stat_fleet(const struct game_s *g, player_id_t pi) { const empiretechorbit_t *e = &(g->eto[pi]); const shipresearch_t *srd = &(g->srd[pi]); int v2, v4, va, ve = 0, sum; sum = 0; for (int i = 0; i < e->shipdesigns_num; ++i) { sum += srd->shipcount[i] * game_num_tbl_hull_w[srd->design[i].hull]; } SETMIN(sum, 0x319750); v4 = 0; va = 125; while (sum > va) { sum -= va; ++v4; ve = va; va <<= 1; } v2 = (sum * 10) / (va - ve) + v4 * 10; SETRANGE(v2, 0, 100); return v2; } int game_stat_tech(const struct game_s *g, player_id_t pi) { const uint8_t *p = g->eto[pi].tech.percent; int sum = 0; for (tech_field_t f = TECH_FIELD_COMPUTER; f < TECH_FIELD_NUM; ++f) { sum += p[f]; } return sum; } int game_stat_prod(const struct game_s *g, player_id_t pi) { uint32_t va, ve = 0, prod = g->eto[pi].total_production_bc; int si = 0; va = 100; while (prod > va) { prod -= va; ++si; ve = va; va <<= 1; } return (prod * 10) / (va - ve) + si * 10; } int game_stat_pop(const struct game_s *g, player_id_t pi) { int sum = 0, num = g->galaxy_stars; for (int i = 0; i < num; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { sum += p->pop; } } return sum / ((num * 3) / 2 + 1); } int game_stat_planets(const struct game_s *g, player_id_t pi) { int sum = 0, num = g->galaxy_stars; for (int i = 0; i < num; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == pi) { ++sum; } } return (sum * 100) / (num + 1); } void game_stats_all(struct game_s *g, player_id_t api, struct game_stats_s *d) { int sum[PLAYER_NUM]; game_update_production(g); game_update_empire_contact(g); game_update_maint_costs(g); d->num = 1; d->p[0] = api; for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != api) && BOOLVEC_IS1(g->eto[api].contact, pi)) { d->p[d->num++] = pi; } } for (int i = 0; i < d->num; ++i) { sum[i] = 0; } for (int s = 0; s < 5; ++s) { for (int i = 0; i < d->num; ++i) { player_id_t pi; int v; pi = d->p[i]; switch (s) { case 0: v = game_stat_fleet(g, pi); break; case 1: v = game_stat_tech(g, pi) / 3; break; case 2: v = game_stat_prod(g, pi); break; case 3: v = game_stat_pop(g, pi); break; case 4: v = game_stat_planets(g, pi); break; } SETRANGE(v, 0, 100); d->v[s][i] = v; sum[i] += v; } } { int maxstats = 0; for (int i = 0; i < d->num; ++i) { SETMAX(maxstats, sum[i]); } for (int i = 0; i < d->num; ++i) { d->v[5][i] = maxstats ? ((sum[i] * 100) / maxstats) : 100; } } } 1oom-1.11.2/src/game/game_stat.h000066400000000000000000000011721476061725400163010ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_STAT_H #define INC_1OOM_GAME_STAT_H #include "game_types.h" struct game_s; extern int game_stat_fleet(const struct game_s *g, player_id_t pi); extern int game_stat_tech(const struct game_s *g, player_id_t pi); extern int game_stat_prod(const struct game_s *g, player_id_t pi); extern int game_stat_pop(const struct game_s *g, player_id_t pi); extern int game_stat_planets(const struct game_s *g, player_id_t pi); struct game_stats_s { player_id_t p[PLAYER_NUM]; uint8_t v[6][PLAYER_NUM]; int num; }; extern void game_stats_all(struct game_s *g, player_id_t api, struct game_stats_s *d); #endif 1oom-1.11.2/src/game/game_str.c000066400000000000000000001127331476061725400161370ustar00rootroot00000000000000#include "config.h" #include "game_str.h" /* -------------------------------------------------------------------------- */ const char *game_str_mm_continue = "Continue"; const char *game_str_mm_load = "Load Game"; const char *game_str_mm_new = "New Game"; const char *game_str_mm_quit = "Quit to OS"; const char *game_str_tbl_race[RACE_NUM + 1] = { "Human", "Mrrshan", "Silicoid", "Sakkra", "Psilon", "Alkari", "Klackon", "Bulrathi", "Meklar", "Darlok", "Random" }; const char *game_str_tbl_races[RACE_NUM] = { "Humans", "Mrrshans", "Silicoids", "Sakkras", "Psilons", "Alkaris", "Klackons", "Bulrathis", "Meklars", "Darloks" }; const char *game_str_tbl_banner[BANNER_NUM + 1] = { "Blue", "Green", "Purple", "Red", "White", "Yellow", "Random" }; const char *game_str_tbl_gsize[GALAXY_SIZE_NUM] = { "Small", "Medium", "Large", "Huge" }; const char *game_str_tbl_diffic[DIFFICULTY_NUM] = { "Simple", "Easy", "Average", "Hard", "Impossible" }; const char *game_str_tbl_oppon[5] = { "One", "Two", "Three", "Four", "Five" }; const char *game_str_tbl_traits[RACE_NUM * 3] = { "EXPERT TRADERS", "AND MAGNIFICENT", "DIPLOMATS", "SUPERIOR GUNNERS", "", "", "IMMUNE TO", "HOSTILE PLANET", "ENVIRONMENTS", "INCREASED", "POPULATION", "GROWTH", "SUPERIOR", "RESEARCH", "TECHNIQUES", "SUPERIOR PILOTS", "", "", "INCREASED", "WORKER", "PRODUCTION", "TERRIFIC GROUND", "FIGHTERS", "", "ENHANCED", "FACTORY", "CONTROLS", "SUPREME SPIES", "", "" }; const char *game_str_tbl_trait1[TRAIT1_NUM] = { "Xenophobic", "Ruthless", "Aggressive", "Erratic", "Honorable", "Pacifistic" }; const char *game_str_tbl_trait2[TRAIT2_NUM] = { "Diplomat", "Militarist", "Expansionist", "Technologist", "Industrialist", "Ecologist" }; const char *game_str_ng_choose_race = "Choose Race"; const char *game_str_ng_choose_banner = "Choose Banner"; const char *game_str_ng_your_name = "Your Name..."; const char *game_str_ng_home_name = "Home World..."; const char *game_str_ng_ai = "AI"; const char *game_str_ng_computer = "Computer"; const char *game_str_ng_player = "Player"; const char *game_str_ng_cancel = "Cancel"; const char *game_str_ng_ok = "Start Game"; const char *game_str_ng_allai = "Must have at least one human player!"; const char *game_str_tbl_planet_names[PLANET_NAMES_MAX] = { "Paranar", "Denubius", "Antares", "Draconis", "Zoctan", "Rigel", "Talas", "Moro", "Quayal", "Neptunus", "Jinga", "Argus", "Escalon", "Berel", "Collassa", "Whynil", "Nordia", "Tau Cygni", "Phyco", "Firma", "Keeta", "Arietis", "Rhilus", "Willow", "Mu Delphi", "Stalaz", "Gorra", "Beta Ceti", "Spica", "Omicron", "Rha", "Kailis", "Vulcan", "Centauri", "Herculis", "Endoria", "Kulthos", "Hyboria", "Zhardan", "Yarrow", "Incedius", "Paladia", "Romulas", "Galos", "Uxmai", "Thrax", "Laan", "Imra", "Selia", "Seidon", "Tao", "Rana", "Vox", "Maalor", "Xudax", "Helos", "Crypto", "Gion", "Phantos", "Reticuli", "Maretta", "Toranor", "Exis", "Tyr", "Ajax", "Obaca", "Dolz", "Drakka", "Ryoun", "Vega", "Anraq", "Gienah", "Rotan", "Proxima", "Mobas", "Iranha", "Celtsi", "Dunatis", "Morrig", "Primodius", "Nyarl", "Ukko", "Crius", "Hyades", "Kronos", "Guradas", "Rayden", "Kakata", "Misha", "Xendalla", "Artemis", "Aurora", "Proteus", "Esper", "Darrian", "Trax", "Xengara", "Nitzer", "Simius", "Bootis", "Pollus", "Cygni", "Aquilae", "Volantis", "Tauri", "Regulus", "Klystron", "Lyae", "Capella", "Alcor" }; const char *game_str_tbl_home_names[RACE_NUM + 1] = { "Sol", "Fierias", "Cryslon", "Sssla", "Mentar", "Altair", "Kholdan", "Ursa", "Meklon", "Nazin", "Randomia" }; const char *game_str_rndempname = "Mr Random"; const char *game_str_planet_name_orion = "Orion"; const char *game_str_tbl_stship_names[NUM_SHIPDESIGNS] = { "SCOUT", "FIGHTER", "DESTROYER", "BOMBER", "COLONY SHIP", "NONE" }; const char *game_str_tbl_copyprotection_ship_names[40] = { "Paladin", "Marauder", "Gladiator", "Devastator", "Cutlass", "Sky Hawk", "Shark", "Dark Star", "Cyclops", "Panther", "Corvette", "Penetrator", "Punisher", "Black Widow", "Destroyer", "Warbird", "Piranha", "Banshee", "Hydra", "Cheetah", "Dreadstar", "Foxbat", "Hunter", "Hornet", "Star Blazer", "Knight", "Kraken", "Avenger", "Manta", "Warcat", "Escort", "Nemesis", "Warbear", "Scorpion", "Seeker", "Condor", "Sun Fire", "Viper", "Titan", "Lynx" }; const char *game_str_tbl_monsh_names[MONSTER_NUM] = { "SPACE CRYSTAL", "SPACE AMOEBA", "GUARDIAN" }; const char *game_str_tbl_mon_names[MONSTER_NUM] = { "Space Crystal", "Space Amoeba", "Guardian" }; const char *game_str_ai_colonyship = "COLONY SHIP"; const char *game_str_st_none = "NONE"; const char *game_str_st_none2 = "None"; const char *game_str_tbl_st_weap[WEAPON_NUM - 1] = { "NUCLEAR BOMB", "LASER", "NUCLEAR MISSILE", "NUCLEAR MISSILE", "HEAVY LASER", "HYPER-V ROCKET", "HYPER-V ROCKET", "GATLING LASER", "NEUTRON PELLET GUN", "HYPER-X ROCKET", "HYPER-X ROCKET", "FUSION BOMB", "ION CANNON", "HEAVY ION CANNON", "SCATTER PACK V", "SCATTER PACK V", "DEATH SPORES", "MASS DRIVER", "MERCULITE MISSILE", "MERCULITE MISSILE", "NEUTRON BLASTER", "HEAVY BLAST CANNON", "ANTI-MATTER BOMB", "GRAVITON BEAM", "STINGER MISSILE", "STINGER MISSILE", "HARD BEAM", "FUSION BEAM", "HEAVY FUSION BEAM", "OMEGA-V BOMB", "ANTI-MATTER TORP", "MEGABOLT CANNON", "PHASOR", "HEAVY PHASOR", "SCATTER PACK VII", "SCATTER PACK VII", "DOOM VIRUS", "AUTO BLASTER", "PULSON MISSILE", "PULSON MISSILE", "TACHYON BEAM", "GAUSS AUTOCANNON", "PARTICLE BEAM", "HERCULAR MISSILE", "HERCULAR MISSILE", "PLASMA CANNON", "DISRUPTOR", "PULSE PHASOR", "NEUTRONIUM BOMB", "BIO TERMINATOR", "HELLFIRE TORPEDO", "ZEON MISSILE", "ZEON MISSILE", "PROTON TORPEDO", "SCATTER PACK X", "SCATTER PACK X", "TRI-FOCUS PLASMA", "STELLAR CONVERTER", "MAULER DEVICE", "PLASMA TORPEDO", "CRYSTAL RAY", "DEATH RAY", "AMEOBA STREAM" }; const char *game_str_tbl_st_weapx[WEAPON_NUM - 1] = { "GROUND ATTACKS ONLY", " ", "2 SHOTS, +1 SPEED", "5 SHOTS", " ", "2 SHOTS, +1 SPEED", "5 SHOTS", "FIRES 4 TIMES/TURN ", "HALVES ENEMY SHIELDS", "2 SHOTS, +1 TO HIT", "5 SHOTS, +1 TO HIT", "GROUND ATTACKS ONLY ", " ", " ", "2 SHOTS, MIRVS TO 5", "5 SHOTS, MIRVS TO 5", "BIOLOGICAL WEAPON", "HALVES ENEMY SHIELDS", "2 SHOTS, +2 TO HIT", "5 SHOTS, +2 TO HIT", " ", " ", "GROUND ATTACKS ONLY", "STREAMING ATTACK", "2 SHOTS, +3 TO HIT", "5 SHOTS, +3 TO HIT", "HALVES SHIELD STR", " ", " ", "GROUND ATTACKS ONLY ", "FIRES ONE PER 2 TURNS", "+3 LEVELS TO HIT", " ", " ", "2 SHOTS, MIRVS TO 7", "5 SHOTS, MIRVS TO 7", "BIOLOGICAL WEAPON", "FIRES 3 TIMES/TURN", "2 SHOTS, +4 TO HIT", "5 SHOTS, +4 TO HIT", "STREAMING ATTACK", "1/2 SHIELDS, FIRES 4$", "HALVES SHIELDS STR", "2 SHOTS, +5 TO HIT", "5 SHOTS, +5 TO HIT", " ", " ", "FIRES 3 TIMES/TURN", "GROUND ATTACKS ONLY", "BIOLOGICAL WEAPON", "HITS ALL FOUR SHIELDS", "2 SHOTS, +6 TO HIT", "5 SHOTS, +6 TO HIT", "FIRES ONE PER 2 TURNS", "2 SHOTS, MIRVS TO 10", "5 SHOTS, MIRVS TO 10", " ", "HITS ALL FOUR SHIELDS", "CRUEL BRUTAL DAMAGE", "LOSES 15 DAMAGE/HEX", "", "", "" }; const char *game_str_tbl_st_comp[SHIP_COMP_NUM - 1] = { "MARK I", "MARK II", "MARK III", "MARK IV", "MARK V", "MARK VI", "MARK VII", "MARK VIII", "MARK IX", "MARK X", "MARK XI" }; const char *game_str_tbl_st_engine[SHIP_ENGINE_NUM] = { "RETROS", "NUCLEAR", "SUB-LIGHT", "FUSION", "IMPULSE", "ION", "ANTI-MATTER", "INTERPHASED", "HYPERTHRUST" }; const char *game_str_tbl_st_armor[SHIP_ARMOR_NUM] = { "TITANIUM", "TITANIUM II", "DURALLOY", "DURALLOY II", "ZORTRIUM", "ZORTRIUM II", "ANDRIUM", "ANDRIUM II", "TRITANIUM", "TRITANIUM II", "ADAMANTIUM", "ADAMANTIUM II", "NEUTRONIUM", "NEUTRONIUM II" }; const char *game_str_tbl_st_shield[SHIP_SHIELD_NUM - 1] = { "CLASS I", "CLASS II", "CLASS III", "CLASS IV", "CLASS V", "CLASS VI", "CLASS VII", "CLASS IX", "CLASS XI", "CLASS XIII", "CLASS XV" }; const char *game_str_tbl_st_jammer[SHIP_JAMMER_NUM - 1] = { "JAMMER I", "JAMMER II", "JAMMER III", "JAMMER IV", "JAMMER V", "JAMMER VI", "JAMMER VII", "JAMMER VIII", "JAMMER IX", "JAMMER X" }; const char *game_str_tbl_st_specsh[SHIP_SPECIAL_NUM] = { "NO SPECIALS", "RESERVE TANKS", "COLONY BASE", "BARREN BASE", "TUNDRA BASE", "DEAD BASE", "INFERNO BASE", "TOXIC BASE", "RADIATED BASE", "BATTLE SCANNER", "ANTI-MISSILES", "REPULSOR BEAM", "WARP DISSIPATOR", "ENERGY PULSAR", "INERT STABILIZER", "ZYRO SHIELD", "AUTO REPAIR", "STASIS FIELD", "CLOAKING DEVICE", "ION STREAM", "H-ENERGY FOCUS", "IONIC PULSAR", "BLACK HOLE GEN", "TELEPORTER", "LIGHTNING SHIELD", "NEUTRON STREAM", "ADV DMG CONTROL", "TECH NULLIFIER", "INERT. NULLIFIER", "ORACLE INTERFACE", "DISPLACE DEVICE" }; const char *game_str_tbl_st_special[SHIP_SPECIAL_NUM - 1] = { "RESERVE FUEL TANKS", "STANDARD COLONY BASE", "BARREN COLONY BASE", "TUNDRA COLONY BASE", "DEAD COLONY BASE", "INFERNO COLONY BASE", "TOXIC COLONY BASE", "RADIATED COLONY BASE", "BATTLE SCANNER", "ANTI-MISSILE ROCKETS", "REPULSOR BEAM", "WARP DISSIPATOR", "ENERGY PULSAR", "INERTIAL STABILIZER", "ZYRO SHIELD", "AUTOMATED REPAIR", "STASIS FIELD", "CLOAKING DEVICE", "ION STREAM PROJECTOR", "HIGH ENERGY FOCUS", "IONIC PULSAR", "BLACK HOLE GENERATOR", "SUB SPACE TELEPORTER", "LIGHTNING SHIELD", "NEUTRON STREAM PROJECTOR", "ADV DAMAGE CONTROL", "TECHNOLOGY NULLIFIER", "INERTIAL NULLIFIER", "ORACLE INTERFACE", "DISPLACMENT DEVICE" }; const char *game_str_tbl_st_specialx[SHIP_SPECIAL_NUM - 1] = { "EXTENDS SHIP RANGE BY 3 PARSECS", "ALLOWS NORMAL PLANET LANDINGS", "ALLOWS BARREN PLANET LANDINGS", "ALLOWS TUNDRA PLANET LANDINGS", "ALLOWS DEAD PLANET LANDINGS", "ALLOWS INFERNO PLANET LANDINGS", "ALLOWS TOXIC PLANET LANDINGS", "ALLOWS RADIATED PLANET LANDINGS", "DISPLAYS ENEMY SHIP STATS", "40% CHANCE MISSILES DESTROYED", "MOVES ENEMY SHIPS BACK 1 SPACE", "REDUCES SPEED OF ENEMY SHIPS", "EXPANDS TO INFLICT 1-5 HITS", "ADDS +2 TO MANEUVERABILITY", "75% CHANCE MISSILES DESTROYED", "HEALS 15% OF SHIP'S HITS A TURN", "ENEMY FROZEN FOR 1 TURN", "RENDERS SHIPS NEARLY INVISIBLE", "REDUCES ENEMY ARMOR BY 20%", "INCREASES WEAPON RANGES BY 3", "EXPANDS TO INFLICT 2-10 HITS", "KILLS 25%-100% OF ENEMY SHIPS", "TELEPORTS SHIP IN COMBAT", "100% CHANCE MISSILES DESTROYED", "REDUCES ENEMY ARMOR BY 40%", "HEALS 30% OF SHIP'S HITS A TURN", "DESTROYS ENEMY COMPUTERS", "ADDS +4 TO MANEUVERABILITY", "CONCENTRATES BEAM ATTACKS", "1/3 OF ALL ENEMY ATTACKS MISS" }; const char *game_str_tbl_st_hull[SHIP_HULL_NUM] = { "SMALL", "MEDIUM", "LARGE", "HUGE" }; const char *game_str_sm_crystal = "CRYSTAL"; const char *game_str_sm_amoeba = "AMOEBA"; const char *game_str_sm_game = "Game"; const char *game_str_sm_design = "Design"; const char *game_str_sm_fleet = "Fleet"; const char *game_str_sm_map = "Map"; const char *game_str_sm_races = "Races"; const char *game_str_sm_planets = "Planets"; const char *game_str_sm_tech = "Tech"; const char *game_str_sm_next_turn = "Next Turn"; const char *game_str_tbl_sm_stinfo[STAR_TYPE_NUM] = { "Yellow stars offer the best chance of discovering terran and sub-terran planets.", "Red stars are old, dull stars that commonly have poor planets.", "Green stars are moderately bright and have a wide range of planetary types.", "White stars burn incredibly hot and generally have hostile planets.", "Blue stars are relatively young stars with mineral rich lifeless planets.", "Neutron stars are rare and offer the greatest chance of finding rich planets." }; const char *game_str_sm_range = "Range"; const char *game_str_sm_parsec = "Parsec"; const char *game_str_sm_parsecs = "Parsecs"; const char *game_str_sm_parsecs2 = "PARSECS"; const char *game_str_sm_colony = "Colony"; const char *game_str_sm_lastrep = "Last Reported As A"; const char *game_str_sm_stargate = "STAR GATE"; const char *game_str_sm_prodnone = "NONE"; const char *game_str_sm_prod_y = "Y"; const char *game_str_sm_defupg = "UPGRD"; const char *game_str_sm_defshld = "SHIELD"; const char *game_str_sm_refit = "REFIT"; const char *game_str_sm_irc[] = { "IRC II", "IRC III", "IRC IV", "IRC V", "IRC VI", "IRC VII" }; const char *game_str_sm_indmax = "MAX"; const char *game_str_sm_indres = "RESERV"; const char *game_str_sm_ecowaste = "WASTE"; const char *game_str_sm_ecoclean = "CLEAN"; const char *game_str_sm_ecoatmos = "ATMOS"; const char *game_str_sm_ecotform = "T-FORM"; const char *game_str_sm_ecosoil = "SOIL"; const char *game_str_sm_ecogaia = "GAIA"; const char *game_str_sm_ecopop = "POP"; const char *game_str_sm_unexplored = "UNEXPLORED"; const char *game_str_sm_nohabit = "NO HABITABLE"; const char *game_str_sm__planets = "PLANETS"; const char *game_str_tbl_sm_pltype[PLANET_TYPE_NUM + 1] = { "NO HABITABLE PLANETS", "RADIATED", "TOXIC", "INFERNO", "DEAD", "TUNDRA", "BARREN", "MINIMAL", "DESERT", "STEPPE", "ARID", "OCEAN", "JUNGLE", "TERRAN", "GAIA" }; const char *game_str_sm_plague = "Plague"; const char *game_str_sm_nova = "Nova"; const char *game_str_sm_comet = "Comet"; const char *game_str_sm_pirates = "Pirates"; const char *game_str_sm_rebellion = "Rebellion"; const char *game_str_sm_unrest = "UNREST"; const char *game_str_sm_accident = "Accident"; const char *game_str_tbl_sm_pgrowth[PLANET_GROWTH_NUM] = { "HOSTILE", " ", "FERTILE", "GAIA" }; const char *game_str_tbl_sm_pspecial[PLANET_SPECIAL_NUM] = { "ULTRA POOR", "POOR", "", "ARTIFACTS", "RICH", "ULTRA RICH", "4$ TECH" }; const char *game_str_sm_pop = "POP"; const char *game_str_sm_max = "MAX"; const char *game_str_sm_hasreached = "has reached its"; const char *game_str_sm_indmaxof = "industry maximum of"; const char *game_str_sm_factories = "factories"; const char *game_str_sm_extrares = " The extra spent was placed in the planetary reserve."; const char *game_str_sm_popmaxof = "population maximum of"; const char *game_str_sm_colonists = "colonists"; const char *game_str_sm_hasterraf = "has been terraformed to a"; const char *game_str_tbl_sm_terraf[3] = { "normal", "fertile", "gaia" }; const char *game_str_sm_envwith = "environment with"; const char *game_str_tbl_sm_envmore[3] = { "", "150% of ", "double " }; const char *game_str_sm_stdgrow = "the standard growth rate"; const char *game_str_sm_hasfsgate = "has finished building a stargate"; const char *game_str_sm_hasfshield = "has completed building a Class"; const char *game_str_sm_planshield = "Planetary Shield"; const char *game_str_sm_planratio = " Planetary spending ratios may be changed at this time. "; const char *game_str_sm_fleetdep = "FLEET DEPLOYMENT"; const char *game_str_sm_destoor = "DESTINATION IS OUT OF RANGE,"; const char *game_str_sm_destoor2 = "OUT OF RANGE"; const char *game_str_sm_parsfromcc = "PARSECS FROM CLOSEST COLONY"; const char *game_str_sm_eta = "ETA"; const char *game_str_sm_turn = "TURN"; const char *game_str_sm_turns = "TURNS"; const char *game_str_sm_chdest = "Choose destination and number to send"; const char *game_str_sm_outsr = "OUT SHIP RANGE BY"; const char *game_str_sm_sreloc = "Ship Relocation"; const char *game_str_sm_sreloc2 = "Choose another star system under your control to redirect newly built ships to."; const char *game_str_sm_delay = "DELAY"; const char *game_str_sm_seltr = "Select a destination star system to send colonists or troops to."; const char *game_str_sm_notrange = "You do not have the required ship range to reach the system."; const char *game_str_sm_notrange1 = "The star system is"; const char *game_str_sm_notrange2 = "parsecs away and you have a maximum range of"; const char *game_str_sm_notrange3 = "parsecs."; const char *game_str_sm_trfirste = "You must first explore a star system and form a new colony before transporting colonists."; const char *game_str_sm_trcontr1 = "You must have at least controlled"; const char *game_str_sm_trcontr2 = "environments to land troops onto the planet."; const char *game_str_sm_trfirstc = "You must first build a ship equipped with a colony base and create a new colony before sending out transports."; const char *game_str_sm_trwarna = "Warning, destination is owned by an ally"; const char *game_str_sm_trwarnm1 = "Warning - Target planet can only support"; const char *game_str_sm_trwarnm2 = "million!"; const char *game_str_sm_trchnum1 = "Choose number of colonists to transport"; const char *game_str_sm_trchnum2 = "Choose number of troops to transport"; const char *game_str_sm_trans1 = "Transport"; const char *game_str_sm_transs = "Transports"; const char *game_str_sm_tdest = "Destination"; const char *game_str_sm_bomb1 = "Bomb the"; const char *game_str_sm_bomb2 = "Enemy Planet?"; const char *game_str_sm_trinb1 = "Troop Transport"; const char *game_str_sm_trinb1s = "Troop Transport"; const char *game_str_sm_trinb2 = "Currently Enroute"; const char *game_str_sm_obomb1 = "Orbital"; const char *game_str_sm_obomb2 = "Bombardment"; const char *game_str_sm_cdest1 = "colony"; const char *game_str_sm_cdest2 = "destroyed"; const char *game_str_sm_ineff1 = "bombing"; const char *game_str_sm_ineff2 = "ineffective"; const char *game_str_sm_bkill1 = "MILLION"; const char *game_str_sm_bkill2 = "KILLED"; const char *game_str_sm_bfact1 = "FACTORY"; const char *game_str_sm_bfact1s = "FACTORIES"; const char *game_str_sm_bfact2 = "DESTROYED"; const char *game_str_sm_traad1 = "transports attempting to land on"; const char *game_str_sm_traad2 = "were all destroyed."; const char *game_str_sm_trbdb1 = "The base at"; const char *game_str_sm_trbdb2 = "was destroyed before the transports arrived leaving the colonists without supplies and shelter. All have perished."; const char *game_str_sm_inorbit = "In Orbit"; const char *game_str_sm_ship_everywhere = "Build everywhere"; const char *game_str_sm_ship_replace = "Replace"; const char *game_str_tbl_roman[31] = { " ", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X", "XI", "XII", "XIII", "XIV", "XV", "XVI", "XVII", "XVIII", "XIX", "XX", "XXI", "XXII", "XXIII", "XXIV", "XXV", "XXVI", "XXVII", "XXVIII", "XXIX", "XXX" }; const char *game_str_no_events = "No Events"; const char *game_str_no_elections = "No Elections"; const char *game_str_bc = "BC"; const char *game_str_y = "Y"; const char *game_str_year = "Year "; const char *game_str_year0 = "/Year"; const char *game_str_year1 = "Year:"; const char *game_str_player = "Player"; const char *game_str_pl_reserve = "Reserve"; const char *game_str_pl_plague = "PLAGUE"; const char *game_str_pl_nova = "SUPER NOVA"; const char *game_str_pl_comet = "COMET"; const char *game_str_pl_pirates = "PIRATES"; const char *game_str_pl_rebellion = "REBELLION"; const char *game_str_pl_unrest = "UNREST"; const char *game_str_pl_accident = "ACCIDENT"; const char *game_str_pl_spending = "Spending Costs"; const char *game_str_pl_tincome = "Total Income"; const char *game_str_pl_transof = "Transfer of planetary"; const char *game_str_pl_resto = "reserves to"; const char *game_str_sd_cancel = "CANCEL"; const char *game_str_sd_build = "BUILD"; const char *game_str_sd_clear = "CLEAR"; const char *game_str_sd_comp = "Computer"; const char *game_str_sd_shield = "Shield"; const char *game_str_sd_ecm = "Ecm"; const char *game_str_sd_armor = "Armor"; const char *game_str_sd_engine = "Engine"; const char *game_str_sd_man = "Maneuver"; const char *game_str_tbl_sd_spec[SPECIAL_SLOT_NUM] = { "Special 1", "Special 2", "Special 3" }; const char *game_str_tbl_sd_weap[WEAPON_SLOT_NUM] = { "Weapon 1", "Weapon 2", "Weapon 3", "Weapon 4", }; const char *game_str_sd_count = "Count"; const char *game_str_sd_sweap = "Ship Weapons"; const char *game_str_sd_damage = "Damage"; const char *game_str_sd_rng = "Rng"; const char *game_str_sd_notes = "Notes"; const char *game_str_sd_hp = "HIT POINTS"; const char *game_str_sd_warp = "WARP"; const char *game_str_sd_def = "DEF"; const char *game_str_sd_cspeed = "COMBAT SPEED"; const char *game_str_sd_absorbs = "ABSORBS"; const char *game_str_sd_hit = "HIT"; const char *game_str_sd_hits = "HITS"; const char *game_str_sd_misdef = "MISSILE DEF"; const char *game_str_sd_att = "ATTACK LEVEL"; const char *game_str_sd_comptype = "COMPUTER TYPE"; const char *game_str_sd_cost = "COST"; const char *game_str_sd_size = "SIZE"; const char *game_str_sd_power = "POWER"; const char *game_str_sd_space = "SPACE"; const char *game_str_sd_comps = "COMPUTERS"; const char *game_str_sd_shieldtype = "SHIELD TYPE"; const char *game_str_sd_shields = "SHIELDS"; const char *game_str_sd_ecmtype = "ECM TYPE"; const char *game_str_sd_ecm2 = "ECM"; const char *game_str_sd_armortype = "ARMOR TYPE"; const char *game_str_sd_armor2 = "ARMOR"; const char *game_str_sd_engtype = "ENGINE TYPE"; const char *game_str_sd_numengs = "NUM ENGINES"; const char *game_str_sd_engs = "ENGINES"; const char *game_str_sd_man1 = "MANEUVER"; const char *game_str_sd_man2 = "MANEUVERABILITY"; const char *game_str_sd_class = "CLASS"; const char *game_str_sd_speed = "SPEED"; const char *game_str_sd_max = "MAX"; const char *game_str_sd_weapname = "WEAPON NAME"; const char *game_str_sd_descr = "DESCRIPTION"; const char *game_str_sd_dmg = "DMG"; const char *game_str_sd_weaps = "WEAPONS"; const char *game_str_sd_specname = "SPECIAL NAME"; const char *game_str_sd_specs = "SPECIAL DEVICES"; const char *game_str_sd_wgroup_names[WEAPON_GROUP_NUM] = { "WEAPONS", "BEAMS", "KINETIC", "BOMBS", "MISSILES", "BIOLOGICAL", "SPECIAL" }; const char *game_str_sp_only6 = "Only 6 ships may be commisioned at one time. 1/4 the decomissioned ship's cost is placed in the planetary reserve."; const char *game_str_sp_wantscrap = "Do you want to scrap this ship?"; const char *game_str_sp_before = "Before a new design can be created, you must first scrap one of the six current designs."; const char *game_str_sp_cost = "Cost"; const char *game_str_fl_station = "STATION"; const char *game_str_fl_inorbit = "IN ORBIT"; const char *game_str_fl_moving = "MOVING TO"; const char *game_str_fl_unknown = "UNKNOWN"; const char *game_str_fl_system = "SYSTEM"; const char *game_str_gm_tchar = "TJOASDMBUEIPRN"; const char *game_str_tbl_gm_spec[PLANET_SPECIAL_NUM] = { "U POOR", "POOR", "", "ARTIFACTS", "RICH", "U RICH", "ORION" }; const char *game_str_gm_unable = "Unable to land on"; const char *game_str_gm_prod = "PROD"; const char *game_str_gm_tech = "TECH"; const char *game_str_gm_1_3 = "1/3"; const char *game_str_gm_1_2 = "1/2"; const char *game_str_gm_2x = "2$ "; const char *game_str_gm_3x = "3$ "; const char *game_str_gm_4x = "4$ "; const char *game_str_gm_prodb1 = "PRODUCTION BONUSES"; const char *game_str_gm_prodb2 = "APPLY TO INDUSTRY,"; const char *game_str_gm_prodb3 = "SHIPS AND DEFENSE"; const char *game_str_gm_gmap = "Galaxy Map"; const char *game_str_gm_mapkey = "Map Key"; const char *game_str_bs_line1 = "How many missile"; const char *game_str_bs_line2 = "bases to eliminate?"; const char *game_str_bs_bases = "Bases"; const char *game_str_tbl_te_field[TECH_FIELD_NUM] = { "Computer", "Construction", "Force Field", "Planetology", "Propulsion", "Weapon" }; const char *game_str_te_adv = "Advanced"; const char *game_str_te_tech = "Tech"; const char *game_str_te_techno = "Technology"; const char *game_str_te_techno2 = "technology"; const char *game_str_te_genimp = "General improvements of existing"; const char *game_str_te_nmis = "Missiles tipped with nuclear warheads that explode for 4 points of damage and move at a speed of 2."; const char *game_str_te_nbomb = "Bombs that explode for 3-12 points of damage on ground targets only."; const char *game_str_te_scrange = "SCANNER RANGE"; const char *game_str_te_rctrl = "Robot Controls"; const char *game_str_te_col = "col"; const char *game_str_te_fwaste = "FACTORY WASTE"; const char *game_str_te_gcombat = "GROUND COMBAT"; const char *game_str_te_tform = "TERRAFORM"; const char *game_str_te_wasteel = "WASTE ELIMINATION"; const char *game_str_te_shrange = "SHIP RANGE"; const char *game_str_te_max = "MAX"; const char *game_str_te_rp = "RP"; const char *game_str_nt_achieve = "Scientists Achieve A"; const char *game_str_nt_break = "Breakthrough"; const char *game_str_nt_infil = "Spies Infiltrate The Research Center At"; const char *game_str_nt_ruins = "Troopers At The Ruins Of"; const char *game_str_nt_discover = "Discover"; const char *game_str_nt_orion = "Troopers Landing on Orion Discover"; const char *game_str_nt_scouts = "Scouts Exploring The Ruins Of"; const char *game_str_nt_choose = "Choose the area of research our scientists now focus on"; const char *game_str_nt_reveal = "Scientists Reveal Their"; const char *game_str_nt_secrets = "Secrets"; const char *game_str_nt_frame = "Your spies managed to frame another race for the theft"; const char *game_str_nt_victim = "Choose the victim race:"; const char *game_str_nt_doyou = "Do you want to "; const char *game_str_nt_inc = "increase the "; const char *game_str_nt_redueco = "reduce the ecology ratio of all of your colonies to the minimum amount necessary to keep them clean?"; const char *game_str_nt_ind = "industry ratios of all of your colonies to upgrade your factory controls?"; const char *game_str_nt_ecoall = "ecology ratios of all of your colonies"; const char *game_str_nt_terra = " in order to begin terraforming your planets?"; const char *game_str_nt_def = "defense ratio of all of your colonies to build the new planetary shields?"; const char *game_str_nt_ecostd = "ecology ratio of your colonies with standard environments"; const char *game_str_nt_ecohost = "ecology ratio of your colonies with hostile environments"; const char *game_str_tbl_nt_adj[4] = { "NO", "+25%", "+50%", "+75%" }; const char *game_str_adj_set = "set the "; const char *game_str_adj_ratios = " ratios of all of your colonies?"; const char *game_str_adj_max = " ratios of all of your colonies to maximum?"; const char *game_str_adj_slider[PLANET_SLIDER_NUM] = { "ship", "defense", "industry", "ecology", "technology" }; const char *game_str_adj_colonies = " colonies?"; const char *game_str_adj_lock = " slider lock for all of your colonies?"; const char *game_str_adj_lock2 = " slider lock for "; const char *game_str_adj_special[7] = { "ultra poor", "poor", "normal", "artifacts", "rich", "ultra rich", "4x tech" }; const char *game_str_ra_nocont = "No Contact"; const char *game_str_ra_notpres = "Not Present"; const char *game_str_ra_secline1 = "SECURITY INCREASES THE CHANCE OF"; const char *game_str_ra_secline2 = "CATCHING ALL ENEMY SPIES. "; const char *game_str_ra_alloc = "Allocations"; const char *game_str_ra_planres = "Planetary Resources"; const char *game_str_ra_diplo = "Diplomat"; const char *game_str_ra_gone = "Gone"; const char *game_str_ra_nospies = "NO SPIES"; const char *game_str_ra_spy = "SPY"; const char *game_str_ra_spies = "SPIES"; const char *game_str_tbl_ra_treaty[TREATY_NUM] = { "No Treaty", "Non-Aggression Pact", "Alliance", "War", "Final War" }; const char *game_str_ra_trade = "Trade"; const char *game_str_ra_notrade = "No Trade"; const char *game_str_tbl_ra_relat[17] = { "FEUD", "HATE", "DISCORD", "TROUBLED", "TENSE", "RESTLESS", "WARY", "UNEASE", "NEUTRAL", "RELAXED", "AMIABLE", "CALM", "AFFABLE", "PEACEFUL", "FRIENDLY", "UNITY", "HARMONY" }; const char *game_str_ra_stats = "Racial Stats"; const char *game_str_re_reportis = "REPORT IS"; const char *game_str_re_current = "CURRENT"; const char *game_str_re_yearsold = "years old"; const char *game_str_re_alliance = "Alliances"; const char *game_str_re_wars = "Wars"; const char *game_str_re_environ = "ENVIRON"; const char *game_str_sc_caught = "Spies Caught Yours Theirs"; const char *game_str_bp_scombat = "Space Combat"; const char *game_str_bp_attack = "attack"; const char *game_str_bp_attacks = "attacks"; const char *game_str_bp_won = "won"; const char *game_str_bt_auto_move = "AUTO MOVE"; const char *game_str_bt_pop = "POPULATION"; const char *game_str_bt_ind = "INDUSTRY"; const char *game_str_bt_bases = "MISSILE BASES"; const char *game_str_bt_subint = "SUBSPACE INTERDICTOR"; const char *game_str_bt_launch = "LAUNCHERS"; const char *game_str_bt_coldest = "Colony Was Destroyed!"; const char *game_str_es_youresp1 = "YOUR SPIES HAVE INFILTRATED A"; const char *game_str_es_youresp2 = "BASE"; const char *game_str_es_youresp3 = "CHOOSE THE TYPE OF TECHNOLOGY TO STEAL"; const char *game_str_es_thesp1 = "Espionage"; const char *game_str_es_thesp2 = "spies steal the plans for:"; const char *game_str_es_unkn = "Unknown"; const char *game_str_sb_choose = "Choose target for sabotage"; const char *game_str_sb_lastrep = "Last Report:"; const char *game_str_sb_pop = "Population:"; const char *game_str_sb_fact = "Factories:"; const char *game_str_sb_bases = "Missile Bases:"; const char *game_str_sb_unkn = "Unknown spy"; const char *game_str_sb_your = "Your"; const char *game_str_sb_spies = "spies"; const char *game_str_sb_increv = "incited a revolt!"; const char *game_str_sb_inc1 = "incited"; const char *game_str_sb_inc2 = "rebels. Unrest now at"; const char *game_str_sb_destr = "destroyed"; const char *game_str_sb_fact2 = "factory"; const char *game_str_sb_facts = "factories"; const char *game_str_sb_mbase = "missile base"; const char *game_str_sb_mbases = "missile bases"; const char *game_str_sb_failed = "failed!"; const char *game_str_sb_nofact = "No factories to sabotage"; const char *game_str_sb_nobases = "No missile bases to sabotage"; const char *game_str_sb_noinc = "failed to incite any rebels"; const char *game_str_sb_frame = "Your spies managed to frame another race for the sabotage"; const char *game_str_ex_planeta = "Planetary"; const char *game_str_ex_scanner = "scanners"; const char *game_str_ex_scout = "Scout ships"; const char *game_str_ex_explore = "explore a new"; const char *game_str_ex_starsys = "star system"; const char *game_str_ex_build = "Build a"; const char *game_str_ex_colony = "new colony?"; const char *game_str_ex_popgr = "POPULATION GROWTH"; const char *game_str_ex_resopnt = "RESOURCE POINTS"; const char *game_str_ex_fromind = "FROM INDUSTRY ARE"; const char *game_str_ex_techpnt = "TECHNOLOGY POINTS"; const char *game_str_ex_fromres = "FROM RESEARCH"; const char *game_str_ex_aredbl = "ARE DOUBLED."; const char *game_str_ex_arequad = "ARE QUADRUPLED."; const char *game_str_ex_pg1[3] = { "Hostile", "Ecologicaly", "Ecological" }; const char *game_str_ex_pg2[3] = { "Environment", "Fertile", "Gaia" }; const char *game_str_ex_pg3[3] = { "IS HALVED.", "IS +50% NORMAL.", "IS DOUBLED." }; const char *game_str_ex_ps1[5] = { "Ultra Poor", "Mineral Poor", "Artifacts", "Mineral Rich", "Ultra Rich" }; const char *game_str_ex_ps2[4] = { "CUT TO ONE-THIRD.", "HALVED.", "DOUBLED.", "TRIPLED." }; const char *game_str_la_colony = "Colony Name..."; const char *game_str_la_inyear = "In the year"; const char *game_str_la_the = "the"; const char *game_str_la_formnew = "s form a new colony"; const char *game_str_gr_carmor = "Combat Armor"; const char *game_str_gr_outof = "out of"; const char *game_str_gr_transs = "transports"; const char *game_str_gr_reclaim = "transports land to reclaim the colony"; const char *game_str_gr_penetr = "penetrate"; const char *game_str_gr_defenss = "defenses"; const char *game_str_gr_troops = "Troops"; const char *game_str_gr_rebel = "Rebel"; const char *game_str_gr_gcon = "Ground Combat On"; const char *game_str_gr_scapt = "s Capture"; const char *game_str_gr_itroops = "Imperial Troops Recapture"; const char *game_str_gr_succd = "s Successfully Defend"; const char *game_str_gr_fcapt = "factories captured"; const char *game_str_gr_tsteal = "technology stolen"; const char *game_str_gr_tnew = "new tech found"; const char *game_str_el_no = "no"; const char *game_str_el_vote = "vote"; const char *game_str_el_votes = "votes"; const char *game_str_el_total = "total"; const char *game_str_el_start = "The High Council has convened to elect one leader to be Emperor of the Galaxy..."; const char *game_str_el_emperor = "Emperor"; const char *game_str_el_ofthe = "of the"; const char *game_str_el_and = "and"; const char *game_str_el_for = "for"; const char *game_str_el_nomin = "have been nominated."; const char *game_str_el_abs1 = "The"; const char *game_str_el_abs2 = "abstain ("; const char *game_str_el_dots = ")..."; const char *game_str_el_your = "Your choice ("; const char *game_str_el_bull = "["; const char *game_str_el_self = "Yourself"; const char *game_str_el_abs = "Abstain"; const char *game_str_el_chose1 = "In the year"; const char *game_str_el_chose2 = ", the Council has chosen"; const char *game_str_el_chose3 = "to be the High Master of the New Republic."; const char *game_str_el_neither = "Neither leader has a two thirds majority..."; const char *game_str_el_accept = "Do you accept the ruling?"; const char *game_str_el_yes = "Yes"; const char *game_str_el_no2 = "No"; const char *game_str_el_sobeit = "So be it. You defy the ruling of the council. Now you will feel the wrath of the New Republic!"; const char *game_str_el_isnow = "is now High Master."; const char *game_str_au_facts = "factories"; const char *game_str_au_bases = "missile bases"; const char *game_str_au_treaty = "treaty"; const char *game_str_au_allian = "Alliance"; const char *game_str_au_nonagg = "Non-Aggression Pact"; const char *game_str_au_tradea = "Trade Agreement"; const char *game_str_au_amreca = "(ambassador recalled)"; const char *game_str_au_tech = "tech"; const char *game_str_au_framed = "(you were framed)"; const char *game_str_au_bull = "["; const char *game_str_au_inxchng = "In exchange you will receive:"; const char *game_str_au_whatif1 = "What if we were to also offer"; const char *game_str_au_whatif2 = "as an incentive"; const char *game_str_au_perrec1 = "Perhaps you would reconsider if we also provided"; const char *game_str_au_ques = "?"; const char *game_str_au_howmay = "How may our empire serve you:"; const char *game_str_au_youprte = "You propose a treaty:"; const char *game_str_au_youprta = "You propose a trade agreement for:"; const char *game_str_au_youract = "Your actions:"; const char *game_str_au_whatech = "What type of technology interests you?"; const char *game_str_au_whatrad = "What will you trade for it?"; const char *game_str_au_whatoff = "What do you offer as tribute?"; const char *game_str_au_perthr1 = "Perhaps if you were to throw in"; const char *game_str_au_perthr2 = "we could deal."; const char *game_str_au_alsoof1 = "If you also offer us"; const char *game_str_au_alsoof2 = "we would accept."; const char *game_str_au_whowar = "Who should we declare war on?"; const char *game_str_au_whobrk = "Who should we break our treaty with?"; const char *game_str_au_bcpery = "BC / year"; const char *game_str_au_whattr = "What do you offer as tribute?"; const char *game_str_au_techn = "[ Technology"; const char *game_str_au_nextp = "[ Next page"; const char *game_str_au_back = "[ Back"; const char *game_str_au_opts_main[6] = { "[ Propose Treaty", "[ Form Trade Agreement", "[ Threaten/Break Treaty and Trade", "[ Offer Tribute", "[ Exchange Technology", "[ Good Bye" }; const char *game_str_au_opts_treaty[6] = { "[ Non-Aggression Pact", "[ Alliance", "[ Peace Treaty", "[ Declaration of War on Another Race", "[ Break Alliance With Another Race", "[ Forget It" }; const char *game_str_au_opts_agree[2] = { "[ Agree", "[ Forget It" }; const char *game_str_au_opts_accept[2] = { "[ Accept", "[ Reject" }; const char *game_str_au_opts_threaten[5] = { "[ Break Non-Aggression Pact", "[ Break Alliance", "[ Break Trade Agreement", "[ Threaten To Attack", "[ Forget It" }; const char *game_str_au_optsmp1[4] = { "[ Agree", "[ Forget It", "[ Demand BC", "[ Demand Technology" }; const char *game_str_tr_cont1 = "Contact has been broken with the"; const char *game_str_tr_cont2 = "empire!"; const char *game_str_tr_fuel1 = "The fleet orbiting"; const char *game_str_tr_fuel2 = "has been cut off from refueling supply lines and has been lost."; const char *game_str_sv_envir = "environment"; const char *game_str_sv_stargt = "Star Gate"; const char *game_str_sv_shild1 = "CLASS"; const char *game_str_sv_shild2 = "SHIELD"; const char *game_str_sv_psize = "PLANET SIZE:"; const char *game_str_sv_fact = "FACTORIES:"; const char *game_str_sv_waste = "WASTE:"; const char *game_str_sv_pop = "POPULATION:"; const char *game_str_sv_growth = "GROWTH:"; const char *game_str_sv_techp = "Technology points from research are"; const char *game_str_sv_resp = "Resource points from industry are"; const char *game_str_sv_1_3x = "cut to one-third."; const char *game_str_sv_1_2x = "halved."; const char *game_str_sv_2x = "doubled."; const char *game_str_sv_3x = "tripled."; const char *game_str_sv_4x = "quadrupled."; const char *game_str_sv_popgr = "Population growth is"; const char *game_str_sv_pg1[3] = { "Hostile", "Fertile", "Gaia" }; const char *game_str_sv_pg2[3] = { "halved.", "50% greater.", "doubled." }; const char *game_str_in_loading = "Loading Master of Orion..."; const char *game_str_wl_won_1 = "Escorted by Honor Guard, High Master "; const char *game_str_wl_won_2 = "returns to Orion, throne world of the Ancients."; const char *game_str_wl_won_3 = "The Galactic Imperium has been reformed..."; const char *game_str_wl_3_good_1 = "A new era has dawned. We must set aside our past"; const char *game_str_wl_3_good_2 = "conflicts and greet a new millenium as a united galaxy"; const char *game_str_wl_3_tyrant_1 = "The universe is mine and all shall bow before the"; const char *game_str_wl_3_tyrant_2 = "might of "; const char *game_str_wl_3_tyrant_3 = ", Master of Orion."; const char *game_str_wl_3_tyrant_4 = "Master of the Universe..."; const char *game_str_wl_exile_1 = "Exiled from the known galaxy, Emperor "; const char *game_str_wl_exile_2 = "sets forth to conquer new worlds."; const char *game_str_wl_exile_3 = "vowing to return and claim the renowned title of"; const char *game_str_wl_exile_4 = " Master of Orion..."; const char *game_str_gnn_end_good = "And that's the way it is..."; const char *game_str_gnn_end_tyrant = "Oh well, another millenium serving under a ruthless tyrant..."; const char *game_str_gnn_also = "Also in the news..."; 1oom-1.11.2/src/game/game_str.h000066400000000000000000000510061476061725400161370ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_STR_H #define INC_1OOM_GAME_STR_H #include "game_design.h" #include "game_planet.h" #include "game_shiptech.h" #include "game_types.h" #include "types.h" extern const char *game_str_mm_continue; extern const char *game_str_mm_load; extern const char *game_str_mm_new; extern const char *game_str_mm_quit; extern const char *game_str_tbl_race[RACE_NUM + 1]; extern const char *game_str_tbl_races[RACE_NUM]; extern const char *game_str_tbl_banner[BANNER_NUM + 1]; extern const char *game_str_tbl_gsize[GALAXY_SIZE_NUM]; extern const char *game_str_tbl_diffic[DIFFICULTY_NUM]; extern const char *game_str_tbl_oppon[5]; extern const char *game_str_tbl_traits[RACE_NUM * 3]; extern const char *game_str_tbl_trait1[TRAIT1_NUM]; extern const char *game_str_tbl_trait2[TRAIT2_NUM]; extern const char *game_str_ng_choose_race; extern const char *game_str_ng_choose_banner; extern const char *game_str_ng_your_name; extern const char *game_str_ng_home_name; extern const char *game_str_ng_ai; extern const char *game_str_ng_computer; extern const char *game_str_ng_player; extern const char *game_str_ng_cancel; extern const char *game_str_ng_ok; extern const char *game_str_ng_allai; #define PLANET_NAMES_MAX 110 extern const char *game_str_tbl_planet_names[PLANET_NAMES_MAX]; extern const char *game_str_tbl_home_names[RACE_NUM + 1]; extern const char *game_str_rndempname; extern const char *game_str_planet_name_orion; extern const char *game_str_tbl_ship_names[RACE_NUM * SHIP_NAME_NUM]; extern const char *game_str_tbl_stship_names[NUM_SHIPDESIGNS]; extern const char *game_str_tbl_copyprotection_ship_names[40]; extern const char *game_str_tbl_monsh_names[MONSTER_NUM]; extern const char *game_str_tbl_mon_names[MONSTER_NUM]; extern const char *game_str_ai_colonyship; extern const char *game_str_st_none; extern const char *game_str_st_none2; extern const char *game_str_tbl_st_weap[WEAPON_NUM - 1]; extern const char *game_str_tbl_st_weapx[WEAPON_NUM - 1]; extern const char *game_str_tbl_st_comp[SHIP_COMP_NUM - 1]; extern const char *game_str_tbl_st_engine[SHIP_ENGINE_NUM]; extern const char *game_str_tbl_st_armor[SHIP_ARMOR_NUM]; extern const char *game_str_tbl_st_shield[SHIP_SHIELD_NUM - 1]; extern const char *game_str_tbl_st_jammer[SHIP_JAMMER_NUM - 1]; extern const char *game_str_tbl_st_specsh[SHIP_SPECIAL_NUM]; extern const char *game_str_tbl_st_special[SHIP_SPECIAL_NUM - 1]; extern const char *game_str_tbl_st_specialx[SHIP_SPECIAL_NUM - 1]; extern const char *game_str_tbl_st_hull[SHIP_HULL_NUM]; extern const char *game_str_sm_crystal; extern const char *game_str_sm_amoeba; extern const char *game_str_sm_game; extern const char *game_str_sm_design; extern const char *game_str_sm_fleet; extern const char *game_str_sm_map; extern const char *game_str_sm_races; extern const char *game_str_sm_planets; extern const char *game_str_sm_tech; extern const char *game_str_sm_next_turn; extern const char *game_str_sm_range; extern const char *game_str_sm_parsec; extern const char *game_str_sm_parsecs; extern const char *game_str_sm_parsecs2; extern const char *game_str_sm_colony; extern const char *game_str_sm_lastrep; extern const char *game_str_sm_stargate; extern const char *game_str_sm_prodnone; extern const char *game_str_sm_prod_y; extern const char *game_str_sm_defupg; extern const char *game_str_sm_defshld; extern const char *game_str_sm_refit; extern const char *game_str_sm_irc[]; extern const char *game_str_sm_indmax; extern const char *game_str_sm_indres; extern const char *game_str_sm_ecowaste; extern const char *game_str_sm_ecoclean; extern const char *game_str_sm_ecoatmos; extern const char *game_str_sm_ecotform; extern const char *game_str_sm_ecosoil; extern const char *game_str_sm_ecogaia; extern const char *game_str_sm_ecopop; extern const char *game_str_sm_unexplored; extern const char *game_str_sm_nohabit; extern const char *game_str_sm__planets; extern const char *game_str_tbl_sm_pltype[PLANET_TYPE_NUM + 1]; extern const char *game_str_tbl_sm_stinfo[STAR_TYPE_NUM]; extern const char *game_str_sm_plague; extern const char *game_str_sm_nova; extern const char *game_str_sm_comet; extern const char *game_str_sm_pirates; extern const char *game_str_sm_rebellion; extern const char *game_str_sm_unrest; extern const char *game_str_sm_accident; extern const char *game_str_tbl_sm_pgrowth[PLANET_GROWTH_NUM]; extern const char *game_str_tbl_sm_pspecial[PLANET_SPECIAL_NUM]; extern const char *game_str_sm_pop; extern const char *game_str_sm_max; extern const char *game_str_sm_hasreached; extern const char *game_str_sm_indmaxof; extern const char *game_str_sm_factories; extern const char *game_str_sm_extrares; extern const char *game_str_sm_popmaxof; extern const char *game_str_sm_colonists; extern const char *game_str_sm_hasterraf; extern const char *game_str_tbl_sm_terraf[3]; extern const char *game_str_sm_envwith; extern const char *game_str_tbl_sm_envmore[3]; extern const char *game_str_sm_stdgrow; extern const char *game_str_sm_hasfsgate; extern const char *game_str_sm_hasfshield; extern const char *game_str_sm_planshield; extern const char *game_str_sm_planratio; extern const char *game_str_sm_fleetdep; extern const char *game_str_sm_destoor; extern const char *game_str_sm_destoor2; extern const char *game_str_sm_parsfromcc; extern const char *game_str_sm_eta; extern const char *game_str_sm_turn; extern const char *game_str_sm_turns; extern const char *game_str_sm_chdest; extern const char *game_str_sm_outsr; extern const char *game_str_sm_sreloc; extern const char *game_str_sm_sreloc2; extern const char *game_str_sm_delay; extern const char *game_str_sm_seltr; extern const char *game_str_sm_notrange; extern const char *game_str_sm_notrange1; extern const char *game_str_sm_notrange2; extern const char *game_str_sm_notrange3; extern const char *game_str_sm_trfirste; extern const char *game_str_sm_trcontr1; extern const char *game_str_sm_trcontr2; extern const char *game_str_sm_trfirstc; extern const char *game_str_sm_trwarna; extern const char *game_str_sm_trwarnm1; extern const char *game_str_sm_trwarnm2; extern const char *game_str_sm_trchnum1; extern const char *game_str_sm_trchnum2; extern const char *game_str_sm_trans1; extern const char *game_str_sm_transs; extern const char *game_str_sm_tdest; extern const char *game_str_sm_bomb1; extern const char *game_str_sm_bomb2; extern const char *game_str_sm_trinb1; extern const char *game_str_sm_trinb1s; extern const char *game_str_sm_trinb2; extern const char *game_str_sm_obomb1; extern const char *game_str_sm_obomb2; extern const char *game_str_sm_cdest1; extern const char *game_str_sm_cdest2; extern const char *game_str_sm_ineff1; extern const char *game_str_sm_ineff2; extern const char *game_str_sm_bkill1; extern const char *game_str_sm_bkill2; extern const char *game_str_sm_bfact1; extern const char *game_str_sm_bfact1s; extern const char *game_str_sm_bfact2; extern const char *game_str_sm_traad1; extern const char *game_str_sm_traad2; extern const char *game_str_sm_trbdb1; extern const char *game_str_sm_trbdb2; extern const char *game_str_sm_inorbit; extern const char *game_str_sm_ship_everywhere; extern const char *game_str_sm_ship_replace; extern const char *game_str_tbl_roman[31]; extern const char *game_str_no_events; extern const char *game_str_no_elections; extern const char *game_str_bc; extern const char *game_str_y; extern const char *game_str_year; extern const char *game_str_year0; extern const char *game_str_year1; extern const char *game_str_player; extern const char *game_str_pl_reserve; extern const char *game_str_pl_plague; extern const char *game_str_pl_nova; extern const char *game_str_pl_comet; extern const char *game_str_pl_pirates; extern const char *game_str_pl_rebellion; extern const char *game_str_pl_unrest; extern const char *game_str_pl_accident; extern const char *game_str_pl_spending; extern const char *game_str_pl_tincome; extern const char *game_str_pl_transof; extern const char *game_str_pl_resto; extern const char *game_str_sd_cancel; extern const char *game_str_sd_build; extern const char *game_str_sd_clear; extern const char *game_str_sd_comp; extern const char *game_str_sd_shield; extern const char *game_str_sd_ecm; extern const char *game_str_sd_armor; extern const char *game_str_sd_engine; extern const char *game_str_sd_man; extern const char *game_str_tbl_sd_spec[SPECIAL_SLOT_NUM]; extern const char *game_str_tbl_sd_weap[WEAPON_SLOT_NUM]; extern const char *game_str_sd_count; extern const char *game_str_sd_sweap; extern const char *game_str_sd_damage; extern const char *game_str_sd_rng; extern const char *game_str_sd_notes; extern const char *game_str_sd_hp; extern const char *game_str_sd_warp; extern const char *game_str_sd_def; extern const char *game_str_sd_cspeed; extern const char *game_str_sd_absorbs; extern const char *game_str_sd_hit; extern const char *game_str_sd_hits; extern const char *game_str_sd_misdef; extern const char *game_str_sd_att; extern const char *game_str_sd_comptype; extern const char *game_str_sd_cost; extern const char *game_str_sd_size; extern const char *game_str_sd_power; extern const char *game_str_sd_space; extern const char *game_str_sd_comps; extern const char *game_str_sd_shieldtype; extern const char *game_str_sd_shields; extern const char *game_str_sd_ecmtype; extern const char *game_str_sd_ecm2; extern const char *game_str_sd_armortype; extern const char *game_str_sd_armor2; extern const char *game_str_sd_engtype; extern const char *game_str_sd_numengs; extern const char *game_str_sd_engs; extern const char *game_str_sd_man1; extern const char *game_str_sd_man2; extern const char *game_str_sd_class; extern const char *game_str_sd_speed; extern const char *game_str_sd_max; extern const char *game_str_sd_weapname; extern const char *game_str_sd_descr; extern const char *game_str_sd_dmg; extern const char *game_str_sd_weaps; extern const char *game_str_sd_specname; extern const char *game_str_sd_specs; extern const char *game_str_sd_wgroup_names[WEAPON_GROUP_NUM]; extern const char *game_str_sp_only6; extern const char *game_str_sp_wantscrap; extern const char *game_str_sp_before; extern const char *game_str_sp_cost; extern const char *game_str_fl_station; extern const char *game_str_fl_inorbit; extern const char *game_str_fl_moving; extern const char *game_str_fl_unknown; extern const char *game_str_fl_system; extern const char *game_str_gm_tchar; extern const char *game_str_tbl_gm_spec[PLANET_SPECIAL_NUM]; extern const char *game_str_gm_unable; extern const char *game_str_gm_prod; extern const char *game_str_gm_tech; extern const char *game_str_gm_1_3; extern const char *game_str_gm_1_2; extern const char *game_str_gm_2x; extern const char *game_str_gm_3x; extern const char *game_str_gm_4x; extern const char *game_str_gm_prodb1; extern const char *game_str_gm_prodb2; extern const char *game_str_gm_prodb3; extern const char *game_str_gm_gmap; extern const char *game_str_gm_mapkey; extern const char *game_str_bs_line1; extern const char *game_str_bs_line2; extern const char *game_str_bs_bases; extern const char *game_str_tbl_te_field[TECH_FIELD_NUM]; extern const char *game_str_te_adv; extern const char *game_str_te_tech; extern const char *game_str_te_techno; extern const char *game_str_te_techno2; extern const char *game_str_te_genimp; extern const char *game_str_te_nmis; extern const char *game_str_te_nbomb; extern const char *game_str_te_scrange; extern const char *game_str_te_rctrl; extern const char *game_str_te_col; extern const char *game_str_te_fwaste; extern const char *game_str_te_gcombat; extern const char *game_str_te_tform; extern const char *game_str_te_wasteel; extern const char *game_str_te_shrange; extern const char *game_str_te_max; extern const char *game_str_te_rp; extern const char *game_str_nt_achieve; extern const char *game_str_nt_break; extern const char *game_str_nt_infil; extern const char *game_str_nt_ruins; extern const char *game_str_nt_discover; extern const char *game_str_nt_orion; extern const char *game_str_nt_scouts; extern const char *game_str_nt_choose; extern const char *game_str_nt_reveal; extern const char *game_str_nt_secrets; extern const char *game_str_nt_frame; extern const char *game_str_nt_victim; extern const char *game_str_nt_doyou; extern const char *game_str_nt_inc; extern const char *game_str_nt_redueco; extern const char *game_str_nt_ind; extern const char *game_str_nt_ecoall; extern const char *game_str_nt_terra; extern const char *game_str_nt_def; extern const char *game_str_nt_ecostd; extern const char *game_str_nt_ecohost; extern const char *game_str_adj_set; extern const char *game_str_adj_ratios; extern const char *game_str_adj_max; extern const char *game_str_adj_slider[PLANET_SLIDER_NUM]; extern const char *game_str_adj_colonies; extern const char *game_str_adj_lock; extern const char *game_str_adj_lock2; extern const char *game_str_adj_special[7]; extern const char *game_str_tbl_nt_adj[4]; extern const char *game_str_ra_nocont; extern const char *game_str_ra_notpres; extern const char *game_str_ra_secline1; extern const char *game_str_ra_secline2; extern const char *game_str_ra_alloc; extern const char *game_str_ra_planres; extern const char *game_str_ra_diplo; extern const char *game_str_ra_gone; extern const char *game_str_ra_nospies; extern const char *game_str_ra_spy; extern const char *game_str_ra_spies; extern const char *game_str_tbl_ra_treaty[TREATY_NUM]; extern const char *game_str_ra_trade; extern const char *game_str_ra_notrade; extern const char *game_str_tbl_ra_relat[17]; extern const char *game_str_ra_stats; extern const char *game_str_re_reportis; extern const char *game_str_re_current; extern const char *game_str_re_yearsold; extern const char *game_str_re_alliance; extern const char *game_str_re_wars; extern const char *game_str_re_environ; extern const char *game_str_sc_caught; extern const char *game_str_bp_scombat; extern const char *game_str_bp_attack; extern const char *game_str_bp_attacks; extern const char *game_str_bp_won; extern const char *game_str_bt_auto_move; extern const char *game_str_bt_pop; extern const char *game_str_bt_ind; extern const char *game_str_bt_bases; extern const char *game_str_bt_subint; extern const char *game_str_bt_launch; extern const char *game_str_bt_coldest; extern const char *game_str_es_youresp1; extern const char *game_str_es_youresp2; extern const char *game_str_es_youresp3; extern const char *game_str_es_thesp1; extern const char *game_str_es_thesp2; extern const char *game_str_es_unkn; extern const char *game_str_sb_choose; extern const char *game_str_sb_lastrep; extern const char *game_str_sb_pop; extern const char *game_str_sb_fact; extern const char *game_str_sb_bases; extern const char *game_str_sb_unkn; extern const char *game_str_sb_your; extern const char *game_str_sb_spies; extern const char *game_str_sb_increv; extern const char *game_str_sb_inc1; extern const char *game_str_sb_inc2; extern const char *game_str_sb_destr; extern const char *game_str_sb_fact2; extern const char *game_str_sb_facts; extern const char *game_str_sb_mbase; extern const char *game_str_sb_mbases; extern const char *game_str_sb_failed; extern const char *game_str_sb_nofact; extern const char *game_str_sb_nobases; extern const char *game_str_sb_noinc; extern const char *game_str_sb_frame; extern const char *game_str_ex_planeta; extern const char *game_str_ex_scanner; extern const char *game_str_ex_scout; extern const char *game_str_ex_explore; extern const char *game_str_ex_starsys; extern const char *game_str_ex_build; extern const char *game_str_ex_colony; extern const char *game_str_ex_popgr; extern const char *game_str_ex_resopnt; extern const char *game_str_ex_fromind; extern const char *game_str_ex_techpnt; extern const char *game_str_ex_fromres; extern const char *game_str_ex_aredbl; extern const char *game_str_ex_arequad; extern const char *game_str_ex_pg1[3]; extern const char *game_str_ex_pg2[3]; extern const char *game_str_ex_pg3[3]; extern const char *game_str_ex_ps1[5]; extern const char *game_str_ex_ps2[4]; extern const char *game_str_la_colony; extern const char *game_str_la_inyear; extern const char *game_str_la_the; extern const char *game_str_la_formnew; extern const char *game_str_gr_carmor; extern const char *game_str_gr_outof; extern const char *game_str_gr_transs; extern const char *game_str_gr_reclaim; extern const char *game_str_gr_penetr; extern const char *game_str_gr_defenss; extern const char *game_str_gr_troops; extern const char *game_str_gr_rebel; extern const char *game_str_gr_gcon; extern const char *game_str_gr_scapt; extern const char *game_str_gr_itroops; extern const char *game_str_gr_succd; extern const char *game_str_gr_fcapt; extern const char *game_str_gr_tsteal; extern const char *game_str_gr_tnew; extern const char *game_str_el_no; extern const char *game_str_el_vote; extern const char *game_str_el_votes; extern const char *game_str_el_total; extern const char *game_str_el_start; extern const char *game_str_el_emperor; extern const char *game_str_el_ofthe; extern const char *game_str_el_and; extern const char *game_str_el_for; extern const char *game_str_el_nomin; extern const char *game_str_el_abs1; extern const char *game_str_el_abs2; extern const char *game_str_el_dots; extern const char *game_str_el_your; extern const char *game_str_el_bull; extern const char *game_str_el_self; extern const char *game_str_el_abs; extern const char *game_str_el_chose1; extern const char *game_str_el_chose2; extern const char *game_str_el_chose3; extern const char *game_str_el_neither; extern const char *game_str_el_accept; extern const char *game_str_el_yes; extern const char *game_str_el_no2; extern const char *game_str_el_sobeit; extern const char *game_str_el_isnow; extern const char *game_str_au_facts; extern const char *game_str_au_bases; extern const char *game_str_au_treaty; extern const char *game_str_au_allian; extern const char *game_str_au_nonagg; extern const char *game_str_au_tradea; extern const char *game_str_au_amreca; extern const char *game_str_au_tech; extern const char *game_str_au_framed; extern const char *game_str_au_bull; extern const char *game_str_au_inxchng; extern const char *game_str_au_whatif1; extern const char *game_str_au_whatif2; extern const char *game_str_au_perrec1; extern const char *game_str_au_ques; extern const char *game_str_au_howmay; extern const char *game_str_au_youprte; extern const char *game_str_au_youprta; extern const char *game_str_au_youract; extern const char *game_str_au_whatech; extern const char *game_str_au_whatrad; extern const char *game_str_au_whatoff; extern const char *game_str_au_perthr1; extern const char *game_str_au_perthr2; extern const char *game_str_au_alsoof1; extern const char *game_str_au_alsoof2; extern const char *game_str_au_whowar; extern const char *game_str_au_whobrk; extern const char *game_str_au_bcpery; extern const char *game_str_au_whattr; extern const char *game_str_au_techn; extern const char *game_str_au_nextp; extern const char *game_str_au_back; extern const char *game_str_au_opts_main[6]; extern const char *game_str_au_opts_treaty[6]; extern const char *game_str_au_opts_agree[2]; extern const char *game_str_au_opts_accept[2]; extern const char *game_str_au_opts_threaten[5]; extern const char *game_str_au_optsmp1[4]; extern const char *game_str_tr_cont1; extern const char *game_str_tr_cont2; extern const char *game_str_tr_fuel1; extern const char *game_str_tr_fuel2; extern const char *game_str_sv_envir; extern const char *game_str_sv_stargt; extern const char *game_str_sv_shild1; extern const char *game_str_sv_shild2; extern const char *game_str_sv_psize; extern const char *game_str_sv_fact; extern const char *game_str_sv_waste; extern const char *game_str_sv_pop; extern const char *game_str_sv_growth; extern const char *game_str_sv_techp; extern const char *game_str_sv_resp; extern const char *game_str_sv_1_3x; extern const char *game_str_sv_1_2x; extern const char *game_str_sv_2x; extern const char *game_str_sv_3x; extern const char *game_str_sv_4x; extern const char *game_str_sv_popgr; extern const char *game_str_sv_pg1[3]; extern const char *game_str_sv_pg2[3]; extern const char *game_str_in_loading; extern const char *game_str_wl_won_1; extern const char *game_str_wl_won_2; extern const char *game_str_wl_won_3; extern const char *game_str_wl_3_good_1; extern const char *game_str_wl_3_good_2; extern const char *game_str_wl_3_tyrant_1; extern const char *game_str_wl_3_tyrant_2; extern const char *game_str_wl_3_tyrant_3; extern const char *game_str_wl_3_tyrant_4; extern const char *game_str_wl_exile_1; extern const char *game_str_wl_exile_2; extern const char *game_str_wl_exile_3; extern const char *game_str_wl_exile_4; extern const char *game_str_gnn_end_good; extern const char *game_str_gnn_end_tyrant; extern const char *game_str_gnn_also; #endif 1oom-1.11.2/src/game/game_str_shipnames.c000066400000000000000000000030461476061725400202020ustar00rootroot00000000000000#include "config.h" #include "game_str.h" /* -------------------------------------------------------------------------- */ const char *game_str_tbl_ship_names[RACE_NUM * SHIP_NAME_NUM] = { "FIGHTER", "GUNBOAT", "COURIER", "FRIGATE", "DESTROYER", "CORVETTE", "CRUISER", "ESCORT", "WARSHIP", "DREADNOUGHT", "BATTLESHIP", "DREADSTAR", "WOLVERINE", "GRIFFIN", "FERRET", "LYNX", "CHEETAH", "BOBCAT", "PANTHER", "LEOPARD", "WARCAT", "SABRETOOTH", "PUMA", "TIGER", "PIRANHA", "STINGRAY", "MINNOW", "MANTA", "BARRACUDA", "MOREY", "SHARK", "MAKO", "WHALE", "KRAKEN", "MONITOR", "POLARIS", "GOBLIN", "CYCLOPS", "DAEMON", "BANSHEE", "SPECTRE", "SPIRIT", "JUGGERNAUT", "VALKYRIE", "HYDRA", "TITAN", "COLOSSUS", "DRAGON", "STARFIGHTER", "COMET", "SEEKER", "STAR WING", "STAR BLAZER", "STAR STREAK", "STAR BLADE", "DARK STAR", "CORAONA", "SUN FIRE", "STAR FURY", "NOVA", "FOXBAT", "SPARROWHAWK", "PELICAN", "FALCON", "SKY HAWK", "SPACE GULL", "WARBIRD", "WARHAWK", "WAREAGLE", "CONDOR", "DREADWING", "SKY MASTER", "SABRE", "CUTLASS", "DAGGER", "LANCER", "PEGASUS", "HORSEMAN", "RANGER", "KNIGHT", "AVENGER", "DRAGOON", "PALADIN", "EXCALIBER", "PAW", "PANDA", "PATROL", "HUNTER", "GLADIATOR", "SENTINEL", "CLAW", "TOOTH", "WARBEAR", "GRIZZLY", "PUNISHER", "RHINO", "MARAUDER", "HYPERION", "DRACHMA", "INTRUDER", "PENETRATOR", "TORMENTER", "AJAX", "TORNADO", "NEXUS", "NEMESIS", "DEVASTATOR", "ANNIHILATOR", "SPIDER", "BUMBLEBEE", "NEEDLE", "HORNET", "SCORPION", "VENOM", "TARANTULA", "VIPER", "COBRA", "KING COBRA", "BLACK WIDOW", "DEATH WYN" }; 1oom-1.11.2/src/game/game_strp.c000066400000000000000000000367301476061725400163210ustar00rootroot00000000000000#include "config.h" #include #include "game_strp.h" #include "gameapi.h" #include "game_str.h" #include "game_types.h" #include "lib.h" #include "log.h" /* -------------------------------------------------------------------------- */ static int patch_num = 0; static char **patch_tbl = NULL; /* -------------------------------------------------------------------------- */ #define DEFSTRITEMTBL(name) { #name, game_str_##name, sizeof(game_str_##name) / sizeof(game_str_##name[0]) } #define DEFSTRITEM(name) { #name, &game_str_##name, 1 } #define DEFSTREND { NULL, NULL, 0 } static const struct strtbl_s { const char *strid; const char **ptr; int size; } game_str_id_tbl[] = { DEFSTRITEM(mm_continue), DEFSTRITEM(mm_load), DEFSTRITEM(mm_new), DEFSTRITEM(mm_quit), DEFSTRITEMTBL(tbl_race), DEFSTRITEMTBL(tbl_races), DEFSTRITEMTBL(tbl_banner), DEFSTRITEMTBL(tbl_gsize), DEFSTRITEMTBL(tbl_diffic), DEFSTRITEMTBL(tbl_oppon), DEFSTRITEMTBL(tbl_traits), DEFSTRITEMTBL(tbl_trait1), DEFSTRITEMTBL(tbl_trait2), DEFSTRITEM(ng_choose_race), DEFSTRITEM(ng_choose_banner), DEFSTRITEM(ng_your_name), DEFSTRITEM(ng_home_name), DEFSTRITEM(ng_ai), DEFSTRITEM(ng_computer), DEFSTRITEM(ng_player), DEFSTRITEM(ng_cancel), DEFSTRITEM(ng_ok), DEFSTRITEM(ng_allai), DEFSTRITEMTBL(tbl_planet_names), DEFSTRITEMTBL(tbl_home_names), DEFSTRITEM(rndempname), DEFSTRITEM(planet_name_orion), DEFSTRITEMTBL(tbl_ship_names), DEFSTRITEMTBL(tbl_stship_names), DEFSTRITEMTBL(tbl_monsh_names), DEFSTRITEMTBL(tbl_mon_names), DEFSTRITEM(ai_colonyship), DEFSTRITEM(st_none), DEFSTRITEM(st_none2), DEFSTRITEMTBL(tbl_st_weap), DEFSTRITEMTBL(tbl_st_weapx), DEFSTRITEMTBL(tbl_st_comp), DEFSTRITEMTBL(tbl_st_engine), DEFSTRITEMTBL(tbl_st_armor), DEFSTRITEMTBL(tbl_st_shield), DEFSTRITEMTBL(tbl_st_jammer), DEFSTRITEMTBL(tbl_st_specsh), DEFSTRITEMTBL(tbl_st_special), DEFSTRITEMTBL(tbl_st_specialx), DEFSTRITEMTBL(tbl_st_hull), DEFSTRITEM(sm_crystal), DEFSTRITEM(sm_amoeba), DEFSTRITEM(sm_game), DEFSTRITEM(sm_design), DEFSTRITEM(sm_fleet), DEFSTRITEM(sm_map), DEFSTRITEM(sm_races), DEFSTRITEM(sm_planets), DEFSTRITEM(sm_tech), DEFSTRITEM(sm_next_turn), DEFSTRITEMTBL(tbl_sm_stinfo), DEFSTRITEM(sm_range), DEFSTRITEM(sm_parsec), DEFSTRITEM(sm_parsecs), DEFSTRITEM(sm_parsecs2), DEFSTRITEM(sm_colony), DEFSTRITEM(sm_lastrep), DEFSTRITEM(sm_stargate), DEFSTRITEM(sm_prodnone), DEFSTRITEM(sm_prod_y), DEFSTRITEM(sm_defupg), DEFSTRITEM(sm_defshld), DEFSTRITEM(sm_refit), DEFSTRITEM(sm_indmax), DEFSTRITEM(sm_indres), DEFSTRITEM(sm_ecowaste), DEFSTRITEM(sm_ecoclean), DEFSTRITEM(sm_ecoatmos), DEFSTRITEM(sm_ecotform), DEFSTRITEM(sm_ecosoil), DEFSTRITEM(sm_ecogaia), DEFSTRITEM(sm_ecopop), DEFSTRITEM(sm_unexplored), DEFSTRITEM(sm_nohabit), DEFSTRITEM(sm__planets), DEFSTRITEMTBL(tbl_sm_pltype), DEFSTRITEM(sm_plague), DEFSTRITEM(sm_nova), DEFSTRITEM(sm_comet), DEFSTRITEM(sm_pirates), DEFSTRITEM(sm_rebellion), DEFSTRITEM(sm_unrest), DEFSTRITEM(sm_accident), DEFSTRITEMTBL(tbl_sm_pgrowth), DEFSTRITEMTBL(tbl_sm_pspecial), DEFSTRITEM(sm_pop), DEFSTRITEM(sm_max), DEFSTRITEM(sm_hasreached), DEFSTRITEM(sm_indmaxof), DEFSTRITEM(sm_factories), DEFSTRITEM(sm_extrares), DEFSTRITEM(sm_popmaxof), DEFSTRITEM(sm_colonists), DEFSTRITEM(sm_hasterraf), DEFSTRITEMTBL(tbl_sm_terraf), DEFSTRITEM(sm_envwith), DEFSTRITEMTBL(tbl_sm_envmore), DEFSTRITEM(sm_stdgrow), DEFSTRITEM(sm_hasfsgate), DEFSTRITEM(sm_hasfshield), DEFSTRITEM(sm_planshield), DEFSTRITEM(sm_planratio), DEFSTRITEM(sm_fleetdep), DEFSTRITEM(sm_destoor), DEFSTRITEM(sm_destoor2), DEFSTRITEM(sm_parsfromcc), DEFSTRITEM(sm_eta), DEFSTRITEM(sm_turn), DEFSTRITEM(sm_turns), DEFSTRITEM(sm_chdest), DEFSTRITEM(sm_outsr), DEFSTRITEM(sm_sreloc), DEFSTRITEM(sm_sreloc2), DEFSTRITEM(sm_delay), DEFSTRITEM(sm_seltr), DEFSTRITEM(sm_notrange), DEFSTRITEM(sm_notrange1), DEFSTRITEM(sm_notrange2), DEFSTRITEM(sm_notrange3), DEFSTRITEM(sm_trfirste), DEFSTRITEM(sm_trcontr1), DEFSTRITEM(sm_trcontr2), DEFSTRITEM(sm_trfirstc), DEFSTRITEM(sm_trwarna), DEFSTRITEM(sm_trwarnm1), DEFSTRITEM(sm_trwarnm2), DEFSTRITEM(sm_trchnum1), DEFSTRITEM(sm_trchnum2), DEFSTRITEM(sm_trans1), DEFSTRITEM(sm_transs), DEFSTRITEM(sm_tdest), DEFSTRITEM(sm_bomb1), DEFSTRITEM(sm_bomb2), DEFSTRITEM(sm_trinb1), DEFSTRITEM(sm_trinb1s), DEFSTRITEM(sm_trinb2), DEFSTRITEM(sm_obomb1), DEFSTRITEM(sm_obomb2), DEFSTRITEM(sm_cdest1), DEFSTRITEM(sm_cdest2), DEFSTRITEM(sm_ineff1), DEFSTRITEM(sm_ineff2), DEFSTRITEM(sm_bkill1), DEFSTRITEM(sm_bkill2), DEFSTRITEM(sm_bfact1), DEFSTRITEM(sm_bfact1s), DEFSTRITEM(sm_bfact2), DEFSTRITEM(sm_traad1), DEFSTRITEM(sm_traad2), DEFSTRITEM(sm_trbdb1), DEFSTRITEM(sm_trbdb2), DEFSTRITEM(sm_inorbit), DEFSTRITEMTBL(tbl_roman), /* FIXME do we really need this to be modifiable? */ DEFSTRITEM(no_events), DEFSTRITEM(bc), DEFSTRITEM(y), DEFSTRITEM(year), DEFSTRITEM(player), DEFSTRITEM(pl_reserve), DEFSTRITEM(pl_plague), DEFSTRITEM(pl_nova), DEFSTRITEM(pl_comet), DEFSTRITEM(pl_pirates), DEFSTRITEM(pl_rebellion), DEFSTRITEM(pl_unrest), DEFSTRITEM(pl_accident), DEFSTRITEM(pl_spending), DEFSTRITEM(pl_tincome), DEFSTRITEM(pl_transof), DEFSTRITEM(pl_resto), DEFSTRITEM(sd_cancel), DEFSTRITEM(sd_build), DEFSTRITEM(sd_clear), DEFSTRITEM(sd_comp), DEFSTRITEM(sd_shield), DEFSTRITEM(sd_ecm), DEFSTRITEM(sd_armor), DEFSTRITEM(sd_engine), DEFSTRITEM(sd_man), DEFSTRITEMTBL(tbl_sd_spec), DEFSTRITEMTBL(tbl_sd_weap), DEFSTRITEM(sd_count), DEFSTRITEM(sd_sweap), DEFSTRITEM(sd_damage), DEFSTRITEM(sd_rng), DEFSTRITEM(sd_notes), DEFSTRITEM(sd_hp), DEFSTRITEM(sd_warp), DEFSTRITEM(sd_def), DEFSTRITEM(sd_cspeed), DEFSTRITEM(sd_absorbs), DEFSTRITEM(sd_hit), DEFSTRITEM(sd_hits), DEFSTRITEM(sd_misdef), DEFSTRITEM(sd_att), DEFSTRITEM(sd_comptype), DEFSTRITEM(sd_cost), DEFSTRITEM(sd_size), DEFSTRITEM(sd_power), DEFSTRITEM(sd_space), DEFSTRITEM(sd_comps), DEFSTRITEM(sd_shieldtype), DEFSTRITEM(sd_shields), DEFSTRITEM(sd_ecmtype), DEFSTRITEM(sd_ecm2), DEFSTRITEM(sd_armortype), DEFSTRITEM(sd_armor2), DEFSTRITEM(sd_engtype), DEFSTRITEM(sd_numengs), DEFSTRITEM(sd_engs), DEFSTRITEM(sd_man1), DEFSTRITEM(sd_man2), DEFSTRITEM(sd_class), DEFSTRITEM(sd_speed), DEFSTRITEM(sd_max), DEFSTRITEM(sd_weapname), DEFSTRITEM(sd_descr), DEFSTRITEM(sd_dmg), DEFSTRITEM(sd_weaps), DEFSTRITEM(sd_specname), DEFSTRITEM(sd_specs), DEFSTRITEM(sp_only6), DEFSTRITEM(sp_wantscrap), DEFSTRITEM(sp_before), DEFSTRITEM(sp_cost), DEFSTRITEM(fl_station), DEFSTRITEM(fl_inorbit), DEFSTRITEM(fl_moving), DEFSTRITEM(fl_unknown), DEFSTRITEM(fl_system), DEFSTRITEM(gm_tchar), DEFSTRITEMTBL(tbl_gm_spec), DEFSTRITEM(gm_unable), DEFSTRITEM(gm_prod), DEFSTRITEM(gm_tech), DEFSTRITEM(gm_1_3), DEFSTRITEM(gm_1_2), DEFSTRITEM(gm_2x), DEFSTRITEM(gm_3x), DEFSTRITEM(gm_4x), DEFSTRITEM(gm_prodb1), DEFSTRITEM(gm_prodb2), DEFSTRITEM(gm_prodb3), DEFSTRITEM(gm_gmap), DEFSTRITEM(gm_mapkey), DEFSTRITEM(bs_line1), DEFSTRITEM(bs_line2), DEFSTRITEM(bs_bases), DEFSTRITEMTBL(tbl_te_field), DEFSTRITEM(te_adv), DEFSTRITEM(te_tech), DEFSTRITEM(te_techno), DEFSTRITEM(te_techno2), DEFSTRITEM(te_genimp), DEFSTRITEM(te_nmis), DEFSTRITEM(te_nbomb), DEFSTRITEM(te_scrange), DEFSTRITEM(te_rctrl), DEFSTRITEM(te_col), DEFSTRITEM(te_fwaste), DEFSTRITEM(te_gcombat), DEFSTRITEM(te_tform), DEFSTRITEM(te_wasteel), DEFSTRITEM(te_shrange), DEFSTRITEM(te_max), DEFSTRITEM(te_rp), DEFSTRITEM(nt_achieve), DEFSTRITEM(nt_break), DEFSTRITEM(nt_infil), DEFSTRITEM(nt_ruins), DEFSTRITEM(nt_orion), DEFSTRITEM(nt_scouts), DEFSTRITEM(nt_choose), DEFSTRITEM(nt_reveal), DEFSTRITEM(nt_secrets), DEFSTRITEM(nt_frame), DEFSTRITEM(nt_victim), DEFSTRITEM(nt_doyou), DEFSTRITEM(nt_inc), DEFSTRITEM(nt_redueco), DEFSTRITEM(nt_ind), DEFSTRITEM(nt_ecoall), DEFSTRITEM(nt_terra), DEFSTRITEM(nt_def), DEFSTRITEM(nt_ecostd), DEFSTRITEM(nt_ecohost), DEFSTRITEMTBL(tbl_nt_adj), DEFSTRITEM(ra_nocont), DEFSTRITEM(ra_notpres), DEFSTRITEM(ra_secline1), DEFSTRITEM(ra_secline2), DEFSTRITEM(ra_alloc), DEFSTRITEM(ra_planres), DEFSTRITEM(ra_diplo), DEFSTRITEM(ra_gone), DEFSTRITEM(ra_nospies), DEFSTRITEM(ra_spy), DEFSTRITEM(ra_spies), DEFSTRITEMTBL(tbl_ra_treaty), DEFSTRITEM(ra_trade), DEFSTRITEM(ra_notrade), DEFSTRITEMTBL(tbl_ra_relat), DEFSTRITEM(ra_stats), DEFSTRITEM(re_reportis), DEFSTRITEM(re_current), DEFSTRITEM(re_yearsold), DEFSTRITEM(re_alliance), DEFSTRITEM(re_wars), DEFSTRITEM(re_environ), DEFSTRITEM(sc_caught), DEFSTRITEM(bp_scombat), DEFSTRITEM(bp_attack), DEFSTRITEM(bp_attacks), DEFSTRITEM(bp_won), DEFSTRITEM(bt_auto_move), DEFSTRITEM(bt_pop), DEFSTRITEM(bt_ind), DEFSTRITEM(bt_bases), DEFSTRITEM(bt_subint), DEFSTRITEM(bt_launch), DEFSTRITEM(bt_coldest), DEFSTRITEM(es_youresp1), DEFSTRITEM(es_youresp2), DEFSTRITEM(es_youresp3), DEFSTRITEM(es_thesp1), DEFSTRITEM(es_thesp2), DEFSTRITEM(es_unkn), DEFSTRITEM(sb_choose), DEFSTRITEM(sb_lastrep), DEFSTRITEM(sb_pop), DEFSTRITEM(sb_fact), DEFSTRITEM(sb_bases), DEFSTRITEM(sb_unkn), DEFSTRITEM(sb_your), DEFSTRITEM(sb_spies), DEFSTRITEM(sb_increv), DEFSTRITEM(sb_inc1), DEFSTRITEM(sb_inc2), DEFSTRITEM(sb_destr), DEFSTRITEM(sb_fact2), DEFSTRITEM(sb_facts), DEFSTRITEM(sb_mbase), DEFSTRITEM(sb_mbases), DEFSTRITEM(sb_failed), DEFSTRITEM(sb_nofact), DEFSTRITEM(sb_nobases), DEFSTRITEM(sb_noinc), DEFSTRITEM(sb_frame), DEFSTRITEM(ex_planeta), DEFSTRITEM(ex_scanner), DEFSTRITEM(ex_scout), DEFSTRITEM(ex_explore), DEFSTRITEM(ex_starsys), DEFSTRITEM(ex_build), DEFSTRITEM(ex_colony), DEFSTRITEM(ex_popgr), DEFSTRITEM(ex_resopnt), DEFSTRITEM(ex_fromind), DEFSTRITEM(ex_techpnt), DEFSTRITEM(ex_fromres), DEFSTRITEM(ex_aredbl), DEFSTRITEM(ex_arequad), DEFSTRITEMTBL(ex_pg1), DEFSTRITEMTBL(ex_pg2), DEFSTRITEMTBL(ex_pg3), DEFSTRITEMTBL(ex_ps1), DEFSTRITEMTBL(ex_ps2), DEFSTRITEM(la_colony), DEFSTRITEM(la_inyear), DEFSTRITEM(la_the), DEFSTRITEM(la_formnew), DEFSTRITEM(gr_carmor), DEFSTRITEM(gr_outof), DEFSTRITEM(gr_transs), DEFSTRITEM(gr_reclaim), DEFSTRITEM(gr_penetr), DEFSTRITEM(gr_defenss), DEFSTRITEM(gr_troops), DEFSTRITEM(gr_rebel), DEFSTRITEM(gr_gcon), DEFSTRITEM(gr_scapt), DEFSTRITEM(gr_itroops), DEFSTRITEM(gr_succd), DEFSTRITEM(gr_fcapt), DEFSTRITEM(gr_tsteal), DEFSTRITEM(gr_tnew), DEFSTRITEM(el_no), DEFSTRITEM(el_vote), DEFSTRITEM(el_votes), DEFSTRITEM(el_total), DEFSTRITEM(el_start), DEFSTRITEM(el_emperor), DEFSTRITEM(el_ofthe), DEFSTRITEM(el_and), DEFSTRITEM(el_for), DEFSTRITEM(el_nomin), DEFSTRITEM(el_abs1), DEFSTRITEM(el_abs2), DEFSTRITEM(el_dots), DEFSTRITEM(el_your), DEFSTRITEM(el_bull), DEFSTRITEM(el_self), DEFSTRITEM(el_abs), DEFSTRITEM(el_neither), DEFSTRITEM(el_accept), DEFSTRITEM(el_yes), DEFSTRITEM(el_no2), DEFSTRITEM(el_sobeit), DEFSTRITEM(el_isnow), DEFSTRITEM(au_facts), DEFSTRITEM(au_bases), DEFSTRITEM(au_treaty), DEFSTRITEM(au_allian), DEFSTRITEM(au_nonagg), DEFSTRITEM(au_tradea), DEFSTRITEM(au_amreca), DEFSTRITEM(au_tech), DEFSTRITEM(au_framed), DEFSTRITEM(au_bull), DEFSTRITEM(au_inxchng), DEFSTRITEM(au_whatif1), DEFSTRITEM(au_whatif2), DEFSTRITEM(au_perrec1), DEFSTRITEM(au_ques), DEFSTRITEM(au_howmay), DEFSTRITEM(au_youprte), DEFSTRITEM(au_youprta), DEFSTRITEM(au_youract), DEFSTRITEM(au_whatech), DEFSTRITEM(au_whatrad), DEFSTRITEM(au_whatoff), DEFSTRITEM(au_perthr1), DEFSTRITEM(au_perthr2), DEFSTRITEM(au_alsoof1), DEFSTRITEM(au_alsoof2), DEFSTRITEM(au_whowar), DEFSTRITEM(au_whobrk), DEFSTRITEM(au_whattr), DEFSTRITEM(au_techn), DEFSTRITEM(au_nextp), DEFSTRITEM(au_back), DEFSTRITEMTBL(au_opts_main), DEFSTRITEMTBL(au_opts_treaty), DEFSTRITEMTBL(au_opts_agree), DEFSTRITEMTBL(au_opts_accept), DEFSTRITEMTBL(au_opts_threaten), DEFSTRITEMTBL(au_optsmp1), DEFSTRITEM(tr_cont1), DEFSTRITEM(tr_cont2), DEFSTRITEM(tr_fuel1), DEFSTRITEM(tr_fuel2), DEFSTRITEM(sv_envir), DEFSTRITEM(sv_stargt), DEFSTRITEM(sv_shild1), DEFSTRITEM(sv_shild2), DEFSTRITEM(sv_psize), DEFSTRITEM(sv_fact), DEFSTRITEM(sv_waste), DEFSTRITEM(sv_pop), DEFSTRITEM(sv_growth), DEFSTRITEM(sv_techp), DEFSTRITEM(sv_resp), DEFSTRITEM(sv_1_3x), DEFSTRITEM(sv_1_2x), DEFSTRITEM(sv_2x), DEFSTRITEM(sv_3x), DEFSTRITEM(sv_4x), DEFSTRITEM(sv_popgr), DEFSTRITEMTBL(sv_pg1), DEFSTRITEMTBL(sv_pg2), DEFSTRITEM(in_loading), DEFSTRITEM(wl_won_1), DEFSTRITEM(wl_won_2), DEFSTRITEM(wl_won_3), DEFSTRITEM(wl_3_good_1), DEFSTRITEM(wl_3_good_2), DEFSTRITEM(wl_3_tyrant_1), DEFSTRITEM(wl_3_tyrant_2), DEFSTRITEM(wl_3_tyrant_3), DEFSTRITEM(wl_3_tyrant_4), DEFSTRITEM(wl_exile_1), DEFSTRITEM(wl_exile_2), DEFSTRITEM(wl_exile_3), DEFSTRITEM(wl_exile_4), DEFSTRITEM(gnn_end_good), DEFSTRITEM(gnn_end_tyrant), DEFSTRITEM(gnn_also), DEFSTREND }; /* -------------------------------------------------------------------------- */ static const char **find_match(const char *strid, int i) { const struct strtbl_s *s = &game_str_id_tbl[0]; while (s->strid) { if (strcmp(s->strid, strid) == 0) { if (i < s->size) { return &s->ptr[i]; } else { log_error("STR: strid '%s' index %i >= size %i\n", strid, i, s->size); return NULL; } } ++s; } log_error("STR: unknown strid '%s'\n", strid); return NULL; } /* -------------------------------------------------------------------------- */ bool game_str_patch(const char *strid, const char *patchstr, int i) { const char **p = find_match(strid, i); if (p) { char *n = lib_stralloc(patchstr); patch_tbl = lib_realloc(patch_tbl, patch_num + 1); patch_tbl[patch_num++] = n; *p = n; return true; } else { return false; } } void game_str_dump(void) { const struct strtbl_s *s = &game_str_id_tbl[0]; log_message("# dump of all game strings\n"); while (s->strid) { for (int i = 0; (i < s->size); ++i) { log_message("3,%s,%i,\"%s\"\n", s->strid, i, s->ptr[i]); } ++s; } } void game_str_shutdown(void) { if (patch_tbl) { for (int i = 0; i < patch_num; ++i) { lib_free(patch_tbl[i]); patch_tbl[i] = NULL; } lib_free(patch_tbl); patch_tbl = NULL; } } 1oom-1.11.2/src/game/game_strp.h000066400000000000000000000002111476061725400163070ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_STRP_H #define INC_1OOM_GAME_STRP_H extern void game_str_shutdown(void); extern void game_str_dump(void); #endif 1oom-1.11.2/src/game/game_tech.c000066400000000000000000001064361476061725400162550ustar00rootroot00000000000000#include "config.h" #include #include "game_tech.h" #include "bits.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_aux.h" #include "game_misc.h" #include "game_num.h" #include "game_shiptech.h" #include "game_str.h" #include "game_techtypes.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define RESEARCH_D0_PTR(ga_, f_, t_) ((const uint8_t *)&((ga_)->research.d0[((f_) * 50 + (t_) - 1) * 6])) const uint8_t tech_reduce_50percent_per_10pts[51] = { 100, 93, 87, 81, 76, 71, 66, 62, 58, 54, 50, 47, 44, 41, 38, 35, 33, 31, 29, 27, 25, 23, 22, 20, 19, 18, 16, 15, 14, 13, 13, 12, 11, 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5, 5, 4, 4, 4, 4, 3, 3 }; const uint8_t tech_reduce_25percent_per_10pts[51] = { 100, 97, 94, 92, 89, 87, 84, 82, 79, 77, 75, 73, 71, 69, 67, 65, 63, 61, 60, 58, 56, 55, 53, 52, 50, 49, 47, 46, 45, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 27, 26, 25, 24, 24 }; /* -------------------------------------------------------------------------- */ static uint8_t find_byte_in_tbl(uint8_t b, const uint8_t *tbl, uint32_t len) { while (len) { if (*tbl++ == b) { return b; } --len; } return 0; } static uint8_t get_tech_reduce_50(uint8_t percent/*1..100*/) { SETMIN(percent, 50); return tech_reduce_50percent_per_10pts[percent - 1]; } static uint16_t get_base_cost_mod_armor(const struct game_s *g, int player_i, int percent) { uint16_t tech_i = 0; uint8_t mult; for (int i = 0; i < SHIP_ARMOR_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_CONSTRUCTION, tbl_shiptech_armor[i].tech_i, player_i)) { tech_i = i; } } if (tech_i) { --tech_i; } mult = get_tech_reduce_50(percent); return ((tbl_shiptech_armor[tech_i].cost[SHIP_HULL_LARGE] + tbl_shiptech_hull[SHIP_HULL_LARGE].cost) * mult) / 1500; } static uint16_t get_base_cost_mod_weap(const struct game_s *g, int tech_i, int percent) { uint16_t mult = get_tech_reduce_50(percent) * 9; return (tbl_shiptech_weap[tech_i].cost * mult) / 1000; } static uint16_t get_base_cost_mod_shield(const struct game_s *g, int tech_i, int percent) { uint16_t mult = get_tech_reduce_50(percent); return (tbl_shiptech_shield[tech_i].cost[SHIP_HULL_LARGE] * mult) / 1000 + tbl_shiptech_shield[tech_i].power[SHIP_HULL_LARGE] / 10; } static uint16_t get_base_cost_mod_comp(const struct game_s *g, int tech_i, int percent) { uint16_t mult = get_tech_reduce_50(percent); return (tbl_shiptech_comp[tech_i].cost[SHIP_HULL_LARGE] * mult) / 1000 + tbl_shiptech_comp[tech_i].power[SHIP_HULL_LARGE] / 10; } static uint16_t get_base_cost_mod_jammer(const struct game_s *g, int player_i, int percent) { uint16_t tech_i = 0; uint8_t mult; for (int i = 0; i < SHIP_JAMMER_NUM; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_COMPUTER, tbl_shiptech_jammer[i].tech_i, player_i)) { tech_i = i; } } mult = get_tech_reduce_50(percent); return (tbl_shiptech_jammer[tech_i].cost[SHIP_HULL_LARGE] * mult) / 1000 + tbl_shiptech_jammer[tech_i].power[SHIP_HULL_LARGE] / 10; } static uint8_t find_best_tech_type(BOOLVEC_PTRPARAMI(tbl), int base, int step, int last) { int best = 0; for (int i = base; i <= last; i += step) { if (BOOLVEC_IS1(tbl, i)) { best = i; } } return (uint8_t)best; } static void game_tech_add_newtech(struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech, techsource_t source, int a8, player_id_t stolen_from, bool frame) { newtechs_t *nts = &(g->evn.newtech[player]); int num = nts->num; if (num < NEWTECH_MAX) { newtech_t *nt = &(nts->d[num]); nt->field = field; nt->tech = tech; nt->source = source; nt->v06 = a8; nt->stolen_from = stolen_from; nt->other1 = PLAYER_NONE; nt->other2 = PLAYER_NONE; if (source != TECHSOURCE_SPY) { frame = false; } if (frame) { const empiretechorbit_t *et; et = &(g->eto[stolen_from]); for (player_id_t i = 0; (i < g->players) && (nt->other2 == PLAYER_NONE); ++i) { if ((i != player) && BOOLVEC_IS1(et->contact, i)) { if (nt->other1 == PLAYER_NONE) { nt->other1 = i; } else { nt->other2 = i; } } } if (nt->other2 == PLAYER_NONE) { nt->other1 = PLAYER_NONE; frame = false; } } nt->frame = frame; nts->num = num + 1; } } static uint8_t game_tech_get_next_techs(const struct game_s *g, player_id_t player, tech_field_t field, uint8_t *tbl) { const uint8_t *rc = g->srd[player].researchcompleted[field]; int num, maxtier, len = g->eto[player].tech.completed[field]; const uint8_t (*rl)[3] = g->srd[player].researchlist[field]; uint8_t tmax = 0; for (int i = 0; i < len; ++i) { uint8_t t; t = rc[i]; SETMAX(tmax, t); } if (len == 1) { maxtier = 1; } else { maxtier = (tmax - 1) / 5 + 2; SETMIN(maxtier, 10); } num = 0; for (int tier = 0; tier < maxtier; ++tier) { for (int l = 0; l < 3; ++l) { uint8_t t; t = rl[tier][l]; if (t != 0) { bool have; have = false; for (int i = 0; i < len; ++i) { if (rc[i] == t) { have = true; break; } } if ((!have) && (num < TECH_NEXT_MAX)) { tbl[num++] = t; } } } } if (num == 0) { if (tmax <= 50) { tmax = 55; } else { tmax += 5; SETMIN(tmax, 100); } for (uint8_t t = 55; t <= tmax; t += 5) { bool have; have = false; for (int i = len - 1; i >= 0; --i) { if (rc[i] == t) { have = true; break; } } if ((!have) && (num < TECH_NEXT_MAX)) { tbl[num++] = t; } } } return num; } static void game_tech_ai_tech_next(struct game_s *g, player_id_t player, tech_field_t field) { uint8_t tbl[TECH_NEXT_MAX]; uint8_t num = game_tech_get_next_techs(g, player, field, tbl); if (num != 0) { uint8_t tech = game_ai->tech_next(g, player, field, tbl, num); game_tech_start_next(g, player, field, tech); } } static void game_tech_share(struct game_s *g, tech_field_t f, bool accepted, bool from_dead) { player_id_t tbl_source[TECH_MAX_LEVEL + 1]; uint8_t maxtech = 0; BOOLVEC_DECLARE(tbl_techcompl, TECH_MAX_LEVEL + 1); BOOLVEC_CLEAR(tbl_techcompl, TECH_MAX_LEVEL + 1); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((BOOLVEC_IS0(g->refuse, pi) == accepted) && (from_dead || IS_ALIVE(g, pi))) { /* BUG MOO1 takes tech also from dead races */ uint8_t *p = g->srd[pi].researchcompleted[f]; uint32_t len = g->eto[pi].tech.completed[f]; while (len--) { uint8_t tech_i; tech_i = *p++; BOOLVEC_SET1(tbl_techcompl, tech_i); SETMAX(maxtech, tech_i); tbl_source[tech_i] = pi; } } } for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((BOOLVEC_IS1(g->refuse, pi) == accepted) || (!IS_ALIVE(g, pi))) { continue; } if (IS_AI(g, pi)) { uint8_t *p = g->srd[pi].researchcompleted[f]; int n; n = 0; for (uint8_t tech_i = 0; tech_i <= maxtech; ++tech_i) { if (BOOLVEC_IS1(tbl_techcompl, tech_i)) { p[n++] = tech_i; } } g->eto[pi].tech.completed[f] = n; } else { for (uint8_t tech_i = 0; (tech_i <= maxtech) && (g->evn.newtech[pi].num < NEWTECH_MAX); ++tech_i) { if (BOOLVEC_IS1(tbl_techcompl, tech_i) && (!game_tech_player_has_tech(g, f, tech_i, pi))) { game_tech_get_new(g, pi, f, tech_i, TECHSOURCE_TRADE, tbl_source[tech_i], PLAYER_NONE, false); } } } } } /* -------------------------------------------------------------------------- */ uint8_t game_tech_player_has_tech(const struct game_s *g, int field_i, int tech_i, int player_i) { const uint8_t *p = g->srd[player_i].researchcompleted[field_i]; uint32_t len = g->eto[player_i].tech.completed[field_i]; return find_byte_in_tbl(tech_i, p, len); } uint8_t game_tech_player_best_tech(const struct game_s *g, int field_i, int tech_i_base, int tech_i_step, int tech_i_max, int player_i) { uint8_t tech_best = 0; for (int tech_i = (tech_i_base >= 2) ? tech_i_base : tech_i_step; tech_i < tech_i_max; tech_i += tech_i_step) { if (game_tech_player_has_tech(g, field_i, tech_i, player_i)) { tech_best = tech_i; } } return tech_best; } uint16_t game_get_base_cost(const struct game_s *g, int player_i) { const uint8_t *p = g->eto[player_i].tech.percent; const empiretechorbit_t *e = &(g->eto[player_i]); uint16_t cost; cost = get_base_cost_mod_armor(g, player_i, p[TECH_FIELD_CONSTRUCTION]); cost += get_base_cost_mod_weap(g, e->base_weapon, p[TECH_FIELD_WEAPON]); cost += get_base_cost_mod_shield(g, e->base_shield, p[TECH_FIELD_FORCE_FIELD]); cost += get_base_cost_mod_comp(g, e->base_comp, p[TECH_FIELD_COMPUTER]); cost += get_base_cost_mod_jammer(g, player_i, p[TECH_FIELD_COMPUTER]); cost = (cost * 3) / 5; if (BOOLVEC_IS1(g->is_ai, player_i)) { switch (g->difficulty) { case 1: cost = (cost * 9) / 10; break; case 2: cost = (cost * 8) / 10; break; case 3: cost = (cost * 7) / 10; break; case 4: cost /= 2; break; default: break; } } if (cost < 50) { cost = 50; } return cost; } uint8_t game_get_base_weapon(const struct game_s *g, player_id_t player_i, int tech_i) { uint8_t r = WEAPON_LASER; /* BUG? */ for (int i = 0; i < WEAPON_NUM; ++i) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[i]); if (1 && (w->tech_i <= tech_i) && (w->damagemin == w->damagemax) && (w->numshots == 2) && (w->misstype == 0) && (!w->is_bio) && (w->nummiss == 1) && game_tech_player_has_tech(g, TECH_FIELD_WEAPON, w->tech_i, player_i) ) { r = i; } } return r; } uint8_t game_get_base_weapon_2(const struct game_s *g, player_id_t player_i, int tech_i, uint8_t r) { for (int i = 0; i < WEAPON_PLASMA_TORPEDO; ++i) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[i]); if (1 && (w->nummiss > 1) && game_tech_player_has_tech(g, TECH_FIELD_WEAPON, w->tech_i, player_i) ) { r = i; } } return r; } uint8_t game_get_best_shield(struct game_s *g, player_id_t player_i, int tech_i) { uint8_t r = 0; for (int i = 0; i < SHIP_SHIELD_NUM; ++i) { const struct shiptech_shield_s *w = &(tbl_shiptech_shield[i]); if (1 && (w->tech_i <= tech_i) && game_tech_player_has_tech(g, TECH_FIELD_FORCE_FIELD, w->tech_i, player_i) ) { r = i; } } return r; } uint8_t game_get_best_comp(struct game_s *g, player_id_t player_i, int tech_i) { uint8_t r = 0; for (int i = 0; i < SHIP_COMP_NUM; ++i) { const struct shiptech_comp_s *w = &(tbl_shiptech_comp[i]); if (1 && (w->tech_i <= tech_i) && game_tech_player_has_tech(g, TECH_FIELD_COMPUTER, w->tech_i, player_i) ) { r = i; } } return r; } uint8_t game_get_best_jammer(const struct game_s *g, player_id_t player_i, int tech_i) { uint8_t r = 0; for (int i = 0; i < SHIP_JAMMER_NUM; ++i) { const struct shiptech_jammer_s *w = &(tbl_shiptech_jammer[i]); if (1 && (w->tech_i <= tech_i) && game_tech_player_has_tech(g, TECH_FIELD_COMPUTER, w->tech_i, player_i) ) { r = i; } } return r; } void game_update_tech_util(struct game_s *g) { BOOLVEC_TBL_DECLARE(tbl_techcompl, TECH_FIELD_NUM, 50 + 1); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); uint8_t b, tech_i; BOOLVEC_TBL_CLEAR(tbl_techcompl, TECH_FIELD_NUM, 50 + 1); for (tech_field_t field_i = TECH_FIELD_COMPUTER; field_i < TECH_FIELD_NUM; ++field_i) { uint8_t *p = g->srd[pi].researchcompleted[field_i]; uint32_t len = e->tech.completed[field_i]; while (len--) { tech_i = *p++; if (tech_i <= 50) { BOOLVEC_TBL_SET1(tbl_techcompl, field_i, tech_i); } } } e->have_colony_for = PLANET_TYPE_MINIMAL; for (int i = 0; i < 6; ++i) { if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, i * 3 + 3)) { e->have_colony_for = PLANET_TYPE_BARREN - i; } } if (e->race == RACE_SILICOID) { e->have_colony_for = PLANET_TYPE_RADIATED; } e->have_adv_soil_enrich = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 30); e->have_atmos_terra = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 22); e->have_soil_enrich = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 16); if (e->race == RACE_SILICOID) { e->have_adv_soil_enrich = false; e->have_atmos_terra = false; e->have_soil_enrich = false; } if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 42)) { e->inc_pop_cost = 5; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 21)) { e->inc_pop_cost = 10; } else { e->inc_pop_cost = 20; } if (e->race == RACE_SAKKRA) { e->inc_pop_cost = (e->inc_pop_cost * 2) / 3; } tech_i = find_best_tech_type(BOOLVEC_TBL_PTRPARAMM(tbl_techcompl, TECH_FIELD_PLANETOLOGY), 2, 6, 50); b = (tech_i > 0) ? (((tech_i - 2) / 6 + 1) * 10) : 0; if (b == 90) { b = 120; } else if (b == 80) { b = 100; } else if (b == 70) { b = 80; } e->have_terraform_n = b; b = (tech_i > 0) ? (5 - ((tech_i - 2) / 12)) : 5; if (b < 2) { b = 2; } e->terraform_cost_per_inc = b; e->have_combat_transporter = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 45); b = 2; if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 5)) { b = 3; } if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 13)) { b = 5; } if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 24)) { b = 10; } if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 34)) { b = 20; } e->have_eco_restoration_n = b; if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 23)) { b = 9; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 13)) { b = 7; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 4)) { b = 5; } else { b = 3; } e->scanner_range = b; e->have_stargates = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 27); e->have_hyperspace_comm = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 34); e->have_ia_scanner = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 13) || BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 23); e->have_adv_scanner = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_COMPUTER, 23); tech_i = find_best_tech_type(BOOLVEC_TBL_PTRPARAMM(tbl_techcompl, TECH_FIELD_COMPUTER), 8, 10, 50); b = (tech_i > 0) ? ((tech_i + 12) / 10 + 1) : 2; if (e->race == RACE_MEKLAR) { b += 2; } e->colonist_oper_factories = b; if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 38)) { b = 2; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 33)) { b = 3; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 28)) { b = 4; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 23)) { b = 5; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 18)) { b = 6; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 13)) { b = 7; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 8)) { b = 8; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 3)) { b = 9; } else { b = 10; } e->factory_cost = b; if (e->race != RACE_MEKLAR) { b = (b * e->colonist_oper_factories) / 2; } e->factory_adj_cost = b; if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 45)) { b = 0; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 35)) { b = 2; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 25)) { b = 4; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 15)) { b = 6; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_CONSTRUCTION, 5)) { b = 8; } else { b = 10; } e->ind_waste_scale = b; if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 41)) { b = 30; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 29)) { b = 10; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 23)) { b = 9; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 19)) { b = 8; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 14)) { b = 7; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 9)) { b = 6; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 5)) { b = 5; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 3)) { b = 4; } else { b = 3; } e->fuel_range = b; tech_i = find_best_tech_type(BOOLVEC_TBL_PTRPARAMM(tbl_techcompl, TECH_FIELD_FORCE_FIELD), 2, 10, 50); if (tech_i < 10) { tech_i = 0; } b = (tech_i > 0) ? (5 * ((tech_i - 2) / 10)) : 0; e->have_planet_shield = b; e->planet_shield_cost = game_num_pshield_cost[b / 5]; b = 1; for (int i = 6; i < 50; i += 6) { if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, i)) { b = (i - 6) / 6 + 1; } } e->have_engine = b; e->have_sub_space_int = BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PROPULSION, 43); if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 36)) { b = 2; } else if (BOOLVEC_TBL_IS1(tbl_techcompl, TECH_FIELD_PLANETOLOGY, 17)) { b = 1; } else { b = 0; } e->antidote = b; if (g->gaux->flag_cheat_galaxy) { e->scanner_range = 30; } } } uint8_t game_tech_get_group(const struct game_aux_s *gaux, tech_field_t field, int tech) { return RESEARCH_D0_PTR(gaux, field, tech)[0]; } uint8_t game_tech_get_tier(const struct game_aux_s *gaux, tech_field_t field, int tech) { return (game_tech_get_group(gaux, field, tech) == 0xff) ? 0 : RESEARCH_D0_PTR(gaux, field, tech)[1]; } uint8_t game_tech_get_gfx_i(const struct game_aux_s *gaux, tech_field_t field, int tech) { return RESEARCH_D0_PTR(gaux, field, tech)[2]; } const char *game_tech_get_name(const struct game_aux_s *gaux, tech_field_t field, int tech, char *buf, size_t bufsize) { if (tech == 0) { lib_sprintf(buf, bufsize, "%s %s", game_str_tbl_te_field[field], game_str_te_techno); } else if (tech == -2) { lib_strcpy(buf, game_str_tbl_st_weap[WEAPON_NUCLEAR_MISSILE_2 - 1], bufsize); } else if (tech == -1) { lib_strcpy(buf, game_str_tbl_st_weap[WEAPON_NUCLEAR_BOMB - 1], bufsize); } else if (tech > 50) { lib_sprintf(buf, bufsize, "%s %s %s %s", game_str_te_adv, game_str_tbl_te_field[field], game_str_te_tech, game_str_tbl_roman[(tech - 50) / 5]); } else { const uint8_t *p = RESEARCH_D0_PTR(gaux, field, tech); if (p[0] != 0xff) { int offs = GET_LE_16(&p[4]); lib_strcpy(buf, &(gaux->research.names[offs]), bufsize); } else { buf[0] = '\0'; } } return buf; } const char *game_tech_get_descr(const struct game_aux_s *gaux, tech_field_t field, int tech, char *buf, size_t bufsize) { if (tech == 0) { buf[0] = '\0'; } else if (tech > 50) { lib_sprintf(buf, bufsize, "%s %s %s.", game_str_te_genimp, game_str_tbl_te_field[field], game_str_te_techno2); } else if (tech == -2) { lib_strcpy(buf, game_str_te_nmis, bufsize); } else if (tech == -1) { lib_strcpy(buf, game_str_te_nbomb, bufsize); } else { lib_strcpy(buf, &(gaux->research.descr[(field * 50 + tech - 1) * RESEARCH_DESCR_LEN]), bufsize); } return buf; } const char *game_tech_get_newtech_msg(const struct game_s *g, player_id_t pi, struct newtech_s *nt, char *buf, size_t bufsize) { race_t race = g->eto[pi].race; switch (nt->source) { case TECHSOURCE_RESEARCH: lib_sprintf(buf, bufsize, "%s %s %s %s", game_str_tbl_race[race], game_str_nt_achieve, game_str_tbl_te_field[nt->field], game_str_nt_break); break; case TECHSOURCE_SPY: lib_sprintf(buf, bufsize, "%s %s %s", game_str_tbl_race[race], game_str_nt_infil, g->planet[nt->v06].name); break; case TECHSOURCE_FOUND: if (nt->v06 == NEWTECH_V06_ORION) { lib_strcpy(buf, game_str_nt_orion, bufsize); } else if (nt->v06 >= 0) { /* WASBUG > 0 vs. scout case with planet 0 */ lib_sprintf(buf, bufsize, "%s %s %s", game_str_nt_ruins, g->planet[nt->v06].name, game_str_nt_discover); } else { lib_sprintf(buf, bufsize, "%s %s %s", game_str_nt_scouts, g->planet[-(nt->v06 + 1)].name, game_str_nt_discover); } break; case TECHSOURCE_CHOOSE: lib_strcpy(buf, game_str_nt_choose, bufsize); break; case TECHSOURCE_TRADE: lib_sprintf(buf, bufsize, "%s %s %s %s", game_str_tbl_race[g->eto[nt->v06].race], game_str_nt_reveal, game_str_tbl_te_field[nt->field], game_str_nt_secrets); break; default: buf[0] = '\0'; break; } return buf; } int game_tech_current_research_percent1(const struct game_s *g, player_id_t player, tech_field_t field) { uint32_t invest, cost; int slider, t1, t3, percent; const empiretechorbit_t *e = &(g->eto[player]); cost = game_tech_get_field_cost(g, player, field); slider = e->tech.slider[field]; if ((cost == 0) || (slider == 0)) { return 0; } invest = e->tech.investment[field]; t1 = (invest * 3) / 20; t3 = (slider * e->total_research_bc) / 100; SETMIN(t1, t3 * 2); invest += t3 + t1; percent = (invest * 100) / cost; return percent; } int game_tech_current_research_percent2(const struct game_s *g, player_id_t player, tech_field_t field) { uint32_t invest, cost; int slider, t1, t3; const empiretechorbit_t *e = &(g->eto[player]); cost = game_tech_get_field_cost(g, player, field); slider = e->tech.slider[field]; if ((cost == 0) || (slider == 0)) { return 0; } invest = e->tech.investment[field]; t1 = (invest * 3) / 20; t3 = (slider * e->total_research_bc) / 100; SETMIN(t1, t3 * 2); invest += t3 + t1; if (invest <= cost) { return 0; } else { int percent = ((invest - cost) * 50) / cost; SETRANGE(percent, 0, 99); return percent; } } bool game_tech_current_research_has_max_bonus(const struct game_s *g, player_id_t player, tech_field_t field) { uint32_t invest, cost; int slider, t1, t3; const empiretechorbit_t *e = &(g->eto[player]); cost = game_tech_get_field_cost(g, player, field); slider = e->tech.slider[field]; if ((cost == 0) || (slider == 0)) { return false; } invest = e->tech.investment[field]; t1 = (invest * 3) / 20; t3 = (slider * e->total_research_bc) / 100; return (t1 <= (t3 * 2) && t3 > 0); } void game_tech_set_to_max_bonus(struct game_s *g, player_id_t player, tech_field_t field) { bool has_bonus, had_bonus = game_tech_current_research_has_max_bonus(g, player, field); empiretechorbit_t *e = &(g->eto[player]); techdata_t *t = &(e->tech); int16_t prev, v = t->slider[field]; do { prev = v; v += had_bonus ? -1 : 1; SETRANGE(v, 0, 100); t->slider[field] = v; game_adjust_slider_group(t->slider, field, v, TECH_FIELD_NUM, t->slider_lock); has_bonus = game_tech_current_research_has_max_bonus(g, player, field); v = t->slider[field]; } while ((has_bonus == had_bonus) && (v != prev)); } void game_tech_get_new(struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech, techsource_t source, int a8, player_id_t stolen_from, bool flag_frame) { empiretechorbit_t *e = &(g->eto[player]); shipresearch_t *srd = &(g->srd[player]); uint8_t *rc = srd->researchcompleted[field]; /*di*/int tc = e->tech.completed[field]; bool have_tech = false; for (int i = 0; i < tc; ++i) { if (rc[i] == tech) { have_tech = true; break; } } if (have_tech || (tech == 0)) { /*6365a*/ if (e->tech.project[field] == tech) { if (IS_HUMAN(g, player)) { e->tech.project[field] = 0; if (source == 4) { game_tech_add_newtech(g, player, field, tech, source, a8, stolen_from, flag_frame); } } else { /*6374b*/ game_tech_ai_tech_next(g, player, field); } } } else { /*6375b*/ rc[tc++] = tech; e->tech.completed[field] = tc; for (int loops = 0; loops < tc; ++loops) { for (int i = 0; i < (tc - 1); ++i) { uint8_t t0, t1; t0 = rc[i]; t1 = rc[i + 1]; if (t0 > t1) { rc[i + 1] = t0; rc[i] = t1; } } } if (IS_HUMAN(g, player)) { game_tech_add_newtech(g, player, field, tech, source, a8, stolen_from, flag_frame); } /*63899*/ if (e->tech.project[field] == tech) { e->tech.project[field] = 0; e->tech.investment[field] = 1; } /*63967*/ if ((e->tech.project[field] == 0) && IS_AI(g, player)) { game_tech_ai_tech_next(g, player, field); } } } void game_tech_finish_new(struct game_s *g, player_id_t pi) { empiretechorbit_t *e = &(g->eto[pi]); BOOLVEC_DECLARE(can_choose, TECH_FIELD_NUM); BOOLVEC_CLEAR(can_choose, TECH_FIELD_NUM); for (int i = 0; i < g->evn.newtech[pi].num; ++i) { newtech_t *nt = &(g->evn.newtech[pi].d[i]); if (e->tech.project[nt->field] == nt->tech) { BOOLVEC_SET1(can_choose, nt->field); } } for (tech_field_t field = 0; field < TECH_FIELD_NUM; ++field) { nexttech_t *xt = &(g->evn.newtech[pi].next[field]); if ((e->tech.project[field] == 0) && (e->tech.investment[field] > 0)) { BOOLVEC_SET1(can_choose, field); } memset(xt->tech, 0, sizeof(xt->tech)); if (BOOLVEC_IS1(can_choose, field)) { xt->num = game_tech_get_next_techs(g, pi, field, xt->tech); } else { xt->num = 0; } } } bool game_tech_can_choose(const struct game_s *g, player_id_t player, tech_field_t field) { return (g->evn.newtech[player].next[field].num != 0); } uint32_t game_tech_get_next_rp(const struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech) { uint32_t cost; cost = tech * tech; cost *= game_num_tech_costmulr[g->eto[player].race][field]; if (IS_AI(g, player)) { cost *= game_num_tech_costmula[g->difficulty]; cost /= 100; } else { cost *= game_num_tech_costmuld[g->difficulty]; cost /= 1000; cost *= 10; } return cost; } void game_tech_start_next(struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech) { techdata_t *td = &(g->eto[player].tech); if (td->project[field] != 0) { td->investment[field] = 0; } td->project[field] = tech; td->cost[field] = game_tech_get_next_rp(g, player, field, tech); g->evn.newtech[player].next[field].num = 0; } int game_tech_get_field_percent(const struct game_s *g, player_id_t player, tech_field_t field) { const uint8_t *rc = g->srd[player].researchcompleted[field]; int v, len = g->eto[player].tech.completed[field]; uint8_t tmax = 0; for (int i = 0; i < len; ++i) { uint8_t t; t = rc[i]; SETMAX(tmax, t); } if (len == 1) { v = 1; } else { v = (tmax - 1) / 5 + 2; } v = tmax + len - v; SETRANGE(v, 1, 99); return v; } int game_tech_get_field_cost(const struct game_s *g, player_id_t player, tech_field_t field) { const empiretechorbit_t *e = &(g->eto[player]); uint32_t cost = e->tech.cost[field]; if (IS_HUMAN(g, player)) { if (game_num_tech_costmuld2 != 100) { cost = (cost * game_num_tech_costmuld2) / 100; } } else { if (game_num_tech_costmula2 != 100) { cost = (cost * game_num_tech_costmula2) / 100; } } if (game_num_tech_costmul != 100) { cost = (cost * game_num_tech_costmul) / 100; } return cost; } void game_tech_research(struct game_s *g) { for (player_id_t player = PLAYER_0; player < g->players; ++player) { empiretechorbit_t *e = &(g->eto[player]); techdata_t *td = &(e->tech); uint32_t total_research; total_research = e->total_research_bc; for (tech_field_t field = 0; field < TECH_FIELD_NUM; ++field) { int slider, t1, t3; uint32_t invest, cost; invest = td->investment[field]; slider = td->slider[field]; t1 = (invest * 3) / 20; t3 = (slider * total_research) / 100; SETMIN(t1, t3 * 2); invest += t3 + t1; td->investment[field] = invest; td->percent[field] = game_tech_get_field_percent(g, player, field); cost = game_tech_get_field_cost(g, player, field); if ((cost != 0) && (slider != 0) && (total_research != 0)) { if (cost < invest) { int v; v = ((invest - cost) * 250) / cost; if (rnd_1_n(500, &g->seed) <= v) { game_tech_get_new(g, player, field, td->project[field], TECHSOURCE_RESEARCH, game_planet_get_random(g, player), PLAYER_NONE, false); } } } else { if ((cost != 0) || (!game_num_first_tech_rp_fix)) { /* WASBUG? 1 RP for first tech rounded down to 0 */ td->investment[field] = (invest * 9) / 10; } } } } game_update_tech_util(g); } void game_tech_get_orion_loot(struct game_s *g, player_id_t player) { empiretechorbit_t *e = &(g->eto[player]); techdata_t *td = &(e->tech); uint8_t percent[TECH_FIELD_NUM]; game_tech_get_new(g, player, TECH_FIELD_WEAPON, TECH_WEAP_DEATH_RAY, TECHSOURCE_FOUND, -PLANETS_MAX, PLAYER_NONE, false); for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { percent[f] = MIN(td->percent[f] + 25, 50); } for (int n = 0; n < 3; ++n) { for (int loops = 0; loops < 200; ++loops) { tech_field_t field; uint8_t tech; tech_group_t group; field = rnd_0_nm1(TECH_FIELD_NUM, &g->seed); tech = rnd_1_n(31, &g->seed) + 19; group = game_tech_get_group(g->gaux, field, tech); if ((percent[field] >= tech) && (group != TECH_GROUP_UNUSED)) { const uint8_t *rc; bool have_tech; rc = &(g->srd[player].researchcompleted[field][0]); have_tech = false; for (int i = 0; i < td->completed[field]; ++i) { if (rc[i] == tech) { have_tech = true; break; } } if (!have_tech) { game_tech_get_new(g, player, field, tech, TECHSOURCE_FOUND, NEWTECH_V06_ORION, PLAYER_NONE, false); break; } } } } } void game_tech_get_artifact_loot(struct game_s *g, uint8_t planet, player_id_t player) { empiretechorbit_t *e = &(g->eto[player]); techdata_t *td = &(e->tech); uint8_t percent[TECH_FIELD_NUM]; if (IS_AI(g, player)) { return; } for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { percent[f] = MIN(td->percent[f] + 10, 50); } for (int n = 0; n < 1; ++n) { for (int loops = 0; loops < 200; ++loops) { tech_field_t field; uint8_t tech; tech_group_t group; field = rnd_0_nm1(TECH_FIELD_NUM, &g->seed); tech = rnd_1_n(30, &g->seed); group = game_tech_get_group(g->gaux, field, tech); if ((percent[field] >= tech) && (group != TECH_GROUP_UNUSED)) { const uint8_t *rc; bool have_tech; rc = &(g->srd[player].researchcompleted[field][0]); have_tech = false; for (int i = 0; i < td->completed[field]; ++i) { if (rc[i] == tech) { have_tech = true; break; } } if (!have_tech) { game_tech_get_new(g, player, field, tech, TECHSOURCE_FOUND, -(planet + 1), PLAYER_NONE, false); break; } } } } } void game_tech_final_war_share(struct game_s *g) { for (tech_field_t field_i = TECH_FIELD_COMPUTER; field_i < TECH_FIELD_NUM; ++field_i) { game_tech_share(g, field_i, true, true); /* BUG MOO1 takes tech also from dead races */ if (!BOOLVEC_ONLY1(g->refuse, PLAYER_NUM)) { game_tech_share(g, field_i, false, false); } } } 1oom-1.11.2/src/game/game_tech.h000066400000000000000000000064031476061725400162530ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_TECH_H #define INC_1OOM_GAME_TECH_H #include "game_types.h" #include "types.h" struct game_s; struct game_aux_s; struct empiretechorbit_s; struct newtech_s; extern const uint8_t tech_reduce_50percent_per_10pts[51]; extern const uint8_t tech_reduce_25percent_per_10pts[51]; extern uint8_t game_tech_player_has_tech(const struct game_s *g, int field_i, int tech_i, int player_i); extern uint8_t game_tech_player_best_tech(const struct game_s *g, int field_i, int tech_i_base, int tech_i_step, int tech_i_max, int player_i); extern uint16_t game_get_base_cost(const struct game_s *g, int player_i); extern uint8_t game_get_base_weapon(const struct game_s *g, player_id_t player_i, int tech_i); extern uint8_t game_get_base_weapon_2(const struct game_s *g, player_id_t player_i, int tech_i, uint8_t weap1); extern uint8_t game_get_best_shield(struct game_s *g, player_id_t player_i, int tech_i); extern uint8_t game_get_best_comp(struct game_s *g, player_id_t player_i, int tech_i); extern uint8_t game_get_best_jammer(const struct game_s *g, player_id_t player_i, int tech_i); extern void game_update_tech_util(struct game_s *g); extern uint8_t game_tech_get_group(const struct game_aux_s *gaux, tech_field_t field, int tech); extern uint8_t game_tech_get_tier(const struct game_aux_s *gaux, tech_field_t field, int tech); extern uint8_t game_tech_get_gfx_i(const struct game_aux_s *gaux, tech_field_t field, int tech); extern const char *game_tech_get_name(const struct game_aux_s *gaux, tech_field_t field, int tech, char *buf, size_t bufsize); extern const char *game_tech_get_descr(const struct game_aux_s *gaux, tech_field_t field, int tech, char *buf, size_t bufsize); extern const char *game_tech_get_newtech_msg(const struct game_s *g, player_id_t pi, struct newtech_s *nt, char *buf, size_t bufsize); extern int game_tech_current_research_percent1(const struct game_s *g, player_id_t player, tech_field_t field); extern int game_tech_current_research_percent2(const struct game_s *g, player_id_t player, tech_field_t field); extern bool game_tech_current_research_has_max_bonus(const struct game_s *g, player_id_t player, tech_field_t field); extern void game_tech_set_to_max_bonus(struct game_s *g, player_id_t player, tech_field_t field); extern void game_tech_get_new(struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech, techsource_t source, int a8, player_id_t stolen_from, bool flag_frame); extern void game_tech_finish_new(struct game_s *g, player_id_t player); extern bool game_tech_can_choose(const struct game_s *g, player_id_t player, tech_field_t field); extern uint32_t game_tech_get_next_rp(const struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech); extern void game_tech_start_next(struct game_s *g, player_id_t player, tech_field_t field, uint8_t tech); extern int game_tech_get_field_percent(const struct game_s *g, player_id_t player, tech_field_t field); extern int game_tech_get_field_cost(const struct game_s *g, player_id_t player, tech_field_t field); extern void game_tech_research(struct game_s *g); extern void game_tech_get_orion_loot(struct game_s *g, player_id_t player); extern void game_tech_get_artifact_loot(struct game_s *g, uint8_t planet, player_id_t player); extern void game_tech_final_war_share(struct game_s *g); #endif 1oom-1.11.2/src/game/game_techtypes.h000066400000000000000000000271261476061725400173450ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_TECHTYPES_H #define INC_1OOM_GAME_TECHTYPES_H typedef enum { TECH_COMP_NONE = 0, TECH_COMP_BATTLE_SCANNER, /*1*/ TECH_COMP_ECM_JAMMER_MARK_I, /*2*/ TECH_COMP_UNUSED_2, /*3*/ TECH_COMP_DEEP_SPACE_SCANNER, /*4*/ TECH_COMP_BATTLE_COMPUTER_MARK_II, /*5*/ TECH_COMP_UNUSED_5, /*6*/ TECH_COMP_ECM_JAMMER_MARK_II, /*7*/ TECH_COMP_IMPROVED_ROBOTIC_CONTROLS_III, /*8*/ TECH_COMP_UNUSED_8, /*9*/ TECH_COMP_BATTLE_COMPUTER_MARK_III, /*10*/ TECH_COMP_UNUSED_10, /*11*/ TECH_COMP_ECM_JAMMER_MARK_III, /*12*/ TECH_COMP_IMPROVED_SPACE_SCANNER, /*13*/ TECH_COMP_UNUSED_13, /*14*/ TECH_COMP_BATTLE_COMPUTER_MARK_IV, /*15*/ TECH_COMP_UNUSED_15, /*16*/ TECH_COMP_ECM_JAMMER_MARK_IV, /*17*/ TECH_COMP_IMPROVED_ROBOTIC_CONTROLS_IV, /*18*/ TECH_COMP_UNUSED_18, /*19*/ TECH_COMP_BATTLE_COMPUTER_MARK_V, /*20*/ TECH_COMP_UNUSED_20, /*21*/ TECH_COMP_ECM_JAMMER_MARK_V, /*22*/ TECH_COMP_ADVANCED_SPACE_SCANNER, /*23*/ TECH_COMP_UNUSED_23, /*24*/ TECH_COMP_BATTLE_COMPUTER_MARK_VI, /*25*/ TECH_COMP_UNUSED_25, /*26*/ TECH_COMP_ECM_JAMMER_MARK_VI, /*27*/ TECH_COMP_IMPROVED_ROBOTIC_CONTROLS_V, /*28*/ TECH_COMP_UNUSED_28, /*29*/ TECH_COMP_BATTLE_COMPUTER_MARK_VII, /*30*/ TECH_COMP_UNUSED_30, /*31*/ TECH_COMP_ECM_JAMMER_MARK_VII, /*32*/ TECH_COMP_UNUSED_32, /*33*/ TECH_COMP_HYPERSPACE_COMMUNICATIONS, /*34*/ TECH_COMP_BATTLE_COMPUTER_MARK_VIII, /*35*/ TECH_COMP_UNUSED_35, /*36*/ TECH_COMP_ECM_JAMMER_MARK_VIII, /*37*/ TECH_COMP_IMPROVED_ROBOTIC_CONTROLS_VI, /*38*/ TECH_COMP_UNUSED_38, /*39*/ TECH_COMP_BATTLE_COMPUTER_MARK_IX, /*40*/ TECH_COMP_UNUSED_40, /*41*/ TECH_COMP_ECM_JAMMER_MARK_IX, /*42*/ TECH_COMP_UNUSED_42, /*43*/ TECH_COMP_UNUSED_43, /*44*/ TECH_COMP_BATTLE_COMPUTER_MARK_X, /*45*/ TECH_COMP_ORACLE_INTERFACE, /*46*/ TECH_COMP_ECM_JAMMER_MARK_X, /*47*/ TECH_COMP_IMPROVED_ROBOTIC_CONTROLS_VII, /*48*/ TECH_COMP_TECHNOLOGY_NULLIFIER, /*49*/ TECH_COMP_BATTLE_COMPUTER_MARK_XI /*50*/ } tech_comp_t; typedef enum { TECH_CONS_NONE = 0, TECH_CONS_RESERVE_FUEL_TANKS, /*1*/ TECH_CONS_UNUSED_1, /*2*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_9, /*3*/ TECH_CONS_UNUSED_3, /*4*/ TECH_CONS_REDUCED_INDUSTRIAL_WASTE_80, /*5*/ TECH_CONS_UNUSED_5, /*6*/ TECH_CONS_UNUSED_6, /*7*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_8, /*8*/ TECH_CONS_UNUSED_8, /*9*/ TECH_CONS_DURALLOY_ARMOR, /*10*/ TECH_CONS_BATTLE_SUITS, /*11*/ TECH_CONS_UNUSED_11, /*12*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_7, /*13*/ TECH_CONS_AUTOMATED_REPAIR_SYSTEM, /*14*/ TECH_CONS_REDUCED_INDUSTRIAL_WASTE_60, /*15*/ TECH_CONS_UNUSED_15, /*16*/ TECH_CONS_ZORTIUM_ARMOR, /*17*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_6, /*18*/ TECH_CONS_UNUSED_18, /*19*/ TECH_CONS_UNUSED_19, /*20*/ TECH_CONS_UNUSED_20, /*21*/ TECH_CONS_UNUSED_21, /*22*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_5, /*23*/ TECH_CONS_ARMORED_EXOSKELETON, /*24*/ TECH_CONS_REDUCED_INDUSTRIAL_WASTE_40, /*25*/ TECH_CONS_ANDRIUM_ARMOR, /*26*/ TECH_CONS_UNUSED_26, /*27*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_4, /*28*/ TECH_CONS_UNUSED_28, /*29*/ TECH_CONS_UNUSED_29, /*30*/ TECH_CONS_UNUSED_30, /*31*/ TECH_CONS_UNUSED_31, /*32*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_3, /*33*/ TECH_CONS_TRITANIUM_ARMOR, /*34*/ TECH_CONS_REDUCED_INDUSTRIAL_WASTE_20, /*35*/ TECH_CONS_ADVANCED_DAMAGE_CONTROL, /*36*/ TECH_CONS_UNUSED_36, /*37*/ TECH_CONS_IMPROVED_INDUSTRIAL_TECH_2, /*38*/ TECH_CONS_UNUSED_38, /*39*/ TECH_CONS_POWERED_ARMOR, /*40*/ TECH_CONS_UNUSED_40, /*41*/ TECH_CONS_ADAMANTIUM_ARMOR, /*42*/ TECH_CONS_UNUSED_42, /*43*/ TECH_CONS_UNUSED_43, /*44*/ TECH_CONS_INDUSTRIAL_WASTE_ELIMINATION, /*45*/ TECH_CONS_UNUSED_45, /*46*/ TECH_CONS_UNUSED_46, /*47*/ TECH_CONS_UNUSED_47, /*48*/ TECH_CONS_UNUSED_48, /*49*/ TECH_CONS_NEUTRONIUM_ARMOR /*50*/ } tech_cons_t; typedef enum { TECH_FFLD_NONE = 0, TECH_FFLD_CLASS_I_DEFLECTOR_SHIELDS, /*1*/ TECH_FFLD_UNUSED_1, /*2*/ TECH_FFLD_UNUSED_2, /*3*/ TECH_FFLD_CLASS_II_DEFLECTOR_SHIELDS, /*4*/ TECH_FFLD_UNUSED_4, /*5*/ TECH_FFLD_UNUSED_5, /*6*/ TECH_FFLD_UNUSED_6, /*7*/ TECH_FFLD_PERSONAL_DEFLECTOR_SHIELD, /*8*/ TECH_FFLD_UNUSED_8, /*9*/ TECH_FFLD_CLASS_III_DEFLECTOR_SHIELDS, /*10*/ TECH_FFLD_UNUSED_10, /*11*/ TECH_FFLD_CLASS_V_PLANETARY_SHIELD, /*12*/ TECH_FFLD_UNUSED_12, /*13*/ TECH_FFLD_CLASS_IV_DEFLECTOR_SHIELDS, /*14*/ TECH_FFLD_UNUSED_14, /*15*/ TECH_FFLD_REPULSOR_BEAM, /*16*/ TECH_FFLD_UNUSED_16, /*17*/ TECH_FFLD_UNUSED_17, /*18*/ TECH_FFLD_UNUSED_18, /*19*/ TECH_FFLD_CLASS_V_DEFLECTOR_SHIELDS, /*20*/ TECH_FFLD_PERSONAL_ABSORPTION_SHIELD, /*21*/ TECH_FFLD_CLASS_X_PLANETARY_SHIELD, /*22*/ TECH_FFLD_UNUSED_22, /*23*/ TECH_FFLD_CLASS_VI_DEFLECTOR_SHIELDS, /*24*/ TECH_FFLD_UNUSED_24, /*25*/ TECH_FFLD_UNUSED_25, /*26*/ TECH_FFLD_CLOAKING_DEVICE, /*27*/ TECH_FFLD_UNUSED_27, /*28*/ TECH_FFLD_UNUSED_28, /*29*/ TECH_FFLD_CLASS_VII_DEFLECTOR_SHIELDS, /*30*/ TECH_FFLD_ZYRO_SHIELD, /*31*/ TECH_FFLD_CLASS_XV_PLANETARY_SHIELD, /*32*/ TECH_FFLD_UNUSED_32, /*33*/ TECH_FFLD_CLASS_IX_DEFLECTOR_SHIELDS, /*34*/ TECH_FFLD_UNUSED_34, /*35*/ TECH_FFLD_UNUSED_35, /*36*/ TECH_FFLD_STASIS_FIELD, /*37*/ TECH_FFLD_PERSONAL_BARRIER_SHIELD, /*38*/ TECH_FFLD_UNUSED_38, /*39*/ TECH_FFLD_CLASS_XI_DEFLECTOR_SHIELDS, /*40*/ TECH_FFLD_UNUSED_40, /*41*/ TECH_FFLD_CLASS_XX_PLANETARY_SHIELD, /*42*/ TECH_FFLD_BLACK_HOLE_GENERATOR, /*43*/ TECH_FFLD_CLASS_XIII_DEFLECTOR_SHIELDS, /*44*/ TECH_FFLD_UNUSED_44, /*45*/ TECH_FFLD_LIGHTNING_SHIELD, /*46*/ TECH_FFLD_UNUSED_46, /*47*/ TECH_FFLD_UNUSED_47, /*48*/ TECH_FFLD_UNUSED_48, /*49*/ TECH_FFLD_CLASS_XV_DEFLECTOR_SHIELDS /*50*/ } tech_ffld_t; typedef enum { TECH_PLAN_NONE = 0, TECH_PLAN_ECOLOGICAL_RESTORATION, /*1*/ TECH_PLAN_IMPROVED_TERRAFORMING__10, /*2*/ TECH_PLAN_CONTROLLED_BARREN_ENVIRONMENT, /*3*/ TECH_PLAN_UNUSED_3, /*4*/ TECH_PLAN_IMPROVED_ECO_RESTORATION, /*5*/ TECH_PLAN_CONTROLLED_TUNDRA_ENVIRONMENT, /*6*/ TECH_PLAN_UNUSED_6, /*7*/ TECH_PLAN_IMPROVED_TERRAFORMING__20, /*8*/ TECH_PLAN_CONTROLLED_DEAD_ENVIRONMENT, /*9*/ TECH_PLAN_DEATH_SPORES, /*10*/ TECH_PLAN_UNUSED_10, /*11*/ TECH_PLAN_CONTROLLED_INFERNO_ENVIRONMENT, /*12*/ TECH_PLAN_ENHANCED_ECO_RESTORATION, /*13*/ TECH_PLAN_IMPROVED_TERRAFORMING__30, /*14*/ TECH_PLAN_CONTROLLED_TOXIC_ENVIRONMENT, /*15*/ TECH_PLAN_SOIL_ENRICHMENT, /*16*/ TECH_PLAN_BIO_TOXIN_ANTIDOTE, /*17*/ TECH_PLAN_CONTROLLED_RADIATED_ENVIRONMENT, /*18*/ TECH_PLAN_UNUSED_18, /*19*/ TECH_PLAN_IMPROVED_TERRAFORMING__40, /*20*/ TECH_PLAN_CLONING, /*21*/ TECH_PLAN_ATMOSPHERIC_TERRAFORMING, /*22*/ TECH_PLAN_UNUSED_22, /*23*/ TECH_PLAN_ADVANCED_ECO_RESTORATION, /*24*/ TECH_PLAN_UNUSED_24, /*25*/ TECH_PLAN_IMPROVED_TERRAFORMING__50, /*26*/ TECH_PLAN_DOOM_VIRUS, /*27*/ TECH_PLAN_UNUSED_27, /*28*/ TECH_PLAN_UNUSED_28, /*29*/ TECH_PLAN_ADVANCED_SOIL_ENRICHMENT, /*30*/ TECH_PLAN_UNUSED_30, /*31*/ TECH_PLAN_IMPROVED_TERRAFORMING__60, /*32*/ TECH_PLAN_UNUSED_32, /*33*/ TECH_PLAN_COMPLETE_ECO_RESTORATION, /*34*/ TECH_PLAN_UNUSED_34, /*35*/ TECH_PLAN_UNIVERSAL_ANTIDOTE, /*36*/ TECH_PLAN_UNUSED_36, /*37*/ TECH_PLAN_IMPROVED_TERRAFORMING__80, /*38*/ TECH_PLAN_UNUSED_38, /*39*/ TECH_PLAN_BIO_TERMINATOR, /*40*/ TECH_PLAN_UNUSED_40, /*41*/ TECH_PLAN_ADVANCED_CLONING, /*42*/ TECH_PLAN_UNUSED_42, /*43*/ TECH_PLAN_IMPROVED_TERRAFORMING__100, /*44*/ TECH_PLAN_UNUSED_44, /*45*/ TECH_PLAN_UNUSED_45, /*46*/ TECH_PLAN_UNUSED_46, /*47*/ TECH_PLAN_UNUSED_47, /*48*/ TECH_PLAN_UNUSED_48, /*49*/ TECH_PLAN_COMPLETE_TERRAFORMING /*50*/ } tech_plan_t; typedef enum { TECH_PROP_NONE = 0, TECH_PROP_RETRO_ENGINES, /*1*/ TECH_PROP_UNUSED_1, /*2*/ TECH_PROP_HYDROGEN_FUEL_CELLS, /*3*/ TECH_PROP_UNUSED_3, /*4*/ TECH_PROP_DEUTERIUM_FUEL_CELLS, /*5*/ TECH_PROP_NUCLEAR_ENGINES, /*6*/ TECH_PROP_UNUSED_6, /*7*/ TECH_PROP_UNUSED_7, /*8*/ TECH_PROP_IRRIDIUM_FUEL_CELLS, /*9*/ TECH_PROP_INERTIAL_STABILIZER, /*10*/ TECH_PROP_UNUSED_10, /*11*/ TECH_PROP_SUB_LIGHT_DRIVES, /*12*/ TECH_PROP_UNUSED_12, /*13*/ TECH_PROP_DOTOMITE_CRYSTALS, /*14*/ TECH_PROP_UNUSED_14, /*15*/ TECH_PROP_ENERGY_PULSAR, /*16*/ TECH_PROP_UNUSED_16, /*17*/ TECH_PROP_FUSION_DRIVES, /*18*/ TECH_PROP_URIDIUM_FUEL_CELLS, /*19*/ TECH_PROP_WARP_DISSIPATOR, /*20*/ TECH_PROP_UNUSED_20, /*21*/ TECH_PROP_UNUSED_21, /*22*/ TECH_PROP_REAJAX_II_FUEL_CELLS, /*23*/ TECH_PROP_IMPULSE_DRIVES, /*24*/ TECH_PROP_UNUSED_24, /*25*/ TECH_PROP_UNUSED_25, /*26*/ TECH_PROP_INTERGALACTIC_STAR_GATES, /*27*/ TECH_PROP_UNUSED_27, /*28*/ TECH_PROP_TRILITHIUM_CRYSTALS, /*29*/ TECH_PROP_ION_DRIVES, /*30*/ TECH_PROP_UNUSED_30, /*31*/ TECH_PROP_UNUSED_31, /*32*/ TECH_PROP_UNUSED_32, /*33*/ TECH_PROP_HIGH_ENERGY_FOCUS, /*34*/ TECH_PROP_UNUSED_34, /*35*/ TECH_PROP_ANTI_MATTER_DRIVES, /*36*/ TECH_PROP_UNUSED_36, /*37*/ TECH_PROP_SUB_SPACE_TELEPORTER, /*38*/ TECH_PROP_UNUSED_38, /*39*/ TECH_PROP_IONIC_PULSAR, /*40*/ TECH_PROP_THORIUM_CELLS, /*41*/ TECH_PROP_INTER_PHASED_DRIVES, /*42*/ TECH_PROP_SUB_SPACE_INTERDICTOR, /*43*/ TECH_PROP_UNUSED_43, /*44*/ TECH_PROP_COMBAT_TRANSPORTERS, /*45*/ TECH_PROP_INERTIAL_NULLIFIER, /*46*/ TECH_PROP_UNUSED_46, /*47*/ TECH_PROP_HYPER_DRIVES, /*48*/ TECH_PROP_UNUSED_48, /*49*/ TECH_PROP_DISPLACEMENT_DEVICE /*50*/ } tech_prop_t; typedef enum { TECH_WEAP_NONE = 0, TECH_WEAP_LASERS, /*1*/ TECH_WEAP_HAND_LASERS, /*2*/ TECH_WEAP_UNUSED_2, /*3*/ TECH_WEAP_HYPER_V_ROCKETS, /*4*/ TECH_WEAP_GATLING_LASER, /*5*/ TECH_WEAP_ANTI_MISSILE_ROCKETS, /*6*/ TECH_WEAP_NEUTRON_PELLET_GUN, /*7*/ TECH_WEAP_HYPER_X_ROCKETS, /*8*/ TECH_WEAP_FUSION_BOMB, /*9*/ TECH_WEAP_ION_CANNON, /*10*/ TECH_WEAP_SCATTER_PACK_V_ROCKETS, /*11*/ TECH_WEAP_ION_RIFLE, /*12*/ TECH_WEAP_MASS_DRIVER, /*13*/ TECH_WEAP_MERCULITE_MISSILES, /*14*/ TECH_WEAP_NEUTRON_BLASTER, /*15*/ TECH_WEAP_ANTI_MATTER_BOMB, /*16*/ TECH_WEAP_GRAVITON_BEAM, /*17*/ TECH_WEAP_STINGER_MISSILES, /*18*/ TECH_WEAP_HARD_BEAM, /*19*/ TECH_WEAP_FUSION_BEAM, /*20*/ TECH_WEAP_ION_STREAM_PROJECTOR, /*21*/ TECH_WEAP_OMEGA_V_BOMB, /*22*/ TECH_WEAP_ANTI_MATTER_TORPEDOES, /*23*/ TECH_WEAP_FUSION_RIFLE, /*24*/ TECH_WEAP_MEGABOLT_CANNON, /*25*/ TECH_WEAP_PHASOR, /*26*/ TECH_WEAP_SCATTER_PACK_VII_MISSILES, /*27*/ TECH_WEAP_AUTO_BLASTER, /*28*/ TECH_WEAP_PULSON_MISSILES, /*29*/ TECH_WEAP_TACHYON_BEAM, /*30*/ TECH_WEAP_HAND_PHASOR, /*31*/ TECH_WEAP_GAUSS_AUTOCANNON, /*32*/ TECH_WEAP_PARTICLE_BEAM, /*33*/ TECH_WEAP_HERCULAR_MISSILES, /*34*/ TECH_WEAP_PLASMA_CANNON, /*35*/ TECH_WEAP_DEATH_RAY, /*36*/ TECH_WEAP_DISRUPTOR, /*37*/ TECH_WEAP_PULSE_PHASOR, /*38*/ TECH_WEAP_NEUTRONIUM_BOMB, /*39*/ TECH_WEAP_HELLFIRE_TORPEDOES, /*40*/ TECH_WEAP_ZEON_MISSILES, /*41*/ TECH_WEAP_PLASMA_RIFLE, /*42*/ TECH_WEAP_PROTON_TORPEDOES, /*43*/ TECH_WEAP_SCATTER_PACK_X_MISSILES, /*44*/ TECH_WEAP_TRI_FOCUS_PLASMA_CANNON, /*45*/ TECH_WEAP_STELLAR_CONVERTER, /*46*/ TECH_WEAP_NEUTRON_STREAM_PROJECTOR, /*47*/ TECH_WEAP_MAULER_DEVICE, /*48*/ TECH_WEAP_UNUSED_48, /*49*/ TECH_WEAP_PLASMA_TORPEDOES /*50*/ } tech_weap_t; #endif 1oom-1.11.2/src/game/game_turn.c000066400000000000000000002067021476061725400163170ustar00rootroot00000000000000#include "config.h" #include #include /* abs */ #include #include "game_turn.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_audience.h" #include "game_aux.h" #include "game_battle.h" #include "game_bomb.h" #include "game_design.h" #include "game_diplo.h" #include "game_election.h" #include "game_end.h" #include "game_event.h" #include "game_fleet.h" #include "game_ground.h" #include "game_misc.h" #include "game_news.h" #include "game_num.h" #include "game_shiptech.h" #include "game_spy.h" #include "game_stat.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ int copyprot_status = 0; static void game_turn_limit_ships(struct game_s *g) { for (int ei = 0; ei < g->enroute_num; ++ei) { fleet_enroute_t *r = &(g->enroute[ei]); for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { SETMIN(r->ships[si], game_num_limit_ships); } r->retreat = false; } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { fleet_orbit_t *r = &(g->eto[j].orbit[i]); for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { SETMIN(r->ships[si], game_num_limit_ships); } } } game_remove_empty_fleets(g); } static void game_turn_countdown_ceasefire(struct game_s *g) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (g->evn.ceasefire[j][i] > 0) { --g->evn.ceasefire[j][i]; } } } } static void game_turn_update_mood_blunder(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = PLAYER_1; j < g->players; ++j) { if (i != j) { int16_t v; v = e->diplo_type[j]; if ((v >= 4) && (v <= 11)) { e->blunder[j] = v; } else if ((v >= 42) && (v <= 49)) { e->blunder[j] = v - 30; } else if ((v >= 50) && (v <= 57)) { e->blunder[j] = v - 46; } if (e->treaty[j] != TREATY_FINAL_WAR) { v = e->mood_treaty[j]; if (v < 0) { v += rnd_1_n(5, &g->seed); } if (v < 50) { v += rnd_1_n(5, &g->seed); } e->mood_treaty[j] = v; v = e->mood_trade[j]; if (v < 0) { v += rnd_1_n(5, &g->seed); } if (v < 50) { v += rnd_1_n(5, &g->seed); } e->mood_trade[j] = v; v = e->mood_tech[j]; if (v < 0) { v += rnd_1_n(5, &g->seed); } if (v < 50) { v += rnd_1_n(5, &g->seed); } e->mood_tech[j] = v; v = e->mood_peace[j]; if (v < 0) { v += rnd_1_n(5, &g->seed); } if (v < 50) { v += rnd_1_n(5, &g->seed); } SETRANGE(v, -200, 200); e->mood_peace[j] = v; } } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = PLAYER_0; j < g->players; ++j) { e->diplo_val[j] = 0; e->diplo_type[j] = 0; if (e->bounty_collect[j] != PLAYER_NONE) { e->attack_bounty[j] = PLAYER_NONE; e->bounty_collect[j] = PLAYER_NONE; } e->au_tech_trade_num[j] = 0; e->offer_tech[j] = 0; e->au_want_tech[j] = 0; e->offer_bc[j] = 0; } } } static void game_turn_init_z_finished(struct game_s *g) { memset(g->evn.spies_caught, 0, sizeof(g->evn.spies_caught)); memset(g->evn.new_ships, 0, sizeof(g->evn.new_ships)); for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); BOOLVEC_CLEAR(p->finished, FINISHED_NUM); BOOLVEC_CLEAR(p->unrefuel, PLAYER_NUM); } for (int i = 0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); BOOLVEC_CLEAR(e->contact_broken, PLAYER_NUM); } memset(g->evn.build_finished_num, 0, sizeof(g->evn.build_finished_num)); } static void game_turn_send_transport(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if ((p->owner != PLAYER_NONE) && (p->trans_num > 0)) { game_send_transport(g, p); } } } static int game_turn_build_eco_sub1(int fact, int colonist_oper_fact, int pop1, int waste, int max_pop2) { if (game_num_waste_calc_fix) { /* WASBUG MOO1 adds waste twice using two separate pieces of code. The first time (see above) is as described in OSG. The second time (see below, from game_turn_build_eco_sub1) has several issues: - p->pop * e->colonist_oper_factories * e->colonist_oper_factories / 10 makes no sense - since p->waste is not limited at this point, the value added can be negative, leading to Silicoid planets with 0 waste - the cost of eco restoration is already calculated; as the slider is typically set to Clean (ecorestore <= ecoprod) the point is mostly moot Speculation: Someone added the above working code and forgot to remove this broken code. */ return 0; } int v; v = pop1 * colonist_oper_fact; SETMIN(fact, v); v = (fact * colonist_oper_fact) / 10; return ((100 - ((waste * 100) / max_pop2)) * v) / 100; } static inline void game_add_planet_to_eco_finished(struct game_s *g, uint8_t pli, player_id_t owner) { BOOLVEC_SET1(g->planet[pli].finished, FINISHED_SOILATMOS); } static void game_turn_build_eco(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; p->pop_prev = (owner != PLAYER_NONE) ? p->pop : 0; if ((owner != PLAYER_NONE) && (p->type != PLANET_TYPE_NOT_HABITABLE) && (p->pop != 0)) { const empiretechorbit_t *e; int ecorestore, ecoprod; e = &(g->eto[owner]); { int v, fact, waste; fact = p->factories; v = p->pop * game_planet_get_pop_oper_fact(g, p); SETMIN(fact, v); waste = (fact * e->ind_waste_scale) / 10; p->waste += ((100 - ((p->waste * 100) / p->max_pop2)) * waste) / 100; } if (p->unrest == PLANET_UNREST_REBELLION) { p->waste = 0; } ecorestore = (e->race != RACE_SILICOID) ? (p->waste / e->have_eco_restoration_n) : 0; p->waste += game_turn_build_eco_sub1(p->factories, game_planet_get_pop_oper_fact(g, p), p->pop, p->waste, p->max_pop2); ecoprod = (p->slider[PLANET_SLIDER_ECO] * p->prod_after_maint) / 100; if (e->race != RACE_SILICOID) { if (ecorestore > ecoprod) { p->waste -= e->have_eco_restoration_n * ecoprod; ecoprod = 0; } else { ecoprod -= ecorestore; p->waste = 0; } } SETMAX(p->waste, 0); if ((p->max_pop2 - p->waste) < 10) { p->waste = p->max_pop2 - 10; } SETMAX(p->waste, 0); if ((ecoprod > 0) && e->have_atmos_terra && (p->growth == PLANET_GROWTH_HOSTILE)) { p->bc_to_ecoproj += ecoprod; if (p->bc_to_ecoproj >= game_num_atmos_cost) { game_turn_atmos_tform(p); ecoprod = p->bc_to_ecoproj - game_num_atmos_cost; p->bc_to_ecoproj = 0; /* WASBUG MOO1 did p->bc_to_ecoproj -= game_num_atmos_cost * instead which allowed double-spending of credits if * p->bc_to_ecoproj > game_num_atmos_cost. */ game_add_planet_to_eco_finished(g, i, owner); } else { ecoprod = 0; } } if ((ecoprod > 0) && e->have_soil_enrich && (p->growth == PLANET_GROWTH_NORMAL)) { p->bc_to_ecoproj += ecoprod; if (p->bc_to_ecoproj > game_num_soil_cost) { game_turn_soil_enrich(p, (int)e->have_terraform_n, false); ecoprod = p->bc_to_ecoproj - game_num_soil_cost; /* p->bc_to_ecoproj carries over as partial progress * towards advanced soil enrichment. */ SETMIN(p->bc_to_ecoproj, game_num_soil_cost); /* WASBUG MOO1 did not do the SETMIN, allowing * double-spending again. */ game_add_planet_to_eco_finished(g, i, owner); } else { ecoprod = 0; } } if ((ecoprod > 0) && e->have_adv_soil_enrich && (p->growth < PLANET_GROWTH_GAIA) && (p->growth > PLANET_GROWTH_HOSTILE)) { p->bc_to_ecoproj += ecoprod; if (p->bc_to_ecoproj > game_num_adv_soil_cost) { game_turn_soil_enrich(p, (int)e->have_terraform_n, true); ecoprod = p->bc_to_ecoproj - game_num_adv_soil_cost; p->bc_to_ecoproj = 0; /* WASBUG MOO1 did not reset p->bc_to_ecoproj to 0, but * the planet may become hostile due to a random event and * then this variable becomes relevant again. */ game_add_planet_to_eco_finished(g, i, owner); } else { ecoprod = 0; } } if ((ecoprod > 0) && ((p->max_pop3 - p->max_pop2) < e->have_terraform_n) && (p->max_pop3 < game_num_max_pop)) { int v, tmax; v = ecoprod / e->terraform_cost_per_inc; tmax = e->have_terraform_n + p->max_pop2; if (tmax < (p->max_pop3 + v)) { ecoprod -= (tmax - p->max_pop3) * e->terraform_cost_per_inc; p->max_pop3 = tmax; } else { p->max_pop3 += v; ecoprod = 0; } } SETMIN(p->max_pop3, game_num_max_pop); SETMAX(ecoprod, 0); { int v; v = game_get_pop_growth_max(g, p, p->max_pop3) + game_get_pop_growth_for_eco(g, p, ecoprod) + p->pop_tenths; p->pop += v / 10; p->pop_tenths = v % 10; } SETRANGE(p->pop, 0, p->max_pop3); } } } static void game_turn_update_trade(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = i; j < g->players; ++j) { empiretechorbit_t *e2 = &(g->eto[j]); uint16_t bc; bc = e->trade_bc[j]; if (bc != 0) { if (BOOLVEC_IS0(e->contact, j)) { e->trade_bc[j] = 0; e->trade_percent[j] = 0; e->trade_established_bc[j] = 0; } else { uint16_t estbc; int16_t v; estbc = e->trade_established_bc[j]; if (estbc < bc) { /* FIXME BUG? never true ; both are set to bc */ estbc += bc / 10; SETMIN(estbc, bc); e->trade_established_bc[j] = estbc; e2->trade_established_bc[i] = estbc; } v = (rnd_1_n(200, &g->seed) + e->relation1[j] + 25) / 60; SETMAX(v, 0); ADDSATT(e->trade_percent[j], v, 100); ADDSATT(e2->trade_percent[i], v, 100); } } } } } static void game_turn_diplo_adjust(struct game_s *g) { for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = i + 1; j < g->players; ++j) { if (!rnd_0_nm1(2, &g->seed)) { if (e->treaty[j] == TREATY_NONAGGRESSION) { game_diplo_act(g, rnd_1_n(3, &g->seed), i, j, 0, 0, 0); } if (e->treaty[j] == TREATY_ALLIANCE) { game_diplo_act(g, rnd_1_n(6, &g->seed), i, j, 0, 0, 0); } if (e->trade_bc[j] != 0) { game_diplo_act(g, rnd_1_n(3, &g->seed), i, j, 2, 0, 0); } } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { int s_ai; if (IS_HUMAN(g, i)) { continue; } s_ai = game_stat_fleet(g, i); for (player_id_t j = PLAYER_0; j < g->players; ++j) { int s_h; if (IS_AI(g, j)) { continue; } s_h = game_stat_fleet(g, j); if (1 && (s_ai < s_h) && (s_ai > 0) && (rnd_1_n(100, &g->seed) >= ((s_h * 50) / s_ai)) && (!rnd_0_nm1(20, &g->seed)) ) { game_diplo_act(g, -10, j, i, 8, 0, 0); } } } if ((g->year & 1) == 0) { uint8_t tbl_num_pp[PLAYER_NUM]; int gscale = ((g->galaxy_size + 1) * 3); int gdiv = g->galaxy_size + 6 - g->difficulty; for (player_id_t i = PLAYER_0; i < g->players; ++i) { tbl_num_pp[i] = 0; } for (int j = 0; j < g->galaxy_stars; ++j) { planet_t *p = &(g->planet[j]); if (p->prod_after_maint >= 100) { ++tbl_num_pp[p->owner]; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); if ((gscale < tbl_num_pp[i]) && !rnd_0_nm1(4, &g->seed)) { int v; v = rnd_1_n(4, &g->seed) * ((-(tbl_num_pp[i] - gscale)) / gdiv); v = (v / 3) * 4; if (IS_HUMAN(g, i)) { v /= 2; } for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (IS_HUMAN(g, j)) { continue; } if (BOOLVEC_IS1(e->contact, j) && (e->treaty[j] == TREATY_ALLIANCE)) { game_diplo_act(g, v, i, j, 12, 0, 0); } } } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); if (IS_HUMAN(g, i)) { continue; } for (player_id_t j = PLAYER_0; j < g->players; ++j) { if ((i != j) && (e->diplo_val[j] == 0)) { int16_t r1, r2; uint8_t v; r1 = e->relation1[j]; r2 = e->relation2[j]; v = (abs(r1) > rnd_1_n(105, &g->seed)) ? rnd_0_nm1(2, &g->seed) : 0; if (r1 < r2) { r1 += v; if (r1 > r2) { r1 = r2; } } else { r1 -= v; if (r1 < r2) { r1 = r2; } } SETRANGE(r1, -100, 100); e->relation1[j] = r1; } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (i == j) { e->relation1[j] = 0; } else { g->eto[j].relation1[i] = e->relation1[j]; } } } } static void game_add_planet_to_shield_finished(struct game_s *g, uint8_t pli, player_id_t owner) { BOOLVEC_SET1(g->planet[pli].finished, FINISHED_SHIELD); } static void game_turn_build_def(struct game_s *g) { int16_t cost_new[PLAYER_NUM], cost_diff[PLAYER_NUM]; for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); int16_t cost_old; cost_old = game_get_base_cost(g, i); e->base_weapon = game_get_base_weapon(g, i, e->tech.percent[TECH_FIELD_WEAPON]); e->base_shield = game_get_best_shield(g, i, e->tech.percent[TECH_FIELD_FORCE_FIELD]); e->base_comp = game_get_best_comp(g, i, e->tech.percent[TECH_FIELD_COMPUTER]); cost_new[i] = game_get_base_cost(g, i); cost_diff[i] = cost_new[i] - cost_old; SETMAX(cost_diff[i], 0); } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; if (owner != PLAYER_NONE) { empiretechorbit_t *e = &(g->eto[owner]); int prod, toup; prod = game_adjust_prod_by_special((p->slider[PLANET_SLIDER_DEF] * p->prod_after_maint) / 100, p->special); prod += p->bc_to_base; toup = cost_diff[owner] * p->missile_bases + p->bc_upgrade_base; if (toup >= prod) { toup -= prod; p->bc_upgrade_base = toup; p->bc_to_base = 0; } else { int tosh; prod -= toup; p->bc_upgrade_base = 0; tosh = e->planet_shield_cost - p->bc_to_shield; SETMAX(tosh, 0); if ((p->battlebg == 0) || game_xy_is_in_nebula(g, p->x, p->y)) { /* FIXME later check is redundant */ tosh = 0; p->bc_to_shield = 0; } if (prod <= tosh) { /* FIXME just "<" ? */ p->bc_to_shield += prod; prod = 0; } else { prod -= tosh; p->bc_to_shield = e->planet_shield_cost; while (prod >= cost_new[owner]) { prod -= cost_new[owner]; ++p->missile_bases; } } p->bc_to_base = prod; } { uint8_t newshield; int curcost; curcost = MIN(e->planet_shield_cost, p->bc_to_shield); newshield = 0; for (int j = 1; (j < PSHIELD_NUM) && (curcost >= game_num_pshield_cost[j]); ++j) { newshield += 5; } if (newshield != p->shield) { p->shield = newshield; if (newshield == g->eto[owner].have_planet_shield) { game_add_planet_to_shield_finished(g, i, owner); } } } } } } static inline void game_add_planet_to_stargate_finished(struct game_s *g, uint8_t pli, player_id_t owner) { BOOLVEC_SET1(g->planet[pli].finished, FINISHED_STARGATE); } static void game_turn_build_ship(struct game_s *g) { game_update_maint_costs(g); for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); shipresearch_t *srd = &(g->srd[i]); struct game_design_s gd; gd.sd_num = e->shipdesigns_num; gd.player_i = i; memcpy(gd.percent, e->tech.percent, sizeof(gd.percent)); for (int j = 0; j < gd.sd_num; ++j) { shipdesign_t *sd = &(srd->design[j]); gd.sd = *sd; sd->cost = game_design_calc_cost(&gd); } } for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; if (owner != PLAYER_NONE) { empiretechorbit_t *e = &(g->eto[owner]); shipresearch_t *srd = &(g->srd[owner]); int prod; uint8_t si; prod = game_adjust_prod_by_special((p->slider[PLANET_SLIDER_SHIP] * p->prod_after_maint) / 100, p->special); prod += p->bc_to_ship; /* BUG: A 1 BC bonus for having the slider > 0. This bonus is not taken into account by UI */ if (p->slider[PLANET_SLIDER_SHIP] > 0) { ++prod; } si = p->buildship; if (si == BUILDSHIP_STARGATE) { if (prod >= game_num_stargate_cost) { p->have_stargate = true; p->buildship = 0; p->bc_to_ship = prod - game_num_stargate_cost; game_add_planet_to_stargate_finished(g, i, owner); } else { p->bc_to_ship = prod; } } else { shipdesign_t *sd = &(srd->design[si]); int cost, shipnum; uint8_t dest; cost = sd->cost; shipnum = 0; while (prod >= cost) { ++shipnum; prod -= cost; } if ((shipnum + srd->shipcount[si]) > game_num_limit_ships_all) { shipnum = game_num_limit_ships_all - srd->shipcount[si]; } SETMAX(shipnum, 0); srd->shipcount[si] += shipnum; dest = p->reloc; if (dest == i) { e->orbit[i].ships[si] += shipnum; if (shipnum > 0) { BOOLVEC_SET1(p->finished, FINISHED_SHIP); } } else { if (shipnum > 0) { game_send_fleet_reloc(g, owner, i, dest, si, shipnum); } } g->evn.new_ships[owner][si] += shipnum; p->bc_to_ship = prod; } } } game_update_visibility(g); } static void game_turn_reserve(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; if (owner != PLAYER_NONE) { uint32_t v, r; v = p->prod_after_maint / 2; r = p->reserve; if (v < r) { r -= v; } else { r = 0; } p->reserve = r; } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); e->reserve_bc += (e->total_production_bc * e->tax) / 2000; } } static inline void game_add_planet_to_build_finished(struct game_s *g, uint8_t pli, player_id_t owner, uint8_t type) { if (game_opt_message_filter[type]) { return; } planet_t *p = &(g->planet[pli]); BOOLVEC_SET1(p->finished, type); ++g->evn.build_finished_num[owner]; } static bool game_turn_finished_switch_slider(struct game_s *g, struct planet_s *p, planet_slider_i_t from, planet_slider_i_t to) { if (game_num_slider_respects_locks && (p->slider_lock[from] || p->slider_lock[to])) { return false; } if (from == to) { return false; } int v = p->slider[from]; if (from == PLANET_SLIDER_ECO) { v -= game_planet_get_waste_percent(NULL, g, p, false); SETMAX(v, 0); } p->slider[from] -= v; p->slider[to] += v; return true; } static void game_turn_finished_disable_slider(struct game_s *g, struct planet_s *p, planet_slider_i_t from, bool build_ind) { if (game_num_slider_respects_locks && p->slider_lock[from]) { return; } planet_slider_i_t first = build_ind ? PLANET_SLIDER_IND : PLANET_SLIDER_TECH; game_turn_finished_switch_slider(g, p, from, first) || game_turn_finished_switch_slider(g, p, from, PLANET_SLIDER_TECH) || game_turn_finished_switch_slider(g, p, from, PLANET_SLIDER_SHIP) || game_turn_finished_switch_slider(g, p, from, PLANET_SLIDER_DEF) || game_turn_finished_switch_slider(g, p, from, PLANET_SLIDER_IND) || game_turn_finished_switch_slider(g, p, from, PLANET_SLIDER_ECO); } static void game_turn_build_ind(struct game_s *g) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); player_id_t owner; owner = p->owner; if (owner != PLAYER_NONE) { empiretechorbit_t *e; uint16_t fact, factold, num; uint8_t cost, bonus; int prod, v; e = &(g->eto[owner]); factold = fact = p->factories; cost = game_planet_get_fact_adj_cost(g, p); prod = game_adjust_prod_by_special((p->slider[PLANET_SLIDER_IND] * p->prod_after_maint) / 100, p->special); prod += p->bc_to_factory; bonus = (e->race == RACE_MEKLAR) ? 2 : 0; v = e->colonist_oper_factories - p->pop_oper_fact - bonus; if (v > 0) { v = v * (e->factory_cost / 2); if (game_num_factory_cost_fix) { if (e->race != RACE_MEKLAR) { v = (e->factory_cost * p->factories) / 2; } else { v = 0; } } } else { v = 0; } if ((prod / cost + fact) > (p->pop * p->pop_oper_fact)) { if (game_num_factory_cost_fix && (fact < (p->pop * p->pop_oper_fact))) { num = p->pop * p->pop_oper_fact - fact; fact = p->pop * p->pop_oper_fact; prod -= num * cost; } p->bc_to_refit += prod; if (p->bc_to_refit >= v) { if (game_num_factory_cost_fix && (e->race != RACE_MEKLAR)) { ++p->pop_oper_fact; SETMIN(p->pop_oper_fact, e->colonist_oper_factories); } else { p->pop_oper_fact = e->colonist_oper_factories; } prod = p->bc_to_refit - v; p->bc_to_refit = 0; } else { prod = 0; } } num = prod / cost; p->bc_to_factory = prod % cost; v = p->max_pop3 * game_planet_get_pop_oper_fact(g, p); if (v < (fact + num)) { v = (fact + num) - v; SETMAX(v, 0); SETMIN(v, num); num -= v; } else { v = 0; } if (game_num_factory_cost_fix && (p->pop_oper_fact < e->colonist_oper_factories)) { p->bc_to_refit += (v * cost) / 2; } else { e->reserve_bc += (v * cost) / 2; } fact += num; SETMIN(fact, game_num_max_factories); p->factories = fact; if ((fact != factold) && (fact >= (p->max_pop3 * e->colonist_oper_factories))) { if (IS_HUMAN(g, owner) && (p->slider[PLANET_SLIDER_IND] > 0)) { game_turn_finished_disable_slider(g, p, PLANET_SLIDER_IND, false); } game_add_planet_to_build_finished(g, i, owner, FINISHED_FACT); } } } } static void game_turn_move_ships(struct game_s *g) { void *ctx; bool local_multiplayer = g->gaux->local_players > 1, move_back = false; ctx = ui_gmap_basic_init(g, local_multiplayer); if (local_multiplayer) { memcpy(g->gaux->move_temp->enroute, g->enroute, g->enroute_num * sizeof(fleet_enroute_t)); memcpy(g->gaux->move_temp->transport, g->transport, g->transport_num * sizeof(transport_t)); g->gaux->move_temp->crystal = g->evn.crystal; g->gaux->move_temp->amoeba = g->evn.amoeba; } for (g->active_player = 0; g->active_player < g->players; ++g->active_player) { bool flag_more; if (BOOLVEC_IS1(g->is_ai, g->active_player)) { continue; } if (move_back) { memcpy(g->enroute, g->gaux->move_temp->enroute, g->enroute_num * sizeof(fleet_enroute_t)); memcpy(g->transport, g->gaux->move_temp->transport, g->transport_num * sizeof(transport_t)); g->evn.crystal = g->gaux->move_temp->crystal; g->evn.amoeba = g->gaux->move_temp->amoeba; } game_update_visibility(g); flag_more = true; ui_gmap_basic_start_player(ctx, g->active_player); for (int frame = 0; (frame < 20) && flag_more; ++frame) { bool odd_frame; game_update_visibility(g); odd_frame = frame & 1; ui_gmap_basic_start_frame(ctx, g->active_player); flag_more = false; for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); if ((r->speed * 2) > frame) { bool in_nebula; int x, y; x = r->x; y = r->y; in_nebula = (odd_frame || (frame == 0)) ? false : game_xy_is_in_nebula(g, x, y); if (odd_frame || (frame == 0) || (!in_nebula)) { int x1, y1; const planet_t *p; p = &(g->planet[r->dest]); x1 = p->x; y1 = p->y; if (r->speed == FLEET_SPEED_STARGATE) { x = x1; y = y1; } else { flag_more = true; util_math_go_line_dist(&x, &y, x1, y1, odd_frame ? 6 : 5); } r->x = x; r->y = y; } else if (in_nebula) { flag_more = true; /* WASBUG MOO1 stopped nebula movement early if no transports or faster ships enroute */ } } } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); if ((r->speed * 2) > frame) { bool in_nebula; int x, y; x = r->x; y = r->y; in_nebula = (!odd_frame) ? false : game_xy_is_in_nebula(g, x, y); if ((!odd_frame) || (!in_nebula)) { int x1, y1; const planet_t *p; p = &(g->planet[r->dest]); x1 = p->x; y1 = p->y; if (r->speed == FLEET_SPEED_STARGATE) { x = x1; y = y1; } else { flag_more = true; util_math_go_line_dist(&x, &y, x1, y1, odd_frame ? 6 : 5); } r->x = x; r->y = y; } else if (in_nebula) { flag_more = true; /* WASBUG MOO1 stopped nebula movement early if no fleets or faster ships enroute */ } } } for (int i = 0; i < 2; ++i) { monster_t *m; m = (i == 0) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists && (m->counter <= 0)) { int x, y, x1, y1; const planet_t *p; p = &(g->planet[m->dest]); x1 = p->x; y1 = p->y; x = m->x; y = m->y; if (((x != x1) || (y != y1)) && (frame < 2)) { util_math_go_line_dist(&x, &y, x1, y1, odd_frame ? 6 : 5); m->x = x; m->y = y; } } } ui_gmap_basic_draw_frame(ctx, g->active_player); ui_gmap_basic_finish_frame(ctx, g->active_player); } move_back = local_multiplayer; } ui_gmap_basic_shutdown(ctx); for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); const planet_t *p; p = &(g->planet[r->dest]); if ((r->x == p->x) && (r->y == p->y)) { fleet_orbit_t *o; o = &(g->eto[r->owner].orbit[r->dest]); for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { uint32_t s; s = o->ships[j] + r->ships[j]; SETMIN(s, game_num_limit_ships); o->ships[j] = s; } util_table_remove_item_any_order(i, g->enroute, sizeof(fleet_enroute_t), g->enroute_num); --g->enroute_num; --i; } } game_update_visibility(g); } #if 0 static void game_turn_unrest_hmm1(struct game_s *g) { /* this does nothing except churn the rng! */ int tbl1[PLAYER_NUM], tbl2[PLAYER_NUM]; for (player_id_t i = PLAYER_0; i < g->players; ++i) { tbl1[i] = 0; tbl2[i] = 0; } for (player_id_t i = PLAYER_0; i < g->players; ++i) { const planet_t *p; int pl, v; v = tbl2[i] * 2; /* always 0 */ pl = game_planet_get_random(g, i); if (pl != PLANET_NONE) { p = &(g->planet[pi]); /* WASBUG unrest != RESOLVED test done even when pl < 0 */ if ((p->unrest != PLANET_UNREST_REBELLION) || (p->unrest != PLANET_UNREST_RESOLVED)) { if (rnd_1_n(100, &g->seed) <= v) { /* never true */ p->unrest = PLANET_UNREST_REBELLION; p->unrest_reported = false; p->rebels = p->pop / 2; } } } } } #endif static void game_turn_explore(struct game_s *g) { for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); p->artifact_looter = PLAYER_NONE; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (BOOLVEC_IS0(p->explored, i) || (p->owner == PLAYER_NONE)) { empiretechorbit_t *e = &(g->eto[i]); bool flag_visible, by_scanner; flag_visible = false; for (int j = 0; j < e->shipdesigns_num; ++j) { if (e->orbit[pli].ships[j] > 0) { flag_visible = true; break; } } by_scanner = false; if ((!flag_visible) && e->have_adv_scanner) { for (int pli2 = 0; pli2 < g->galaxy_stars; ++pli2) { const planet_t *p2 = &(g->planet[pli2]); if ((p2->owner == i) && (util_math_dist_fast(p->x, p->y, p2->x, p2->y) <= game_num_adv_scan_range)) { flag_visible = true; break; } } by_scanner = true; } /*c4ca*/ if (flag_visible) { bool first, flag_colony_ship, flag_do_colonize, was_explored; int best_colonize, best_colonyship = 0; /* FIXME artifacts disappearing due to scanning a planet is weird */ first = BOOLVEC_IS_CLEAR(p->explored, PLAYER_NUM); if ((p->special == PLANET_SPECIAL_ARTIFACTS) && (!by_scanner) && first) { /* FIXME? AIs (last player ID) win on simultaneous explore */ p->artifact_looter = i; } flag_colony_ship = false; flag_do_colonize = false; best_colonize = 200; for (int j = 0; j < e->shipdesigns_num; ++j) { const shipdesign_t *sd = &(g->srd[i].design[j]); int can_colonize; can_colonize = 200; for (int k = 0; k < SPECIAL_SLOT_NUM; ++k) { ship_special_t s; s = sd->special[k]; if ((s >= SHIP_SPECIAL_STANDARD_COLONY_BASE) && (s <= SHIP_SPECIAL_RADIATED_COLONY_BASE)) { can_colonize = PLANET_TYPE_MINIMAL - (s - SHIP_SPECIAL_STANDARD_COLONY_BASE); } } if ((can_colonize < 200) && (e->orbit[pli].ships[j] > 0)) { flag_colony_ship = true; if (can_colonize < best_colonize) { best_colonize = can_colonize; best_colonyship = j; } if (e->race == RACE_SILICOID) { best_colonize = PLANET_TYPE_RADIATED; } } } if (0 || (best_colonize == 200) || (p->owner != PLAYER_NONE) || (p->type == PLANET_TYPE_NOT_HABITABLE) || (p->type < best_colonize) ) { best_colonize = 0; } was_explored = BOOLVEC_IS1(p->explored, i); BOOLVEC_SET1(p->explored, i); if (IS_HUMAN(g, i)) { if ((best_colonize != 0) || (!was_explored)) { game_update_visibility(g); /* from explore_draw_cb */ if ((p->type < best_colonize) || (best_colonize == 0)) { flag_colony_ship = false; } else { flag_colony_ship = true; } if (ui_explore(g, i, pli, by_scanner, flag_colony_ship) && flag_colony_ship) { flag_do_colonize = true; } } } else { if (best_colonize != 0) { flag_do_colonize = true; } } if (flag_do_colonize) { p->owner = i; p->pop = 2; if (1 && game_num_colonized_factories_fix && (p->prev_owner != PLAYER_NONE) && (p->prev_owner != i)) { if (p->factories != 0) { p->pop_oper_fact = 1; } else { p->pop_oper_fact = 2; } p->bc_to_refit = 0; } --e->orbit[pli].ships[best_colonyship]; if ((pli == g->evn.planet_orion_i) && game_num_news_orion) { g->evn.have_orion_conquer = i + 1; } } } } } } } static int game_turn_transport_shoot(struct game_s *g, uint8_t planet_i, player_id_t rowner, uint16_t num_transports, uint8_t speed, player_id_t attacker, int bases, weapon_t basewpnt) { const planet_t *p = &(g->planet[planet_i]); const empiretechorbit_t *ea = &(g->eto[attacker]); const empiretechorbit_t *ed = &(g->eto[rowner]); int totaldmg = 0, transport_hp, total_hp, complevel, killed; uint8_t bestcomp = 0, bestarmor = 0; const uint8_t *rc = &(g->srd[rowner].researchcompleted[TECH_FIELD_CONSTRUCTION][0]); /* Transports use the best armor that the owner has researched. */ for (int i = 0; i < ed->tech.completed[TECH_FIELD_CONSTRUCTION]; ++i) { uint8_t tier; tech_group_t group; group = game_tech_get_group(g->gaux, TECH_FIELD_CONSTRUCTION, rc[i]); tier = game_tech_get_tier(g->gaux, TECH_FIELD_CONSTRUCTION, rc[i]); if (group == TECH_GROUP_ARMOR) { bestarmor = tier; } } transport_hp = ((bestarmor + 1) * 15); total_hp = transport_hp * num_transports; uint32_t tbl[WEAPON_NUM]; memset(tbl, 0, sizeof(tbl)); tbl[basewpnt] = bases * 24; for (int i = 0; i < ea->shipdesigns_num; ++i) { const shipdesign_t *sd = &(g->srd[attacker].design[i]); uint8_t comp; comp = sd->comp; if (comp > speed) { /* FIXME BUG ? */ bestcomp = comp; } for (int j = 0; j < WEAPON_SLOT_NUM; ++j) { weapon_t wpnt = sd->wpnt[j]; uint32_t v; v = ea->orbit[planet_i].ships[i] * sd->wpnn[j]; if (v != 0) { const struct shiptech_weap_s *w; int ns; w = &(tbl_shiptech_weap[wpnt]); ns = w->numshots; if (ns == -1) { ns = 4; } v *= ns; if (w->nummiss != 0) { v *= w->nummiss; } SETMIN(v, game_num_max_trans_dmg); if (w->is_bomb || w->is_bio) { v = 0; } if (w->misstype != 0) { v /= 2; } tbl[wpnt] += (v * 2) / speed; } } } if (bases > 0) { bestcomp = game_get_best_comp(g, rowner, ed->tech.percent[TECH_FIELD_COMPUTER]); /* FIXME should be ea ? */ } complevel = (bestcomp - speed) * 2 + 12; SETRANGE(complevel, 1, 20); for (int i = 0; i < (game_num_orbital_weap_any ? WEAPON_NUM : WEAPON_CRYSTAL_RAY); ++i) { /* WASBUG? excludes death ray and amoeba stream too */ uint32_t vcur = tbl[i]; if (vcur != 0) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[i]); int dmgmin, dmgmax; dmgmin = w->damagemin; dmgmax = w->damagemax; if (dmgmin == dmgmax) { for (uint32_t n = 0; n < vcur; ++n) { if (rnd_1_n(20, &g->seed) <= complevel) { totaldmg += dmgmax; } } } else { /*7c47d*/ int dmgrange; dmgrange = dmgmax - dmgmin + 1; --dmgmin; vcur = (complevel * vcur) / 20; for (uint32_t n = 0; n < vcur; ++n) { int dmg; dmg = rnd_1_n(dmgrange, &g->seed) + dmgmin; if (dmg > 0) { totaldmg += dmg; } } } if (totaldmg >= total_hp) { break; } } } killed = totaldmg / transport_hp; SETMIN(killed, 1000); for (monster_id_t i = MONSTER_CRYSTAL; i <= MONSTER_AMOEBA; ++i) { monster_t *m; m = (i == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists && (m->killer == PLAYER_NONE) && (m->x == p->x) && (m->y == p->y)){ killed = 1000; } } return killed; } static void game_turn_transport(struct game_s *g) { for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); for (player_id_t i = PLAYER_0; i < g->players; ++i) { p->inbound[i] = 0; p->total_inbound[i] = 0; } } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); planet_t *p; uint8_t dest; dest = r->dest; p = &(g->planet[dest]); if ((r->x == p->x) && (r->y == p->y)) { int pop2, pop3; player_id_t owner; owner = r->owner; pop2 = pop3 = r->pop; for (int j = 0; j < g->players; ++j) { treaty_t t; if (j == owner) { continue; } t = g->eto[owner].treaty[j]; if ((j == p->owner) || (t == TREATY_NONE) || (t >= TREATY_WAR)) { empiretechorbit_t *e; e = &(g->eto[j]); if (j == p->owner) { pop3 -= game_turn_transport_shoot(g, dest, owner, pop3, r->speed, j, p->missile_bases, e->base_weapon); } else { /*e102*/ bool any_ships; any_ships = false; for (int k = 0; k < e->shipdesigns_num; ++k) { if (e->orbit[dest].ships[k] > 0) { any_ships = true; break; } } if (any_ships) { pop3 -= game_turn_transport_shoot(g, dest, owner, pop3, r->speed, j, 0, WEAPON_NONE); } } } } if (g->evn.have_guardian && (dest == g->evn.planet_orion_i)) { pop3 = 0; } for (monster_id_t j = MONSTER_CRYSTAL; j <= MONSTER_AMOEBA; ++j) { monster_t *m; m = (j == MONSTER_CRYSTAL) ? &(g->evn.crystal) : &(g->evn.amoeba); if (m->exists && /*(m->killer == PLAYER_NONE) &&*/ (m->x == p->x) && (m->y == p->y)) { /* FIXME dead monster kills transports ? */ pop3 = 0; } } SETMAX(pop3, 0); if (g->eto[owner].have_combat_transporter) { int n; n = pop2 - pop3; if (game_num_combat_trans_fix) { /* do as OSG says: 50% chance, 25% if interdictor */ int c; c = g->eto[p->owner].have_sub_space_int ? 4 : 2; for (int j = 0; j < n; ++j) { if (!rnd_0_nm1(c, &g->seed)) { ++pop3; } } } else if (g->eto[p->owner].have_sub_space_int) { /* WASBUG transporters only work when planet owner has interdictor */ for (int j = 0; j < n; ++j) { if (!rnd_0_nm1(4, &g->seed)) { ++pop3; } else if (!rnd_0_nm1(2, &g->seed)) { ++pop3; } } } } /*e2a4*/ if (pop3 <= 0) { if (IS_HUMAN(g, owner) || IS_HUMAN(g, p->owner)) { char *buf = ui_get_strbuf(); const char *s; if ((g->gaux->local_players == 1) && IS_HUMAN(g, owner)) { s = game_str_sb_your; } else { s = game_str_tbl_race[g->eto[owner].race]; } lib_sprintf(buf, UI_STRBUF_SIZE, "%s %s %s %s", s, game_str_sm_traad1, g->planet[dest].name, game_str_sm_traad2); ui_turn_msg(g, IS_HUMAN(g, owner) ? owner : p->owner, buf); } } else if (p->owner == PLAYER_NONE) { /*e36d*/ if (IS_HUMAN(g, owner)) { char *buf = ui_get_strbuf(); lib_sprintf(buf, UI_STRBUF_SIZE, "%s %s %s", game_str_sm_trbdb1, g->planet[dest].name, game_str_sm_trbdb2); ui_turn_msg(g, owner, buf); } } else { /*e3fe*/ if ((p->owner == PLAYER_NONE) || (p->pop == 0)) { if (IS_HUMAN(g, owner)) { ui_landing(g, owner, dest); } p->pop = pop3; p->bc_to_refit = 0; p->pop_oper_fact = 1; if (dest == g->evn.planet_orion_i) { g->evn.have_orion_conquer = owner + 1; } p->owner = owner; } else if (p->owner == owner) { if (p->unrest == PLANET_UNREST_REBELLION) { ADDSATT(p->inbound[owner], pop3, game_num_max_inbound); p->total_inbound[owner] += pop3; } else { ADDSATT(p->pop, pop3, p->max_pop3); } } else { /*e5a6*/ if (g->eto[owner].treaty[p->owner] != TREATY_ALLIANCE) { ADDSATT(p->inbound[owner], pop3, game_num_max_inbound); p->total_inbound[owner] += pop2; } } } /*e639*/ util_table_remove_item_any_order(i, g->transport, sizeof(transport_t), g->transport_num); --g->transport_num; --i; } } } static void game_turn_coup(struct game_s *g) { uint8_t tbl_planets[PLAYER_NUM]; uint8_t tbl_rebelplanets[PLAYER_NUM]; memset(tbl_planets, 0, sizeof(tbl_planets)); memset(tbl_rebelplanets, 0, sizeof(tbl_rebelplanets)); BOOLVEC_CLEAR(g->evn.coup, PLAYER_NUM); for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); if (p->owner != PLAYER_NONE) { ++tbl_planets[p->owner]; if (p->unrest == PLANET_UNREST_REBELLION) { ++tbl_rebelplanets[p->owner]; } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((tbl_rebelplanets[i] >= (tbl_planets[i] + 1) / 2) && IS_ALIVE(g, i)) { empiretechorbit_t *e = &(g->eto[i]); e->trait2 = rnd_0_nm1(TRAIT2_NUM, &g->seed); e->trait1 = rnd_0_nm1(TRAIT1_NUM, &g->seed); /* WASBUG MOO1 reads an unitialized variable at BP-2 and check for it to be 0 or 1. It is the return address to the caller which is neither of the values, leading to the code below. */ for (player_id_t j = PLAYER_0; j < g->players; ++j) { int16_t rel; rel = e->relation2[j]; e->relation1[j] = rel; if (i != j) { g->eto[j].relation1[i] = rel; if (IS_HUMAN(g, j)) { game_diplo_break_treaty(g, i, j); game_diplo_break_trade(g, i, j); } } } BOOLVEC_SET1(g->evn.coup, i); for (int pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); if (p->owner == i) { p->unrest = PLANET_UNREST_NORMAL; p->rebels = 0; } } } } } static bool game_turn_check_end(struct game_s *g, struct game_end_s *ge) { player_id_t pih = PLAYER_NONE; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (IS_HUMAN(g, i) && IS_ALIVE(g, i)) { pih = i; break; } } if (g->end == GAME_END_LOST_EXILE) { ge->type = GAME_END_LOST_EXILE; if (pih == g->winner) { for (player_id_t i = pih + 1; i < g->players; ++i) { if (IS_HUMAN(g, i) && IS_ALIVE(g, i)) { pih = i; break; } } } ge->name = g->emperor_names[pih]; return true; } if (g->end == GAME_END_WON_GOOD) { ge->type = GAME_END_WON_GOOD; ge->name = g->emperor_names[g->winner]; ge->race = g->eto[g->winner].race; return true; } { player_id_t pi1 = PLAYER_NONE, pi2 = PLAYER_NONE; bool human_alive = false; uint8_t num_planets[PLAYER_NUM]; uint8_t good_planets[PLAYER_NUM]; memset(num_planets, 0, sizeof(num_planets)); memset(good_planets, 0, sizeof(num_planets)); for (int pli = 0; pli < g->galaxy_stars; ++pli) { const planet_t *p = &(g->planet[pli]); if (p->owner != PLAYER_NONE) { ++num_planets[p->owner]; if (p->unrest != PLANET_UNREST_REBELLION) { ++good_planets[p->owner]; } } } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (num_planets[i] > 0) { if (pi1 == PLAYER_NONE) { pi1 = i; } else if (pi2 == PLAYER_NONE) { pi2 = i; } if (IS_HUMAN(g, i) && (good_planets[i] > 0) && IS_ALIVE(g, i)) { human_alive = true; } } } if (pi2 == PLAYER_NONE) { ge->type = GAME_END_WON_TYRANT; ge->name = g->emperor_names[pi1]; ge->race = g->eto[pi1].race; return true; } if (!human_alive) { struct news_s ns; int killer = g->gaux->human_killer; if (killer >= g->players) { killer = (pi1 != PLAYER_NONE) ? pi1 : 1; } ns.type = GAME_NEWS_GENOCIDE; ns.race = g->eto[pih].race; ns.subtype = 3; ns.num1 = pih; ui_news_start(); ui_news(g, &ns); ge->type = GAME_END_LOST_FUNERAL; ge->race = g->eto[killer].banner; ge->banner_dead = pih; return true; } } return false; } static void game_turn_update_have_met(struct game_s *g) { game_update_empire_contact(g); for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); if (!IS_HUMAN(g, i)) { continue; } for (player_id_t j = PLAYER_0; j < g->players; ++j) { if ((i != j) && (!e->have_met[j]) && BOOLVEC_IS1(e->contact, j)) { e->have_met[j] = 1; e->treaty[j] = TREATY_NONE; g->eto[j].treaty[i] = TREATY_NONE; } } } } static void game_turn_audiences(struct game_s *g) { for (player_id_t ph = PLAYER_0; ph < PLAYER_NUM; ++ph) { empiretechorbit_t *e = &(g->eto[ph]); if (!IS_HUMAN(g, ph)) { continue; } g->evn.newtech[ph].num = 0; for (player_id_t pa = PLAYER_0; pa < PLAYER_NUM; ++pa) { if (IS_AI(g, pa) && (e->diplo_type[pa] != 0)) { game_audience(g, ph, pa); e->diplo_type[pa] = 0; } } game_tech_finish_new(g, ph); ui_newtech(g, ph); } } static void game_turn_contact_broken(struct game_s *g, player_id_t pi, const BOOLVEC_PTRPARAMI(bv)) { empiretechorbit_t *e = &(g->eto[pi]); if (!IS_ALIVE(g, pi)) { return; } for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != pi) && IS_ALIVE(g, i) && BOOLVEC_IS0(e->contact, i) && BOOLVEC_IS1(bv, i)) { empiretechorbit_t *e2 = &(g->eto[i]); e->mood_trade[i] = 0; e->trade_bc[i] = 0; e->trade_percent[i] = 0; e->spymode[i] = SPYMODE_HIDE; BOOLVEC_SET1(e->contact_broken, i); e2->mood_trade[pi] = 0; e2->trade_bc[pi] = 0; e2->trade_percent[pi] = 0; e2->spymode[pi] = SPYMODE_HIDE; BOOLVEC_SET1(e2->contact_broken, pi); } } } static void game_turn_update_seen(struct game_s *g) { game_update_visibility(g); for (uint8_t i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { bool can_see; can_see = (BOOLVEC_IS1(p->within_srange, pi) || (p->owner == pi)); if (!can_see) { /* WASBUG handled only on game load (game_update_seen_by_orbit) */ const shipcount_t *os = &(g->eto[pi].orbit[i].ships[0]); for (int j = 0; j < NUM_SHIPDESIGNS; ++j) { if (os[j] != 0) { can_see = true; break; } } } if (can_see) { g->seen[pi][i].owner = p->owner; g->seen[pi][i].pop = p->pop; g->seen[pi][i].bases = p->missile_bases; g->seen[pi][i].factories = p->factories; } else if ((p->owner != PLAYER_NONE) && BOOLVEC_IS1(g->eto[pi].contact, p->owner)) { g->seen[pi][i].owner = p->owner; } } } } static void game_turn_finished_slider(struct game_s *g) { for (uint8_t pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); player_id_t pi; empiretechorbit_t *e; bool cond_build_ind; pi = p->owner; if ((pi == PLAYER_NONE) || IS_AI(g, pi)) { BOOLVEC_CLEAR(p->finished, FINISHED_NUM); continue; } e = &(g->eto[pi]); cond_build_ind = (p->factories < (p->pop * e->colonist_oper_factories)); if (game_num_cond_switch_to_ind_fix) { cond_build_ind = (p->factories < (p->max_pop3 * e->colonist_oper_factories)); } if (game_num_factory_cost_fix) { cond_build_ind |= (p->pop_oper_fact < e->colonist_oper_factories); } if (BOOLVEC_IS1(p->finished, FINISHED_SOILATMOS) && !(game_num_slider_eco_done_fix && game_planet_can_terraform(g, p, p->owner, true))) { game_turn_finished_disable_slider(g, p, PLANET_SLIDER_ECO, cond_build_ind); game_add_planet_to_build_finished(g, pli, pi, FINISHED_SOILATMOS); } if (1 && (p->pop >= p->max_pop3) && (p->unrest == PLANET_UNREST_NORMAL) ) { bool flag_pending_ecoproj; int v; v = (p->prod_after_maint * p->slider[PLANET_SLIDER_ECO]) / 100; flag_pending_ecoproj = false; if (v > 0) { if (0 || (e->have_atmos_terra && (p->growth == PLANET_GROWTH_HOSTILE)) || (e->have_soil_enrich && (p->growth == PLANET_GROWTH_NORMAL)) || (e->have_adv_soil_enrich && ((p->growth == PLANET_GROWTH_NORMAL) || (p->growth == PLANET_GROWTH_FERTILE))) || ((p->max_pop3 - p->max_pop2) < e->have_terraform_n) ) { flag_pending_ecoproj = true; } } if (!flag_pending_ecoproj) { int w, waste = 0; w = game_planet_get_waste_percent(&waste, g, p, false); SUBSAT0(v, waste); if (0 || ((game_get_pop_growth_for_eco(g, p, v) / 10) > 0) || ((p->slider[PLANET_SLIDER_ECO] != 0) && (e->race == RACE_SILICOID)) ) { if ((p->pop > p->pop_prev) || (p->slider[PLANET_SLIDER_ECO] > (w + game_num_eco_slider_slack))) { game_turn_finished_disable_slider(g, p, PLANET_SLIDER_ECO, cond_build_ind); if (p->pop > p->pop_prev) { game_add_planet_to_build_finished(g, pli, pi, FINISHED_POPMAX); } } } if (1 && (p->slider[PLANET_SLIDER_ECO] > 0) && ((e->race == RACE_SILICOID) || ((e->ind_waste_scale == 0) && (p->waste == 0))) ) { game_turn_finished_disable_slider(g, p, PLANET_SLIDER_ECO, cond_build_ind); } } } if (BOOLVEC_IS1(p->finished, FINISHED_SHIELD)) { game_turn_finished_disable_slider(g, p, PLANET_SLIDER_DEF, false); game_add_planet_to_build_finished(g, pli, pi, FINISHED_SHIELD); } if (BOOLVEC_IS1(p->finished, FINISHED_STARGATE)) { /* WASBUG MOO1 has DEF, not SHIP */ /* p->slider[PLANET_SLIDER_TECH] += p->slider[PLANET_SLIDER_SHIP]; p->slider[PLANET_SLIDER_SHIP] = 0; */ game_turn_finished_disable_slider(g, p, PLANET_SLIDER_SHIP, false); game_add_planet_to_build_finished(g, pli, pi, FINISHED_STARGATE); } } } static void game_turn_claim(struct game_s *g) { for (uint8_t pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); player_id_t pi; pi = p->owner; p->claim = pi; if (pi == PLAYER_NONE) { for (pi = PLAYER_0; pi < g->players; ++pi) { empiretechorbit_t *e = &(g->eto[pi]); for (int i = 0; i < e->shipdesigns_num; ++i) { if (e->orbit[pli].ships[i] != 0) { p->claim = pi; break; } } } } } } static void game_turn_update_final_war(struct game_s *g) { if (g->end != GAME_END_FINAL_WAR) { return; } game_tech_final_war_share(g); for (player_id_t i = 0; i < g->players; ++i) { if (IS_HUMAN(g, i)) { game_tech_finish_new(g, i); ui_newtech(g, i); } } for (player_id_t pi1 = PLAYER_0; pi1 < g->players; ++pi1) { empiretechorbit_t *e1 = &(g->eto[pi1]); for (player_id_t pi2 = pi1 + 1; pi2 < g->players; ++pi2) { empiretechorbit_t *e2 = &(g->eto[pi2]); if (BOOLVEC_IS1(g->refuse, pi1) == BOOLVEC_IS1(g->refuse, pi2)) { e1->treaty[pi2] = TREATY_ALLIANCE; e2->treaty[pi1] = TREATY_ALLIANCE; e1->relation1[pi2] = 100; e2->relation1[pi1] = 100; } else { e1->treaty[pi2] = TREATY_FINAL_WAR; e2->treaty[pi1] = TREATY_FINAL_WAR; e1->relation1[pi2] = -100; e2->relation1[pi1] = -100; } } } } /* -------------------------------------------------------------------------- */ struct game_end_s game_turn_process(struct game_s *g) { struct game_end_s game_end; BOOLVEC_TBL_DECLARE(old_contact, PLAYER_NUM, PLAYER_NUM); uint8_t old_focus[PLAYER_NUM]; int num_alive = 0, num_colony = 0; game_end.type = GAME_END_NONE; game_turn_limit_ships(g); for (int i = 0; i < g->players; ++i) { BOOLVEC_TBL_COPY1(old_contact, g->eto[i].contact, i, PLAYER_NUM); old_focus[i] = g->planet_focus_i[i]; } if ((g->year > 40) && (!rnd_0_nm1(30, &g->seed)) && (copyprot_status == 0)) { copyprot_status = 1; } ui_turn_pre(g); game_turn_countdown_ceasefire(g); game_turn_update_mood_blunder(g); game_update_have_reserve_fuel(g); game_ai->turn_p1(g); game_ai->turn_p2(g); game_update_have_reserve_fuel(g); game_ai->turn_p3(g); game_turn_init_z_finished(g); game_turn_send_transport(g); game_update_production(g); game_turn_build_eco(g); game_update_total_research(g); game_update_have_reserve_fuel(g); game_turn_update_trade(g); game_spy_build(g); if (!game_num_hidden_child_labor_fix) { game_update_production(g); } game_turn_diplo_adjust(g); game_turn_build_def(g); game_turn_build_ship(g); game_turn_reserve(g); game_turn_build_ind(g); game_turn_move_ships(g); game_turn_limit_ships(g); game_remove_empty_fleets(g); game_spy_report(g); game_battle_handle_all(g); /*game_turn_unrest_hmm1(g);*/ for (int i = 0; i < g->players; ++i) { g->evn.newtech[i].num = 0; } { struct spy_turn_s st[1]; game_spy_turn(g, st); game_spy_esp_human(g, st); game_spy_sab_human(g); } /*ui_newtech(); FIXME redundant;*/ for (int i = 0; i < g->players; ++i) { g->evn.newtech[i].num = 0; } /*935f*/ game_tech_research(g); for (int i = 0; i < g->players; ++i) { if (IS_HUMAN(g, i)) { game_tech_finish_new(g, i); ui_newtech(g, i); } } /* FIXME useless? game_battle should have taken care of this */ if (g->evn.have_guardian) { uint8_t o = g->evn.planet_orion_i; for (int i = 0; i < g->players; ++i) { shipcount_t *s = &(g->eto[i].orbit[o].ships[0]); memset(s, 0, sizeof(*s)); } } game_turn_explore(g); game_turn_bomb(g); game_turn_transport(g); { const uint8_t *grdata; grdata = game_turn_ground_resolve_all(g); game_turn_ground_show_all(g, grdata); } game_turn_coup(g); if (game_turn_check_end(g, &game_end)) { return game_end; } game_event_new(g); if (game_event_run(g, &game_end)) { return game_end; } if (game_turn_check_end(g, &game_end)) { return game_end; } for (int pli = 0; pli < g->galaxy_stars; ++pli) { player_id_t looter; looter = g->planet[pli].artifact_looter; if (looter != PLAYER_NONE) { game_tech_get_artifact_loot(g, pli, looter); } } for (int i = 0; i < g->players; ++i) { if (IS_HUMAN(g, i)) { game_tech_finish_new(g, i); ui_newtech(g, i); } g->evn.newtech[i].num = 0; } game_turn_update_have_met(g); game_ai->turn_diplo_p1(g); for (int i = 0; i < g->galaxy_stars; ++i) { if (g->planet[i].owner != PLAYER_NONE) { ++num_colony; } } for (int i = 0; i < g->players; ++i) { if (IS_ALIVE(g, i)) { ++num_alive; } } if (1 && (!g->gaux->flag_cheat_elections) && (game_num_council_years != 0) && (((g->year % game_num_council_years) == 0) || (!g->election_held)) && (num_alive > 2) && (((g->galaxy_stars * 2) / 3) <= num_colony) && (g->end == GAME_END_NONE) ) { game_election(g); g->election_held = true; } if (game_turn_check_end(g, &game_end)) { return game_end; } if (g->gaux->local_players > 1) { game_turn_update_final_war(g); /* MOO1 does this much later */ } game_ai->turn_diplo_p2(g); game_turn_audiences(g); if (game_turn_check_end(g, &game_end)) { return game_end; } for (player_id_t i = PLAYER_0; i < g->players; ++i) { game_turn_contact_broken(g, i, BOOLVEC_TBL_PTRPARAMM(old_contact, i)); } game_fleet_unrefuel(g); game_update_production(g); if (copyprot_status == 1) { ui_copyprotection_check(g); } for (player_id_t i = PLAYER_0; i < g->players; ++i) { game_update_eco_on_waste(g, i, false); } game_turn_update_seen(g); game_diplo_mood_relax(g); for (int i = 0; i < g->players; ++i) { g->planet_focus_i[i] = old_focus[i]; /* FIXME should not be needed anymore */ } ++g->year; if (copyprot_status == 1) { ui_copyprotection_lose(g, &game_end); return game_end; } #if 0 game_turn_show_newships(g); /* handled in game_turn_start_messages */ #endif /* MOO1 autosaves here every 5 turns */ game_update_tech_util(g); for (player_id_t i = PLAYER_0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { e->tech.percent[f] = game_tech_get_field_percent(g, i, f); } } game_turn_finished_slider(g); game_turn_claim(g); game_update_within_range(g); if (game_num_extended_reloc_range) { game_update_reloc_dest(g); } game_update_visibility(g); if (g->gaux->local_players == 1) { game_turn_update_final_war(g); /* MOO1 does this here, after update_tech_util etc */ } game_remove_empty_fleets(g); game_planet_update_home(g); return game_end; } 1oom-1.11.2/src/game/game_turn.h000066400000000000000000000003301476061725400163110ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_TURN_H #define INC_1OOM_GAME_TURN_H #include "game_end.h" #include "types.h" struct game_s; extern struct game_end_s game_turn_process(struct game_s *g); extern int copyprot_status; #endif 1oom-1.11.2/src/game/game_turn_start.c000066400000000000000000000037271476061725400175360ustar00rootroot00000000000000#include "config.h" #include #include "game_turn_start.h" #include "boolvec.h" #include "game.h" #include "game_str.h" #include "lib.h" #include "types.h" #include "ui.h" #include "util.h" /* -------------------------------------------------------------------------- */ void game_turn_start_messages(struct game_s *g, player_id_t pi) { char *buf = ui_get_strbuf(); { empiretechorbit_t *e = &(g->eto[pi]); for (player_id_t i = PLAYER_0; i < g->players; ++i) { if (BOOLVEC_IS1(e->contact_broken, i)) { BOOLVEC_SET0(e->contact_broken, i); lib_sprintf(buf, UI_STRBUF_SIZE, "%s %s %s", game_str_tr_cont1, game_str_tbl_race[g->eto[i].race], game_str_tr_cont2); ui_turn_msg(g, pi, buf); } } } for (uint8_t pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); if (BOOLVEC_IS1(p->unrefuel, pi)) { struct strbuild_s str = strbuild_init(buf, UI_STRBUF_SIZE); size_t planet_name_len = strlen(p->name); BOOLVEC_SET0(p->unrefuel, pi); strbuild_catf(&str, "%s ", game_str_tr_fuel1); if (planet_name_len > 0) { strbuild_append_char(&str, p->name[0]); for (size_t i = 1; i < planet_name_len; i++) { strbuild_append_char(&str, tolower(p->name[i])); } } strbuild_catf(&str, " %s", game_str_tr_fuel2); g->planet_focus_i[pi] = pli; ui_turn_msg(g, pi, buf); } } { bool any_new; any_new = false; for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { if (g->evn.new_ships[pi][si] != 0) { any_new = true; break; } } if (any_new) { ui_newships(g, pi); } for (int si = 0; si < NUM_SHIPDESIGNS; ++si) { g->evn.new_ships[pi][si] = 0; } } } 1oom-1.11.2/src/game/game_turn_start.h000066400000000000000000000003001476061725400175230ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_TURN_START_H #define INC_1OOM_GAME_TURN_START_H #include "game_types.h" struct game_s; extern void game_turn_start_messages(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/game/game_types.h000066400000000000000000000111011476061725400164630ustar00rootroot00000000000000#ifndef INC_1OOM_GAME_TYPES_H #define INC_1OOM_GAME_TYPES_H #include "types.h" typedef enum { PLAYER_0 = 0, PLAYER_1, PLAYER_2, PLAYER_3, PLAYER_4, PLAYER_5, PLAYER_NUM } player_id_t; #define PLAYER_NONE PLAYER_NUM typedef enum tech_group_e { TECH_GROUP_SINGULAR = 0, TECH_GROUP_ECM_JAMMER = 1, TECH_GROUP_BATTLE_COMPUTER = 2, TECH_GROUP_IMPROVED_ROBOTIC_CONTROLS = 3, TECH_GROUP_SPACE_SCANNER = 4, TECH_GROUP_REDUCED_INDUSTRIAL_WASTE = 5, TECH_GROUP_IMPROVED_INDUSTRIAL_TECH = 6, TECH_GROUP_ARMOR = 7, TECH_GROUP_AUTOMATED_REPAIR_SYSTEM = 8, TECH_GROUP_DEFLECTOR_SHIELDS = 9, TECH_GROUP_PLANETARY_SHIELD = 10, TECH_GROUP_ANTI_MISSILE_SHIELD = 11, TECH_GROUP_IMPROVED_TERRAFORMING = 12, TECH_GROUP_CONTROLLED_ENVIRONMENT = 13, TECH_GROUP_ECO_RESTORATION = 14, TECH_GROUP_PERSONAL_ARMOR = 15, TECH_GROUP_PERSONAL_SHIELD = 16, TECH_GROUP_ENGINES = 17, TECH_GROUP_FUEL_CELLS = 18, TECH_GROUP_BEAMS = 19, TECH_GROUP_ROCKETS = 20, TECH_GROUP_PERSONAL_WEAPONS = 21, TECH_GROUP_BOMBS = 22, TECH_GROUP_BIO_WEAPONS = 23, TECH_GROUP_PULSAR = 24, TECH_GROUP_STREAM_PROJECTOR = 25, TECH_GROUP_PENETRATING_BEAMS = 30, /*FIXME is there anything else????*/ TECH_GROUP_UNUSED = 0xff, } tech_group_t; typedef enum tech_field_e { TECH_FIELD_COMPUTER = 0, TECH_FIELD_CONSTRUCTION, /*1*/ TECH_FIELD_FORCE_FIELD, /*2*/ TECH_FIELD_PLANETOLOGY, /*3*/ TECH_FIELD_PROPULSION, /*4*/ TECH_FIELD_WEAPON, /*5*/ TECH_FIELD_NUM } tech_field_t; typedef enum race_e { RACE_HUMAN = 0, RACE_MRRSHAN, /*1*/ RACE_SILICOID, /*2*/ RACE_SAKKRA, /*3*/ RACE_PSILON, /*4*/ RACE_ALKARI, /*5*/ RACE_KLACKON, /*6*/ RACE_BULRATHI, /*7*/ RACE_MEKLAR, /*8*/ RACE_DARLOK, /*9*/ RACE_NUM } race_t; #define RACE_RANDOM RACE_NUM typedef enum banner_e { BANNER_BLUE = 0, BANNER_GREEN, /*1*/ BANNER_PURPLE, /*2*/ BANNER_RED, /*3*/ BANNER_WHITE, /*4*/ BANNER_YELLOW, /*5*/ BANNER_NUM } banner_t; #define BANNER_RANDOM BANNER_NUM typedef enum { GALAXY_SIZE_SMALL = 0, GALAXY_SIZE_MEDIUM, /*1*/ GALAXY_SIZE_LARGE, /*2*/ GALAXY_SIZE_HUGE, /*3*/ GALAXY_SIZE_NUM } galaxy_size_t; typedef enum { DIFFICULTY_SIMPLE = 0, DIFFICULTY_EASY, /*1*/ DIFFICULTY_AVERAGE, /*2*/ DIFFICULTY_HARD, /*3*/ DIFFICULTY_IMPOSSIBLE, /*4*/ DIFFICULTY_NUM } difficulty_t; typedef enum { TREATY_NONE = 0, TREATY_NONAGGRESSION, /*1*/ TREATY_ALLIANCE, /*2*/ TREATY_WAR, /*3*/ TREATY_FINAL_WAR, /*4*/ TREATY_NUM } treaty_t; typedef enum { SPYMODE_HIDE = 0, SPYMODE_ESPIONAGE, /*1*/ SPYMODE_SABOTAGE /*2*/ } spymode_t; typedef enum { TRAIT1_XENOPHOBIC = 0, TRAIT1_RUTHLESS, /*1*/ TRAIT1_AGGRESSIVE, /*2*/ TRAIT1_ERRATIC, /*3*/ TRAIT1_HONORABLE, /*4*/ TRAIT1_PACIFISTIC, /*5*/ TRAIT1_NUM } trait1_t; typedef enum { TRAIT2_DIPLOMAT = 0, TRAIT2_MILITARIST, /*1*/ TRAIT2_EXPANSIONIST, /*2*/ TRAIT2_TECHNOLOGIST, /*3*/ TRAIT2_INDUSTRIALIST, /*4*/ TRAIT2_ECOLOGIST, /*5*/ TRAIT2_NUM } trait2_t; typedef enum { GAME_EVENT_NONE = 0, GAME_EVENT_PLAGUE, /*1*/ GAME_EVENT_QUAKE, /*2*/ GAME_EVENT_NOVA, /*3*/ GAME_EVENT_ACCIDENT, /*4*/ GAME_EVENT_ASSASSIN, /*5*/ GAME_EVENT_VIRUS, /*6*/ GAME_EVENT_COMET, /*7*/ GAME_EVENT_PIRATES, /*8*/ GAME_EVENT_DERELICT, /*9*/ GAME_EVENT_REBELLION, /*10*/ GAME_EVENT_CRYSTAL, /*11*/ GAME_EVENT_AMOEBA, /*12*/ GAME_EVENT_ENVIRO, /*13*/ GAME_EVENT_RICH, /*14*/ GAME_EVENT_SUPPORT, /*15*/ GAME_EVENT_POOR, /*16*/ GAME_EVENT_NUM } gameevent_type_t; typedef enum { MONSTER_CRYSTAL = 0, MONSTER_AMOEBA, /*1*/ MONSTER_GUARDIAN, /*2*/ MONSTER_NUM } monster_id_t; typedef enum game_end_type_e { GAME_END_NONE = 0, GAME_END_LOST_EXILE, /*1*/ GAME_END_WON_GOOD, /*2*/ GAME_END_FINAL_WAR, /*3*/ GAME_END_WON_TYRANT, GAME_END_LOST_FUNERAL, GAME_END_QUIT } game_end_type_t; typedef enum { TECHSOURCE_RESEARCH = 0, TECHSOURCE_SPY, /*1*/ TECHSOURCE_FOUND, /*2*/ TECHSOURCE_AI_SPY, /*3*/ TECHSOURCE_TRADE /*4*/ } techsource_t; #define TECHSOURCE_CHOOSE TECHSOURCE_AI_SPY typedef uint16_t shipcount_t; typedef uint32_t shipsum_t; #define SHIP_NAME_NUM 12 #define NUM_SHIPDESIGNS 6 #define BUILDSHIP_STARGATE NUM_SHIPDESIGNS #define TECH_SPY_MAX 6 #define TECH_NEXT_MAX 12 #define FLEET_ENROUTE_AI_MAX 208 #define FLEET_ENROUTE_MAX 260 #define TRANSPORT_MAX 100 #define PLANETS_MAX 108 #endif 1oom-1.11.2/src/gameapi.h000066400000000000000000000005441476061725400150310ustar00rootroot00000000000000#ifndef INC_1OOM_GAMEAPI_H #define INC_1OOM_GAMEAPI_H #include "cfg.h" #include "types.h" extern const struct cfg_items_s game_cfg_items[]; extern bool game_num_patch(const char *numid, const int32_t *patchnums, int first, int num); extern bool game_str_patch(const char *strid, const char *patchstr, int i); extern void game_apply_rules(void); #endif 1oom-1.11.2/src/gfxaux.c000066400000000000000000000754721476061725400147370ustar00rootroot00000000000000#include "config.h" #include #include "gfxaux.h" #include "comp.h" #include "hw.h" #include "gfxscale.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ static const uint8_t tbl_cloak[0x100] = { 0x2a, 0x44, 0x23, 0x01, 0x46, 0x19, 0x4f, 0x3b, 0x3f, 0x41, 0x06, 0x2e, 0x52, 0x1c, 0x3e, 0x5c, 0x60, 0x2b, 0x1c, 0x25, 0x5c, 0x05, 0x03, 0x36, 0x5d, 0x53, 0x16, 0x11, 0x13, 0x60, 0x30, 0x1b, 0x48, 0x27, 0x46, 0x0d, 0x44, 0x64, 0x24, 0x5f, 0x04, 0x0c, 0x17, 0x22, 0x4a, 0x41, 0x2a, 0x0c, 0x36, 0x45, 0x30, 0x2d, 0x3f, 0x3a, 0x26, 0x3c, 0x18, 0x2a, 0x1e, 0x4f, 0x11, 0x24, 0x5b, 0x2b, 0x59, 0x07, 0x29, 0x2b, 0x41, 0x31, 0x2f, 0x06, 0x5b, 0x1e, 0x47, 0x33, 0x07, 0x02, 0x5e, 0x31, 0x1e, 0x18, 0x55, 0x37, 0x39, 0x29, 0x43, 0x4d, 0x20, 0x09, 0x2d, 0x28, 0x1b, 0x18, 0x26, 0x27, 0x13, 0x53, 0x1e, 0x2a, 0x22, 0x10, 0x28, 0x3b, 0x05, 0x1f, 0x4e, 0x07, 0x4a, 0x57, 0x16, 0x2e, 0x19, 0x49, 0x47, 0x1e, 0x4e, 0x4a, 0x62, 0x0d, 0x57, 0x5b, 0x3e, 0x25, 0x38, 0x44, 0x38, 0x4b, 0x20, 0x35, 0x33, 0x33, 0x2a, 0x19, 0x43, 0x1f, 0x08, 0x5c, 0x08, 0x26, 0x3a, 0x58, 0x36, 0x54, 0x2e, 0x0a, 0x0a, 0x3b, 0x16, 0x59, 0x17, 0x2f, 0x07, 0x1f, 0x0e, 0x45, 0x01, 0x5c, 0x3f, 0x38, 0x0b, 0x3c, 0x19, 0x26, 0x31, 0x54, 0x60, 0x2a, 0x03, 0x33, 0x5c, 0x25, 0x4b, 0x15, 0x61, 0x16, 0x31, 0x64, 0x45, 0x55, 0x52, 0x23, 0x36, 0x64, 0x13, 0x27, 0x01, 0x59, 0x1c, 0x44, 0x1d, 0x5e, 0x31, 0x54, 0x08, 0x16, 0x0b, 0x12, 0x0e, 0x0f, 0x0a, 0x11, 0x24, 0x34, 0x01, 0x32, 0x14, 0x39, 0x63, 0x04, 0x19, 0x09, 0x2d, 0x0a, 0x5a, 0x03, 0x60, 0x56, 0x5e, 0x2c, 0x18, 0x58, 0x0f, 0x04, 0x31, 0x01, 0x3b, 0x13, 0x51, 0x61, 0x63, 0x52, 0x5a, 0x63, 0x0a, 0x3a, 0x49, 0x17, 0x27, 0x5d, 0x27, 0x50, 0x5b, 0x3a, 0x3b, 0x5c, 0x10, 0x59, 0x39, 0x0c, 0x03, 0x23, 0x49, 0x38, 0x1d, 0x2f }; /* -------------------------------------------------------------------------- */ static void gfx_aux_scale_up(struct gfx_aux_s *aux, int xscale, int yscale) { uint8_t *p, *q, *q2; int w = aux->w, h = aux->h, oldw = w, posold = w * h - 1; unsigned int xinc, yinc, yacc = 0; w = (w * xscale) / 100; h = (h * yscale) / 100; if ((w * h) > aux->size) { LOG_DEBUG((1, "%s: realloc aux %ix%i == %i > %i (current %ix%i)\n", __func__, w, h, w * h, aux->size, aux->w, aux->h)); aux->data = lib_realloc(aux->data, w * h); } aux->w = w; aux->h = h; p = &(aux->data[w * h - 1]); q = q2 = &(aux->data[posold]); xinc = (100 << 8) / xscale; yinc = (100 << 8) / yscale; for (int y = 0; y < h; ++y) { unsigned int xacc; xacc = 0; q = q2; for (int x = 0; x < w; ++x) { *p-- = *q; xacc += xinc; q -= (xacc >> 8); xacc &= 0xff; } yacc += yinc; q2 -= (yacc >> 8) * oldw; yacc &= 0xff; } } static void gfx_aux_scale_down(struct gfx_aux_s *aux, int xscale, int yscale) { uint8_t *p = aux->data, *q = p, *q2 = p; int w = aux->w, h = aux->h, oldw = w; unsigned int xinc, yinc, yacc = 0; aux->w = w = (w * xscale) / 100; aux->h = h = (h * yscale) / 100; xinc = (100 << 8) / xscale; yinc = (100 << 8) / yscale; for (int y = 0; y < h; ++y) { unsigned int xacc; xacc = 0; q = q2; for (int x = 0; x < w; ++x) { *p++ = *q; xacc += xinc; q += (xacc >> 8); xacc &= 0xff; } yacc += yinc; q2 += (yacc >> 8) * oldw; yacc &= 0xff; } } static void gfx_aux_overlay_do_normal(uint8_t *dest, const uint8_t *src, int w, int h, int destskipw, int srcskipw) { for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uint8_t c; c = *src++; if (c != 0) { *dest++ = c; } else { ++dest; } } src += srcskipw; dest += destskipw; } } static void gfx_aux_overlay_do_clear(uint8_t *dest, const uint8_t *src, int w, int h, int destskipw, int srcskipw) { for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uint8_t c; c = *src++; if (c == 0) { *dest++ = c; } else { ++dest; } } src += srcskipw; dest += destskipw; } } static void gfx_aux_overlay_do(int x, int y, struct gfx_aux_s *dest, struct gfx_aux_s *src, void (*fptr)(uint8_t *dest, const uint8_t *src, int w, int h, int destskipw, int srcskipw)) { int destw, desth, srcx1, srcy1, xskip, x0, yskip, y0, w, h, destskip0, srcskip0, destskipw, srcskipw; destw = dest->w; if (destw <= x) { return; } desth = dest->h; if (desth <= y) { return; } srcx1 = src->w + x - 1; if (srcx1 < 0) { return; } srcy1 = src->h + y - 1; if (srcy1 < 0) { return; } if (x >= 0) { xskip = 0; x0 = x; } else { xskip = -x; x0 = 0; } if (y >= 0) { yskip = 0; y0 = y; } else { yskip = -y; y0 = 0; } if ((destw - 1) > srcx1) { w = srcx1 - x0 + 1; } else { w = destw - 1 - x0 + 1; } SETMIN(w, destw); if ((desth - 1) > srcy1) { h = srcy1 - y0 + 1; } else { h = desth - 1 - y0 + 1; } SETMIN(h, desth); destskip0 = destw * y0 + x0; destskipw = destw - w; srcskip0 = src->h * yskip + xskip; srcskipw = src->w - w; fptr(&(dest->data[destskip0]), &(src->data[srcskip0]), w, h, destskipw, srcskipw); } static inline void gfx_aux_draw_frame_1x(const uint8_t *q, uint8_t *p, int w, int h, uint16_t pitch_aux, uint16_t pitch_hw) { for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uint8_t b = q[x]; if (b) { p[x] = b; } } p += pitch_hw; q += pitch_aux; } } static inline void gfx_aux_draw_frame_nx(const uint8_t *q, uint8_t *p, int w, int h, uint16_t pitch_aux, uint16_t pitch_hw, int scale) { for (int y = 0; y < h; ++y) { uint8_t *o; o = p; for (int x = 0; x < w; ++x) { uint8_t b = q[x]; if (b) { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { o[sx + sy * pitch_hw] = b; } } } o += scale; } p += pitch_hw * scale; q += pitch_aux; } } static void gfx_aux_draw_frame_from_limit_do(int x, int y, int w, int h, int xskip, int yskip, struct gfx_aux_s *aux, uint16_t pitch_hw, int scale) { uint8_t *p, *q; uint16_t pitch_aux = aux->w; p = hw_video_get_buf() + (y * pitch_hw + x) * scale; q = aux->data + yskip * pitch_aux + xskip; if (scale == 1) { gfx_aux_draw_frame_1x(q, p, w, h, pitch_aux, pitch_hw); } else { gfx_aux_draw_frame_nx(q, p, w, h, pitch_aux, pitch_hw, scale); } } /* FIXME MOO1 stores the aux gfx in columnwise order. The rotate functions below currently do the same. This results in the following ugly hack: b = gfx[(j % r->srch) * r->srcw + (j / r->srch)]; This can be optimized to "b = *q" when the rotation is rewritten to regular pixel order. */ #define DEBUGLEVEL_ROTATE 5 struct rotate_param_s { int destx; int desty; int w; int h; int hfrac; int destxstep; int destxfrac; int destxadd; int srcstart; /*srcdataseg*/ int srcxstep; int srcxfrac2; int srcxadd2; int srcxfrac1; int srcxadd1; int srcystep; int srcyfrac2; int srcyadd2; int srcyfrac1; int srcyadd1; int destxskip; int destmin; int destmax; /* only needed for columnwise -> regular */ int srcw; int srch; }; static void gfx_aux_draw_rotate_sub1(struct rotate_param_s *r, const uint8_t *gfx, uint16_t pitch_hw, int scale) { int destxskip = r->destxskip, edest = 0x80, ex1 = 0x80, ex2 = 0x80, hx100 = r->h * 0x100, w = r->w, di, si; int sw = r->srcw, sh = r->srch; uint8_t *dest; dest = hw_video_get_buf(); di = (r->desty * pitch_hw + r->destx) * scale; si = r->srcstart; LOG_DEBUG((DEBUGLEVEL_ROTATE, "r: hf:%i S:%i d:%i,%i,0x%x s:%i y:%i,%i,0x%x,%i,0x%x x:%i,%i,0x%x,%i,0x%x\n", r->hfrac, r->destxskip, r->destxstep, r->destxadd, r->destxfrac, r->srcstart, r->srcystep, r->srcyadd1, r->srcyfrac1, r->srcyadd2, r->srcyfrac2, r->srcxstep, r->srcxadd1, r->srcxfrac1, r->srcxadd2, r->srcxfrac2)); while (1) { if (destxskip < 0) { int loops, esy1, esy2, i, j; loops = hx100 / 0x100; i = di; j = si; esy1 = esy2 = 0; do { uint8_t b; b = gfx[(j % sh) * sw + (j / sh)]; /* FIXME HACK columnwise -> regular */ if (b != 0) { for (int y = 0; y < scale; ++y) { for (int x = 0; x < scale; ++x) { int xi; xi = i + x; if ((xi >= r->destmin) && (xi < r->destmax)) { dest[xi] = b; } } i += pitch_hw; } } else { i += pitch_hw * scale; } j += r->srcystep; if ((esy1 += r->srcyfrac1) >= 0x100) { esy1 &= 0xff; j += r->srcyadd1; } if ((esy2 += r->srcyfrac2) >= 0x100) { esy2 &= 0xff; j += r->srcyadd2; } } while (--loops); } --destxskip; if (--w <= 0) { break; } di += (r->destxstep + 1 ) * scale; if ((edest += r->destxfrac) >= 0x100) { edest &= 0xff; di += r->destxadd * scale; } hx100 += r->hfrac; si += r->srcxstep; if ((ex1 += r->srcxfrac1) >= 0x100) { ex1 &= 0xff; si += r->srcxadd1; } if ((ex2 += r->srcxfrac2) >= 0x100) { ex2 &= 0xff; si += r->srcxadd2; } } } static void gfx_aux_draw_frame_from_rotate_limit_do(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, struct gfx_aux_s *aux, int lx0, int ly0, int lx1, int ly1, uint16_t pitch_hw, int scale) { struct rotate_param_s r; int tx[4] = { x0, x1, x2, x3 }; int ty[4] = { y0, y1, y2, y3 }; int ti[4] = { 1, 2, 3, 4 }; int maxy = 0, miny = 10000; /* WASBUG initial values made the following SET* ineffective */ int w = aux->w, h = aux->h; for (int i = 0; i < 4; ++i) { SETMIN(miny, ty[i]); SETMAX(maxy, ty[i]); for (int j = 0; j < 3; ++j) { int t; t = tx[j]; if (t > tx[j + 1]) { tx[j] = tx[j + 1]; tx[j + 1] = t; t = ty[j]; ty[j] = ty[j + 1]; ty[j + 1] = t; t = ti[j]; ti[j] = ti[j + 1]; ti[j + 1] = t; } } } if ((tx[0] > lx1) || (tx[3] < lx0) || (miny > ly1) || (maxy < ly0)) { return; } memset(&r, 0, sizeof(r)); r.srcw = aux->w; r.srch = aux->h; r.destmin = lx0 * pitch_hw * scale; r.destmax = (lx1 + 1) * pitch_hw * scale; if (tx[0] == tx[1]) { if (ty[0] > ty[1]) { int t; t = ty[0]; ty[0] = ty[1]; ty[1] = t; t = ti[0]; ti[0] = ti[1]; ti[1] = t; } LOG_DEBUG((DEBUGLEVEL_ROTATE, "%s: case %i y1:%i y2:%i -> %i\n", __func__, ti[0], ty[1], ty[2], ty[1] < ty[2])); r.destx = tx[0]; r.desty = ty[0]; r.h = ty[1] - ty[0] + 1; r.w = tx[2] - tx[0] + 1; switch (ti[0]) { default: case 1: r.srcstart = 0; r.srcyadd2 = 1; r.srcxadd1 = h; r.srcxfrac1 = (w << 8) / r.w; r.srcyfrac2 = (h << 8) / r.h; break; case 2: r.srcstart = (w - 1) * h; r.srcyadd2 = -h; r.srcxadd1 = 1; r.srcxfrac1 = (h << 8) / r.w; r.srcyfrac2 = (w << 8) / r.h; break; case 3: r.srcstart = w * h - 1; r.srcyadd2 = -1; r.srcxadd1 = -h; r.srcxfrac1 = (w << 8) / r.w; r.srcyfrac2 = (h << 8) / r.h; break; case 4: r.srcstart = h - 1; r.srcyadd2 = h; r.srcxadd1 = -1; r.srcxfrac1 = (h << 8) / r.w; r.srcyfrac2 = (w << 8) / r.h; break; } r.srcxstep = 0; if (r.srcxfrac1 >= 0x100) { r.srcxstep = (r.srcxfrac1 / 0x100) * r.srcxadd1; r.srcxfrac1 = r.srcxfrac1 % 0x100; } r.srcystep = 0; if (r.srcyfrac2 >= 0x100) { r.srcystep = (r.srcyfrac2 / 0x100) * r.srcyadd2; r.srcyfrac2 = r.srcyfrac2 % 0x100; } if ((tx[2] < lx0) || (tx[0] > lx1)) { return; } r.destxskip = lx0 - tx[0] - 1; if (lx1 < tx[2]) { r.w = lx1 - tx[0] + 1; } r.srcxadd2 = r.srcyadd2; r.srcyadd1 = r.srcxadd1; gfx_aux_draw_rotate_sub1(&r, aux->data, pitch_hw, scale); } else { int v4a; LOG_DEBUG((DEBUGLEVEL_ROTATE, "%s: case %i y1:%i y2:%i -> %i\n", __func__, ti[0], ty[1], ty[2], ty[1] < ty[2])); r.destx = tx[0]; r.desty = ty[0]; r.w = tx[1] - tx[0] + 1; if (ty[1] < ty[0]) { v4a = ((ty[2] - ty[0]) * (tx[1] - tx[0])) / (tx[2] - tx[0]) + ty[0] - ty[1] + 1; } else { v4a = ((ty[0] - ty[2]) * (tx[1] - tx[0])) / (tx[2] - tx[0]) + ty[1] - ty[0] + 1; } r.h = 1; r.hfrac = ((v4a - r.h) << 8) / (r.w - 1); r.destxadd = -pitch_hw; if (ty[1] < ty[2]) { r.destxfrac = ((ty[0] - ty[1]) << 8) / (tx[1] - tx[0]); } else { r.destxfrac = ((ty[0] - ty[2]) << 8) / (tx[2] - tx[0]); } if (r.destxfrac >= 0x100) { r.destxstep = (r.destxfrac / 0x100) * -pitch_hw; r.destxfrac = r.destxfrac % 0x100; } else { r.destxstep = 0; } if ((ti[0] == 1) || (ti[0] == 3)) { if (ty[1] < ty[2]) { /*21e55*/ r.srcyfrac1 = ((w - 1) << 8) / (v4a - 1); r.srcyfrac2 = (((tx[1] - tx[0]) * ((h - 1) << 8)) / (v4a - 1)) / (tx[2] - tx[0]); } else { /*21ead*/ r.srcyfrac1 = (((tx[1] - tx[0]) * ((w - 1) << 8)) / (v4a - 1)) / (tx[2] - tx[0]); r.srcyfrac2 = ((h - 1) << 8) / (v4a - 1); } } else { /*21f10*/ if (ty[1] < ty[2]) { r.srcyfrac1 = (((tx[3] - tx[2]) * ((w - 1) << 8)) / (v4a - 1)) / (tx[3] - tx[1]); r.srcyfrac2 = ((h - 1) << 8) / (v4a - 1); } else { r.srcyfrac1 = ((w - 1) << 8) / (v4a - 1); r.srcyfrac2 = (((tx[1] - tx[0]) * ((h - 1) << 8)) / (v4a - 1)) / (tx[2] - tx[0]); } } /*21fd0*/ switch (ti[0]) { default: case 1: r.srcstart = 0; r.srcxadd2 = 1; r.srcxadd1 = h; r.srcyadd2 = 1; r.srcyadd1 = -h; r.srcxfrac2 = 0; r.srcxfrac1 = ((w - 1) << 8) / (((ty[1] < ty[2]) ? tx[1] : tx[2]) - tx[0]); break; case 2: r.srcstart = (w - 1) * h; r.srcxadd2 = 1; r.srcxadd1 = -h; r.srcyadd2 = -1; r.srcyadd1 = -h; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (((ty[1] < ty[2]) ? tx[1] : tx[2]) - tx[0]); break; case 3: r.srcstart = w * h - 1; r.srcxadd2 = -1; r.srcxadd1 = -h; r.srcyadd2 = -1; r.srcyadd1 = h; r.srcxfrac2 = 0; r.srcxfrac1 = ((w - 1) << 8) / (((ty[1] < ty[2]) ? tx[1] : tx[2]) - tx[0]); break; case 4: r.srcstart = h - 1; r.srcxadd2 = -1; r.srcxadd1 = h; r.srcyadd2 = 1; r.srcyadd1 = h; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (((ty[1] < ty[2]) ? tx[1] : tx[2]) - tx[0]); break; } r.srcxstep = 0; if (r.srcxfrac2 >= 0x100) { r.srcxstep = (r.srcxfrac2 / 0x100) * r.srcxadd2; r.srcxfrac2 = r.srcxfrac2 % 0x100; } if (r.srcxfrac1 >= 0x100) { r.srcxstep += (r.srcxfrac1 / 0x100) * r.srcxadd1; r.srcxfrac1 = r.srcxfrac1 % 0x100; } r.srcystep = 0; if (r.srcyfrac2 >= 0x100) { r.srcystep = (r.srcyfrac2 / 0x100) * r.srcyadd2; r.srcyfrac2 = r.srcyfrac2 % 0x100; } if (r.srcyfrac1 >= 0x100) { r.srcystep += (r.srcyfrac1 / 0x100) * r.srcyadd1; r.srcyfrac1 = r.srcyfrac1 % 0x100; } if ((tx[1] >= lx0) && (tx[0] <= lx1)) { r.destxskip = lx0 - tx[0] - 1; if (lx1 < tx[1]) { r.w = lx1 - tx[0] + 1; } gfx_aux_draw_rotate_sub1(&r, aux->data, pitch_hw, scale); } /*22297*/ r.destx = tx[1]; r.w = tx[2] - tx[1] + 1; r.h = v4a; r.hfrac = 0; if (ty[1] < ty[2]) { r.desty = ty[1]; r.destxadd = pitch_hw; r.destxfrac = ((ty[3] - ty[1]) << 8) / (tx[3] - tx[1]); if (r.destxfrac >= 0x100) { r.destxstep = (r.destxfrac / 0x100) * pitch_hw; r.destxfrac = r.destxfrac % 0x100; } else { r.destxstep = 0; } } else { /*22309*/ r.desty = ty[0] - ((ty[0] - ty[2]) * (tx[1] - tx[0])) / (tx[2] - tx[0]); } /*22329*/ switch (ti[0]) { default: case 1: if (ty[1] < ty[2]) { r.srcstart = (w - 1) * h; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (tx[3] - tx[1]); } else { r.srcstart = h * ((((w - 1) * (tx[1] - tx[0])) / (tx[2] - tx[0]))); } break; case 2: if (ty[1] < ty[2]) { r.srcstart = w * h - 1; r.srcxfrac1 = ((w - 1) << 8) / (tx[3] - tx[1]); r.srcxfrac2 = 0; } else { r.srcstart = (w - 1) * h + (((h - 1) * (tx[1] - tx[0])) / (tx[2] - tx[0])); } break; case 3: if (ty[1] < ty[2]) { r.srcstart = h - 1; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (tx[3] - tx[1]); } else { r.srcstart = w * h - 1 - h * (((w - 1) * (tx[1] - tx[0])) / (tx[2] - tx[0])); } break; case 4: if (ty[1] < ty[2]) { r.srcstart = 0; r.srcxfrac1 = ((w - 1) << 8) / (tx[3] - tx[1]); r.srcxfrac2 = 0; } else { r.srcstart = h - 1 - (((h - 1) * (tx[1] - tx[0])) / (tx[2] - tx[0])); } break; } /*224a0*/ if (ty[1] < ty[2]) { r.srcxstep = 0; if (r.srcxfrac2 >= 0x100) { r.srcxstep = (r.srcxfrac2 / 0x100) * r.srcxadd2; r.srcxfrac2 = r.srcxfrac2 % 0x100; } if (r.srcxfrac1 >= 0x100) { r.srcxstep += (r.srcxfrac1 / 0x100) * r.srcxadd1; r.srcxfrac1 = r.srcxfrac1 % 0x100; } } /*224ed*/ if ((tx[2] >= lx0) && (tx[1] <= lx1)) { r.destxskip = lx0 - tx[1] - 1; if (lx1 < tx[2]) { r.w = lx1 - tx[1] + 1; } gfx_aux_draw_rotate_sub1(&r, aux->data, pitch_hw, scale); } /*225da*/ r.destx = tx[2]; r.w = tx[3] - tx[2] + 1; r.hfrac = -(((v4a - 1) << 8) / (r.w - 1)); if (ty[1] < ty[2]) { r.desty = ty[3] - ((ty[3] - ty[1]) * (tx[3] - tx[2])) / (tx[3] - tx[1]); } else { r.desty = ty[2]; r.destxadd = pitch_hw; r.destxfrac = ((ty[3] - ty[2]) << 8) / (tx[3] - tx[2]); if (r.destxfrac >= 0x100) { r.destxstep = (r.destxfrac / 0x100) * pitch_hw; r.destxfrac = r.destxfrac % 0x100; } else { r.destxstep = 0; } } /*22676*/ switch (ti[0]) { default: case 1: if (ty[1] < ty[2]) { r.srcstart = (w - 1) * h + (((h - 1) * (tx[2] - tx[1])) / (tx[3] - tx[1])); } else { r.srcstart = (w - 1) * h; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (tx[3] - tx[2]); } break; case 2: if (ty[1] < ty[2]) { r.srcstart = (w * h - 1) - h * (((w - 1) * (tx[2] - tx[1])) / (tx[3] - tx[1])); } else { r.srcstart = w * h - 1; r.srcxfrac1 = ((w - 1) << 8) / (tx[3] - tx[2]); r.srcxfrac2 = 0; } break; case 3: if (ty[1] < ty[2]) { r.srcstart = h - 1 - (((h - 1) * (tx[2] - tx[1])) / (tx[3] - tx[1])); } else { r.srcstart = h - 1; r.srcxfrac1 = 0; r.srcxfrac2 = ((h - 1) << 8) / (tx[3] - tx[2]); } break; case 4: if (ty[1] < ty[2]) { r.srcstart = h * (((w - 1) * (tx[2] - tx[1])) / (tx[3] - tx[1])); } else { r.srcstart = 0; r.srcxfrac1 = ((w - 1) << 8) / (tx[3] - tx[2]); r.srcxfrac2 = 0; } break; } /*227ed*/ if (ty[1] >= ty[2]) { r.srcxstep = 0; if (r.srcxfrac2 >= 0x100) { r.srcxstep = (r.srcxfrac2 / 0x100) * r.srcxadd2; r.srcxfrac2 = r.srcxfrac2 % 0x100; } if (r.srcxfrac1 >= 0x100) { r.srcxstep += (r.srcxfrac1 / 0x100) * r.srcxadd1; r.srcxfrac1 = r.srcxfrac1 % 0x100; } } /*2283a*/ if ((tx[3] >= lx0) && (tx[2] <= lx1)) { r.destxskip = lx0 - tx[2] - 1; if (lx1 < tx[3]) { r.w = lx1 - tx[2] + 1; } gfx_aux_draw_rotate_sub1(&r, aux->data, pitch_hw, scale); } } } static void gfx_aux_make_paltbl(const struct gfx_aux_s *aux, uint8_t *tbl) { const uint8_t *p = aux->data, *q = lbxpal_palette;; int len = aux->w * aux->h; memset(tbl, 0xff, 0x100); for (int i = 0; i < len; ++i) { uint8_t c; c = *p++; if (c) { tbl[c] = 0; } } /* FIXME only != 0xff tested in callers */ for (int i = 0; i < 0x100; ++i, q += 3) { if (tbl[i] != 0xff) { tbl[i] = q[0] + q[1] + q[2] / 2; } } } /* -------------------------------------------------------------------------- */ void gfx_aux_setup_wh(struct gfx_aux_s *aux, int w, int h) { int size = w * h; aux->w = w; aux->h = h; if (size > aux->size) { lib_free(aux->data); aux->data = lib_malloc(size); aux->size = size; } else { memset(aux->data, 0, size); } aux->frame = 0; } void gfx_aux_setup(struct gfx_aux_s *aux, const uint8_t *data, int frame) { int w = lbxgfx_get_w(data); int h = lbxgfx_get_h(data); gfx_aux_setup_wh(aux, w, h); aux->frame = frame; } void gfx_aux_free(struct gfx_aux_s *aux) { if (aux) { if (aux->data) { lib_free(aux->data); aux->data = 0; aux->size = 0; } } } void gfx_aux_flipx(struct gfx_aux_s *aux) { uint8_t *p = aux->data; int w = aux->w; for (int y = 0; y < aux->h; ++y) { for (int x = 0; x < (w / 2); ++x) { uint8_t t; t = p[x]; p[x] = p[w - 1 - x]; p[w - 1 - x] = t; } p += w; } } void gfx_aux_scale(struct gfx_aux_s *aux, int xscale, int yscale) { int w = aux->w, h = aux->h; if ((xscale <= 0) || (yscale <= 0) || (((w * xscale) / 100) < 1) || (((h * yscale) / 100) < 1)) { gfx_aux_setup_wh(aux, w, h); } else { int xs = xscale, ys = yscale; if ((xs < 100) && (ys > 100)) { xs = 100; } if ((xs > 100) && (ys < 100)) { ys = 100; } if ((xs > 100) || (ys > 100)) { gfx_aux_scale_up(aux, xs, ys); } xs = MIN(xscale, 100); ys = MIN(yscale, 100); if ((xs < 100) || (ys < 100)) { gfx_aux_scale_down(aux, xs, ys); } } } void gfx_aux_color_replace(struct gfx_aux_s *aux, uint8_t from, uint8_t to) { uint8_t *p = aux->data; int len = aux->w * aux->h; for (int i = 0; i < len; ++i, ++p) { if (*p == from) { *p = to; } } } void gfx_aux_color_non0(struct gfx_aux_s *aux, uint8_t color) { uint8_t *p = aux->data; int len = aux->w * aux->h; for (int i = 0; i < len; ++i, ++p) { if (*p != 0) { *p = color; } } } void gfx_aux_recolor_ctbl(struct gfx_aux_s *aux, const uint8_t *ctbl, int ctbllen) { uint8_t paltbl[0x100], cmax = 0, cmin = 0xff, crange; if (ctbllen <= 0) { return; } gfx_aux_make_paltbl(aux, paltbl); for (int i = 0; i < 0x100; ++i) { uint8_t c; c = paltbl[i]; if (c != 0xff) { SETMIN(cmin, c); SETMAX(cmax, c); } } crange = cmax - cmin; if (crange != 0) { for (int i = 0; i < 0x100; ++i) { /* FIXME only the range */ uint8_t c; c = paltbl[i]; if (c != 0xff) { int v; v = c + (crange / ctbllen) / 2 - cmin; v = (v * (ctbllen - 1)) / crange; if ((v >= 0) && (v < ctbllen)) { paltbl[i] = ctbl[v]; } else { paltbl[i] = 0xff; } } } } else { /*2336d*/ for (int i = 0; i < 0x100; ++i) { /* FIXME only the range */ if (paltbl[i] != 0xff) { paltbl[i] = ctbl[0]; } } } /*23385*/ for (int i = 0; i < 0x100; ++i) { /* FIXME only the range */ uint8_t c; c = paltbl[i]; if (c != 0xff) { gfx_aux_color_replace(aux, i, c); } } } void gfx_aux_overlay(int x, int y, struct gfx_aux_s *dest, struct gfx_aux_s *src) { gfx_aux_overlay_do(x, y, dest, src, gfx_aux_overlay_do_normal); } void gfx_aux_overlay_clear_unused(int x, int y, struct gfx_aux_s *dest, struct gfx_aux_s *src) { gfx_aux_overlay_do(x, y, dest, src, gfx_aux_overlay_do_clear); } void gfx_aux_copy(struct gfx_aux_s *dest, struct gfx_aux_s *src) { int w = src->w, h = src->h; int size = w * h; if (size > dest->size) { lib_free(dest->data); dest->data = lib_malloc(size); dest->size = size; } dest->w = w; dest->h = h; dest->frame = src->frame; memcpy(dest->data, src->data, size); } void gfx_aux_draw_cloak(struct gfx_aux_s *aux, uint8_t percent, uint16_t rndv) { uint8_t pos, v; for (int y = 0; y < aux->h; ++y) { rndv = rnd_bitfiddle(rndv); pos = (rndv >> 8) & 0xff; for (int x = 0; x < aux->w; ++x) { v = tbl_cloak[pos++]; if (v > percent) { aux->data[y * aux->w + x] = 0; } } } } void gfx_aux_draw_frame_to(uint8_t *data, struct gfx_aux_s *aux) { uint16_t f, frame; frame = lbxgfx_get_frame(data); if (lbxgfx_get_indep(data)) { f = frame; } else { f = 0; lbxgfx_set_frame_0(data); } if (f == 0) { lbxgfx_apply_palette(data); } gfx_aux_setup(aux, data, frame); for (; f <= frame; ++f) { lbxgfx_draw_frame_do(aux->data, data, aux->w, 1); } } void gfx_aux_draw_frame_from(int x, int y, struct gfx_aux_s *aux, uint16_t pitch, int scale) { uint8_t *p, *q; p = hw_video_get_buf() + (y * pitch + x) * scale; q = aux->data; if (scale == 1) { gfx_aux_draw_frame_1x(q, p, aux->w, aux->h, aux->w, pitch); } else { gfx_aux_draw_frame_nx(q, p, aux->w, aux->h, aux->w, pitch, scale); } } void gfx_aux_draw_frame_from_limit(int x, int y, struct gfx_aux_s *aux, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { int xskip, yskip, x0, y0, x1, y1, w, h; if ((x > lx1) || (y > ly1)) { return; } x1 = x + aux->w - 1; if (x1 < lx0) { return; } y1 = y + aux->h - 1; if (y1 < ly0) { return; } if (x >= lx0) { xskip = 0; x0 = x; } else { xskip = lx0 - x; x0 = lx0; } if (y >= ly0) { yskip = 0; y0 = y; } else { yskip = ly0 - y; y0 = ly0; } w = ((x1 < lx1) ? x1 : lx1) - x0 + 1; h = ((y1 < ly1) ? y1 : ly1) - y0 + 1; gfx_aux_draw_frame_from_limit_do(x0, y0, w, h, xskip, yskip, aux, pitch, scale); } void gfx_aux_draw_frame_from_rotate_limit(int x0, int y0, int x1, int y1, struct gfx_aux_s *aux, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { int h = aux->h, angle, angle2, x2, y2, x3, y3, xo, yo, v; angle = util_math_calc_angle(x1 - x0, y1 - y0); angle2 = 90 - angle; if (angle2 < 0) { angle2 += 360; } xo = util_math_angle_dist_cos(angle2, h) / 2; yo = util_math_angle_dist_sin(angle2, h) / 2; LOG_DEBUG((DEBUGLEVEL_ROTATE, "%s:o %i,%i %i,%i %i,%i %i,%i\n", __func__, x0, y0, x1, y1, xo, yo, angle, angle2)); x0 += xo; y0 -= yo; x1 += xo; y1 -= yo; v = util_math_angle_dist_sin(angle, h * 12) / 10; x2 = x1 - v; x3 = x0 - v; v = util_math_angle_dist_cos(angle, h); y2 = y1 + v; y3 = y0 + v; LOG_DEBUG((DEBUGLEVEL_ROTATE, "%s:t %i,%i %i,%i %i,%i %i,%i\n", __func__, x0, y0, x1, y1, x2, y2, x3, y3)); gfx_aux_draw_frame_from_rotate_limit_do(x0, y0, x1, y1, x2, y2, x3, y3, aux, lx0, ly0, lx1, ly1, pitch, scale); } 1oom-1.11.2/src/gfxaux.h000066400000000000000000000030531476061725400147260ustar00rootroot00000000000000#ifndef INC_1OOM_GFXAUX_H #define INC_1OOM_GFXAUX_H #include "types.h" struct gfx_aux_s { int w; int h; int frame; int size; uint8_t *data; }; extern void gfx_aux_setup_wh(struct gfx_aux_s *aux, int w, int h); extern void gfx_aux_setup(struct gfx_aux_s *aux, const uint8_t *data, int frame); extern void gfx_aux_free(struct gfx_aux_s *aux); extern void gfx_aux_flipx(struct gfx_aux_s *aux); extern void gfx_aux_scale(struct gfx_aux_s *aux, int xscale, int yscale); extern void gfx_aux_color_replace(struct gfx_aux_s *aux, uint8_t from, uint8_t to); extern void gfx_aux_color_non0(struct gfx_aux_s *aux, uint8_t color); extern void gfx_aux_recolor_ctbl(struct gfx_aux_s *aux, const uint8_t *ctbl, int ctbllen); extern void gfx_aux_overlay(int x, int y, struct gfx_aux_s *dest, struct gfx_aux_s *src); extern void gfx_aux_overlay_clear_unused(int x, int y, struct gfx_aux_s *dest, struct gfx_aux_s *src); extern void gfx_aux_copy(struct gfx_aux_s *dest, struct gfx_aux_s *src); extern void gfx_aux_draw_cloak(struct gfx_aux_s *aux, uint8_t percent, uint16_t rndv); extern void gfx_aux_draw_frame_to(uint8_t *data, struct gfx_aux_s *aux); extern void gfx_aux_draw_frame_from(int x, int y, struct gfx_aux_s *aux, uint16_t pitch, int scale); extern void gfx_aux_draw_frame_from_limit(int x, int y, struct gfx_aux_s *aux, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); extern void gfx_aux_draw_frame_from_rotate_limit(int x0, int y0, int x1, int y1, struct gfx_aux_s *aux, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); #endif 1oom-1.11.2/src/gfxconv.c000066400000000000000000000312411476061725400150710ustar00rootroot00000000000000#include "config.h" #include #include #include #include "bits.h" #include "fmt_pic.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #ifdef FEATURE_MODEBUG int opt_modebug = 0; #endif /* -------------------------------------------------------------------------- */ struct picanim_s { struct pic_s pic; const char *filename; uint8_t *buf; int len, alloc; }; struct animopts_s { bool fmt1; bool indep; int num_frames; int loop_frame; int extra_start_frame; int pal_first; int pal_num; }; /* -------------------------------------------------------------------------- */ static void gfx_pa_add_more(struct picanim_s *pa, int len) { if (pa->alloc < (pa->len + len)) { int newlen = ((pa->len + len) | 0xfff) + 1; pa->buf = lib_realloc(pa->buf, newlen); } } static void gfx_pa_add_buf(struct picanim_s *pa, const uint8_t *buf, int len) { gfx_pa_add_more(pa, len); memcpy(&(pa->buf[pa->len]), buf, len); pa->len += len; } static void gfx_pa_add_byte(struct picanim_s *pa, uint8_t b) { gfx_pa_add_more(pa, 1); pa->buf[pa->len++] = b; } static int gfx_convert(const char *filename_out, const char **filenames_in, int num_in, struct animopts_s *opts) { struct picanim_s *picanim = lib_malloc(sizeof(struct picanim_s) * opts->num_frames); uint8_t *bufdiff = NULL; uint8_t *hdr = NULL; FILE *fd = NULL; int res = 1, w = 1, h = 1, hdrlen; for (int frame = 0; frame < num_in; ++frame) { struct picanim_s *pa = &(picanim[frame]); pa->filename = filenames_in[frame]; if (!fmt_pic_load(pa->filename, &(pa->pic))) { goto fail; } if (frame == 0) { w = pa->pic.w; h = pa->pic.h; } else if ((pa->pic.w != w) || (pa->pic.h != h)) { log_error("size mismatch in '%s' (%ix%i != %ix%i) '%s'\n", pa->filename, pa->pic.w, picanim[frame].pic.h, w, h, picanim[0].filename); goto fail; } } for (int frame = num_in; frame < opts->num_frames; ++frame) { struct picanim_s *pa = &(picanim[frame]); pa->filename = "(none)"; } bufdiff = lib_malloc(w * h); for (int frame = 0; frame < opts->num_frames; ++frame) { struct picanim_s *pa = &(picanim[frame]); if ((frame == 0) || (opts->indep) || (frame == opts->extra_start_frame)) { for (int i = 0; i < (w * h); ++i) { bufdiff[i] = (pa->pic.pix[i] != 0); } gfx_pa_add_byte(pa, 1); } else if (frame >= num_in) { memset(bufdiff, 0, w * h); gfx_pa_add_byte(pa, 0); } else { for (int i = 0; i < (w * h); ++i) { bufdiff[i] = (picanim[frame - 1].pic.pix[i] != pa->pic.pix[i]); } gfx_pa_add_byte(pa, 0); } for (int x = 0; x < w; ++x) { uint8_t colbufu[256]; uint8_t colbufc[512]; uint8_t *pc, *pu; int y, lenc, lenu; pu = colbufu; pc = colbufc; y = lenc = lenu = 0; *pu = 0x00; pu += 2; *pc = 0x80; pc += 2; while (y < h) { int skiplen; skiplen = 0; while ((y < h) && (bufdiff[y * w + x] == 0)) { ++skiplen; ++y; } if (y == h) { if (lenu == 0) { colbufu[0] = 0xff; colbufc[0] = 0xff; lenu = 1; lenc = 1; } } else { int rlen; rlen = 1; while (((y + rlen) < h) && (bufdiff[(y + rlen) * w + x] != 0)) { ++rlen; } /* uncompressed */ if ((lenu + rlen + 2) < 256) { *pu++ = rlen; *pu++ = skiplen; for (int i = 0; i < rlen; ++i) { *pu++ = pa->pic.pix[(y + i) * w + x]; } lenu += rlen + 2; } else { lenu = 512; } /* compressed */ if (lenc < 255) { uint8_t *p; int clen; pc[1] = skiplen; p = pc + 2; clen = 0; for (int i = 0; i < rlen;) { uint8_t n, c; n = 1; c = pa->pic.pix[(y + i) * w + x]; while ((n < 0x20) && ((i + n) < rlen) && (c == pa->pic.pix[(y + i + n) * w + x])) { ++n; } if ((n > 1) || (c > 0xdf)) { *p++ = n + 0xdf; ++clen; } *p++ = c; ++clen; i += n; } pc[0] = clen; lenc += clen + 2; pc += clen + 2; } else { lenc = 512; } y += rlen; } } if ((lenc > 255) && (lenu > 255)) { log_error("column %i in '%s' encoded is too long (h %i, un %i, compr %i)\n", x, pa->filename, h, lenu, lenc); goto fail; } colbufu[1] = lenu; colbufc[1] = lenc; if (lenc || lenu) { const uint8_t *b; int l; if (lenc < lenu) { l = lenc; b = colbufc; } else { l = lenu; b = colbufu; } if (l > 1) { l += 2; } gfx_pa_add_buf(pa, b, l); } } } { int paloffs = 0, offs; hdrlen = 0x12 + 4 * (opts->num_frames + 1); if (opts->pal_num) { paloffs = hdrlen; hdrlen += 8 + 3 * opts->pal_num; } hdr = lib_malloc(hdrlen); SET_LE_16(&(hdr[0]), w); SET_LE_16(&(hdr[2]), h); SET_LE_16(&(hdr[6]), opts->num_frames); { int loop_frame = opts->loop_frame; if (loop_frame >= opts->num_frames) { loop_frame = opts->num_frames; } SET_LE_16(&(hdr[8]), loop_frame); } SET_LE_16(&(hdr[0xe]), paloffs); hdr[0x10] = opts->indep ? 1 : 0; hdr[0x11] = opts->fmt1 ? 1 : 0; offs = hdrlen; for (int frame = 0; frame < opts->num_frames; ++frame) { SET_LE_32(&(hdr[0x12 + 4 * frame]), offs); offs += picanim[frame].len; } SET_LE_32(&(hdr[0x12 + 4 * opts->num_frames]), offs); if (opts->pal_num) { SET_LE_16(&(hdr[paloffs + 0]), paloffs + 8); SET_LE_16(&(hdr[paloffs + 2]), opts->pal_first); SET_LE_16(&(hdr[paloffs + 4]), opts->pal_num); memcpy(&(hdr[paloffs + 8]), &(picanim[0].pic.pal[opts->pal_first * 3]), opts->pal_num * 3); } } fd = fopen(filename_out, "wb"); if (0 || (!fd) || (fwrite(hdr, hdrlen, 1, fd) != 1) ) { log_error("creating file '%s'\n", filename_out); goto fail; } for (int frame = 0; frame < opts->num_frames; ++frame) { struct picanim_s *pa = &(picanim[frame]); if (fwrite(pa->buf, pa->len, 1, fd) != 1) { log_error("writing file '%s'\n", filename_out); goto fail; } } res = 0; fail: if (fd) { fclose(fd); fd = NULL; } for (int frame = 0; frame < opts->num_frames; ++frame) { fmt_pic_free(&(picanim[frame].pic)); lib_free(picanim[frame].buf); picanim[frame].buf = NULL; } lib_free(picanim); picanim = NULL; lib_free(bufdiff); bufdiff = NULL; lib_free(hdr); hdr = NULL; return res; } static int gfx_dump(const char *filename) { uint8_t *data, *p; int frames, w, h; uint32_t len; p = data = util_file_load(filename, &len); if (!data) { return 1; } w = lbxgfx_get_w(p); h = lbxgfx_get_h(p); frames = lbxgfx_get_frames(p); log_message("%ix%i %i frames\n", w, h, frames); for (int f = 0; f < frames; ++f) { p = lbxgfx_get_frameptr(data, f); ++p; for (int x = 0; x < w; ++x) { int l; uint8_t b; b = *p; if (b == 0xff) { l = 1; } else { l = 2 + p[1]; } log_message("f:%i x:%i l:%i", f, x, l); for (int i = 0; i < l; ++i) { log_message(" %02x", *p++); } log_message("\n"); } } lib_free(data); return 0; } static void show_usage(void) { fprintf(stderr, "Usage:\n" " 1oom_gfxconv [OPTIONS] OUT.BIN IN.PCX|=WxHcC [INn.PCX]*\n" " 1oom_gfxconv -d IN.BIN\n" "Options:\n" " -f Make format 1 binary (only council.lbx item 1)\n" " -i All independent frames (winlose.lbx items 1-...)\n" " -e N Extra independent frame (embassy.lbx items 2-...)\n" " -n N Set number of frames (default N = number of input files)\n" " -l N Set loop frame\n" " -p F N Include palette ; First, Number of colors\n" " -d Dump converted file for debugging\n" ); } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { struct animopts_s opts = { false, false, 0, 0, 0, 0, 0 }; int i; bool mode_dump = false; i = 1; if (i >= argc) { show_usage(); return 1; } while (argv[i][0] == '-') { uint32_t v; if (argv[i][2] != '\0') { show_usage(); return 1; } switch (argv[i][1]) { case 'd': mode_dump = true; break; case 'f': opts.fmt1 = true; break; case 'i': opts.indep = true; break; case 'n': ++i; if ((i == argc) || (!util_parse_number(argv[i], &v))) { show_usage(); return 1; } opts.num_frames = v; break; case 'e': ++i; if ((i == argc) || (!util_parse_number(argv[i], &v))) { show_usage(); return 1; } opts.extra_start_frame = v; break; case 'l': ++i; if ((i == argc) || (!util_parse_number(argv[i], &v))) { show_usage(); return 1; } opts.loop_frame = v; break; case 'p': ++i; if ((i == argc) || (!util_parse_number(argv[i], &v)) || (v > 255)) { show_usage(); return 1; } opts.pal_first = v; ++i; if ((i == argc) || (!util_parse_number(argv[i], &v)) || (v > 256) || ((opts.pal_first + v) > 256)) { show_usage(); return 1; } opts.pal_num = v; break; default: show_usage(); return 1; } ++i; } if (mode_dump) { const char *filename_in; filename_in = argv[i++]; return gfx_dump(filename_in); } else { const char *filename_out; int num_in; filename_out = argv[i++]; num_in = argc - i; if (num_in < 1) { show_usage(); return 1; } if (opts.num_frames == 0) { opts.num_frames = num_in; } else if (opts.num_frames < num_in) { num_in = opts.num_frames; } return gfx_convert(filename_out, (const char **)&argv[i], num_in, &opts); } } 1oom-1.11.2/src/gfxscale.h000066400000000000000000000005161476061725400152210ustar00rootroot00000000000000#ifndef INC_1OOM_GFXSCALE_H #define INC_1OOM_GFXSCALE_H #include "types.h" static inline uint8_t *gfxscale_draw_pixel(uint8_t *q, uint8_t b, uint16_t pitch, int scale) { for (int y = 0; y < scale; ++y) { for (int x = 0; x < scale; ++x) { q[x] = b; } q += pitch; } return q; } #endif 1oom-1.11.2/src/hw.h000066400000000000000000000050261476061725400140440ustar00rootroot00000000000000#ifndef INC_1OOM_HW_H #define INC_1OOM_HW_H /* API to hw/ */ #include "cfg.h" #include "options.h" #include "types.h" extern const char *idstr_hw; extern int hw_early_init(void); extern int hw_init(void); extern void hw_shutdown(void); extern const struct cmdline_options_s hw_cmdline_options[]; extern const struct cmdline_options_s hw_cmdline_options_extra[]; extern const struct cfg_items_s hw_cfg_items[]; extern const struct cfg_items_s hw_cfg_items_extra[]; extern void hw_opt_menu_make_page_video(void); extern void hw_log_message(const char *msg); extern void hw_log_warning(const char *msg); extern void hw_log_error(const char *msg); extern int hw_event_handle(void); extern void hw_textinput_start(void); extern void hw_textinput_stop(void); extern bool hw_kbd_set_repeat(bool enabled); extern void hw_mouse_set_xy(int mx, int my); extern int hw_icon_set(const uint8_t *data, const uint8_t *pal, int w, int h); extern int hw_video_init(int w, int h); extern void hw_video_set_palette(const uint8_t *palette, int first, int num); extern void hw_video_set_palette_color(int i, uint8_t r, uint8_t g, uint8_t b); extern void hw_video_refresh_palette(void); /* Return back buffer. */ extern uint8_t *hw_video_get_buf(void); /* Return front buffer. */ extern uint8_t *hw_video_get_buf_front(void); /* Draw the current back buffer and return new back buffer. */ extern uint8_t *hw_video_draw_buf(void); /* Redraw the front buffer. */ extern void hw_video_redraw_front(void); /* Copy front buffer to back buffer. */ extern void hw_video_copy_buf(void); /* Copy back buffer to pointed buffer. */ extern void hw_video_copy_buf_out(uint8_t *buf); extern void hw_video_copy_back_to_page2(void); extern void hw_video_copy_back_from_page2(void); extern void hw_video_copy_back_to_page3(void); extern void hw_video_copy_back_from_page3(void); extern int hw_audio_music_init(int mus_index, const uint8_t *data, uint32_t len); extern void hw_audio_music_release(int mus_index); extern void hw_audio_music_play(int mus_index); extern void hw_audio_music_fadeout(void); extern void hw_audio_music_stop(void); extern bool hw_audio_music_volume(int volume/*0..128*/); extern int hw_audio_sfx_batch_start(int sfx_index_max); extern int hw_audio_sfx_batch_end(void); extern int hw_audio_sfx_init(int sfx_index, const uint8_t *data, uint32_t len); extern void hw_audio_sfx_release(int sfx_index); extern void hw_audio_sfx_play(int sfx_index); extern void hw_audio_sfx_stop(void); extern bool hw_audio_sfx_volume(int volume/*0..128*/); extern int64_t hw_get_time_us(void); #endif 1oom-1.11.2/src/hw/000077500000000000000000000000001476061725400136705ustar00rootroot000000000000001oom-1.11.2/src/hw/Makefile.am000066400000000000000000000001771476061725400157310ustar00rootroot00000000000000SUBDIRS = nop if COMPILE_HW_SDL SUBDIRS += sdl endif if COMPILE_HW_ALLEG4 SUBDIRS += alleg endif DIST_SUBDIRS = alleg nop sdl 1oom-1.11.2/src/hw/alleg/000077500000000000000000000000001476061725400147545ustar00rootroot000000000000001oom-1.11.2/src/hw/alleg/4/000077500000000000000000000000001476061725400151175ustar00rootroot000000000000001oom-1.11.2/src/hw/alleg/4/Makefile.am000066400000000000000000000003611476061725400171530ustar00rootroot00000000000000AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/hw/alleg noinst_LIBRARIES = libhwalleg4.a libhwalleg4_a_SOURCES = \ hwalleg4.c \ hwalleg4_audio.c \ hwalleg4_mouse.c \ hwalleg4_opt.c \ hwalleg4_video.c 1oom-1.11.2/src/hw/alleg/4/hwalleg4.c000066400000000000000000000236221476061725400167770ustar00rootroot00000000000000#include "config.h" #include #include #include "types.h" #include #include "hw.h" #include "hwalleg_audio.h" #include "hwalleg_mouse.h" #include "hwalleg_opt.h" #include "hwalleg_video.h" #include "kbd.h" #include "log.h" #include "main.h" #include "mouse.h" #include "options.h" /* -------------------------------------------------------------------------- */ const char *idstr_hw = "alleg4"; /* -------------------------------------------------------------------------- */ static mookey_t key_xlat[KEY_MAX]; static void build_key_xlat(void) { memset(key_xlat, 0, sizeof(key_xlat)); key_xlat[KEY_A] = MOO_KEY_a; key_xlat[KEY_B] = MOO_KEY_b; key_xlat[KEY_C] = MOO_KEY_c; key_xlat[KEY_D] = MOO_KEY_d; key_xlat[KEY_E] = MOO_KEY_e; key_xlat[KEY_F] = MOO_KEY_f; key_xlat[KEY_G] = MOO_KEY_g; key_xlat[KEY_H] = MOO_KEY_h; key_xlat[KEY_I] = MOO_KEY_i; key_xlat[KEY_J] = MOO_KEY_j; key_xlat[KEY_K] = MOO_KEY_k; key_xlat[KEY_L] = MOO_KEY_l; key_xlat[KEY_M] = MOO_KEY_m; key_xlat[KEY_N] = MOO_KEY_n; key_xlat[KEY_O] = MOO_KEY_o; key_xlat[KEY_P] = MOO_KEY_p; key_xlat[KEY_Q] = MOO_KEY_q; key_xlat[KEY_R] = MOO_KEY_r; key_xlat[KEY_S] = MOO_KEY_s; key_xlat[KEY_T] = MOO_KEY_t; key_xlat[KEY_U] = MOO_KEY_u; key_xlat[KEY_V] = MOO_KEY_v; key_xlat[KEY_W] = MOO_KEY_w; key_xlat[KEY_X] = MOO_KEY_x; key_xlat[KEY_Y] = MOO_KEY_y; key_xlat[KEY_Z] = MOO_KEY_z; key_xlat[KEY_0] = MOO_KEY_0; key_xlat[KEY_1] = MOO_KEY_1; key_xlat[KEY_2] = MOO_KEY_2; key_xlat[KEY_3] = MOO_KEY_3; key_xlat[KEY_4] = MOO_KEY_4; key_xlat[KEY_5] = MOO_KEY_5; key_xlat[KEY_6] = MOO_KEY_6; key_xlat[KEY_7] = MOO_KEY_7; key_xlat[KEY_8] = MOO_KEY_8; key_xlat[KEY_9] = MOO_KEY_9; key_xlat[KEY_0_PAD] = MOO_KEY_KP0; key_xlat[KEY_1_PAD] = MOO_KEY_KP1; key_xlat[KEY_2_PAD] = MOO_KEY_KP2; key_xlat[KEY_3_PAD] = MOO_KEY_KP3; key_xlat[KEY_4_PAD] = MOO_KEY_KP4; key_xlat[KEY_5_PAD] = MOO_KEY_KP5; key_xlat[KEY_6_PAD] = MOO_KEY_KP6; key_xlat[KEY_7_PAD] = MOO_KEY_KP7; key_xlat[KEY_8_PAD] = MOO_KEY_KP8; key_xlat[KEY_9_PAD] = MOO_KEY_KP9; key_xlat[KEY_F1] = MOO_KEY_F1; key_xlat[KEY_F2] = MOO_KEY_F2; key_xlat[KEY_F3] = MOO_KEY_F3; key_xlat[KEY_F4] = MOO_KEY_F4; key_xlat[KEY_F5] = MOO_KEY_F5; key_xlat[KEY_F6] = MOO_KEY_F6; key_xlat[KEY_F7] = MOO_KEY_F7; key_xlat[KEY_F8] = MOO_KEY_F8; key_xlat[KEY_F9] = MOO_KEY_F9; key_xlat[KEY_F10] = MOO_KEY_F10; key_xlat[KEY_F11] = MOO_KEY_F11; key_xlat[KEY_F12] = MOO_KEY_F12; key_xlat[KEY_ESC] = MOO_KEY_ESCAPE; /* KEY_TILDE */ key_xlat[KEY_MINUS] = MOO_KEY_MINUS; key_xlat[KEY_EQUALS] = MOO_KEY_EQUALS; key_xlat[KEY_BACKSPACE] = MOO_KEY_BACKSPACE; key_xlat[KEY_TAB] = MOO_KEY_TAB; key_xlat[KEY_OPENBRACE] = MOO_KEY_LEFTBRACKET; key_xlat[KEY_CLOSEBRACE] = MOO_KEY_RIGHTBRACKET; key_xlat[KEY_ENTER] = MOO_KEY_RETURN; key_xlat[KEY_COLON] = MOO_KEY_COLON; key_xlat[KEY_QUOTE] = MOO_KEY_QUOTE; key_xlat[KEY_BACKSLASH] = MOO_KEY_BACKSLASH; /* KEY_BACKSLASH2 */ key_xlat[KEY_COMMA] = MOO_KEY_COMMA; /* KEY_STOP */ key_xlat[KEY_SLASH] = MOO_KEY_SLASH; key_xlat[KEY_SPACE] = MOO_KEY_SPACE; key_xlat[KEY_INSERT] = MOO_KEY_INSERT; key_xlat[KEY_DEL] = MOO_KEY_DELETE; key_xlat[KEY_HOME] = MOO_KEY_HOME; key_xlat[KEY_END] = MOO_KEY_END; key_xlat[KEY_PGUP] = MOO_KEY_PAGEUP; key_xlat[KEY_PGDN] = MOO_KEY_PAGEDOWN; key_xlat[KEY_LEFT] = MOO_KEY_LEFT; key_xlat[KEY_RIGHT] = MOO_KEY_RIGHT; key_xlat[KEY_UP] = MOO_KEY_UP; key_xlat[KEY_DOWN] = MOO_KEY_DOWN; key_xlat[KEY_SLASH_PAD] = MOO_KEY_KP_DIVIDE; key_xlat[KEY_ASTERISK] = MOO_KEY_ASTERISK; /* or MOO_KEY_KP_MULTIPLY? */ key_xlat[KEY_MINUS_PAD] = MOO_KEY_KP_MINUS; key_xlat[KEY_PLUS_PAD] = MOO_KEY_KP_PLUS; key_xlat[KEY_DEL_PAD] = MOO_KEY_KP_PERIOD; key_xlat[KEY_ENTER_PAD] = MOO_KEY_RETURN; key_xlat[KEY_PRTSCR] = MOO_KEY_PRINT; key_xlat[KEY_PAUSE] = MOO_KEY_PAUSE; /* KEY_ABNT_C1, KEY_YEN, KEY_KANA, KEY_CONVERT, KEY_NOCONVERT */ key_xlat[KEY_AT] = MOO_KEY_AT; /* KEY_CIRCUMFLEX, KEY_COLON2, KEY_KANJI */ key_xlat[KEY_LSHIFT] = MOO_KEY_LSHIFT; key_xlat[KEY_RSHIFT] = MOO_KEY_RSHIFT; key_xlat[KEY_LCONTROL] = MOO_KEY_LCTRL; key_xlat[KEY_RCONTROL] = MOO_KEY_RCTRL; key_xlat[KEY_ALT] = MOO_KEY_LALT; key_xlat[KEY_ALTGR] = MOO_KEY_RALT; key_xlat[KEY_LWIN] = MOO_KEY_LSUPER; key_xlat[KEY_RWIN] = MOO_KEY_RSUPER; key_xlat[KEY_MENU] = MOO_KEY_MENU; key_xlat[KEY_SCRLOCK] = MOO_KEY_SCROLLOCK; key_xlat[KEY_NUMLOCK] = MOO_KEY_NUMLOCK; key_xlat[KEY_CAPSLOCK] = MOO_KEY_CAPSLOCK; key_xlat[KEY_EQUALS_PAD] = MOO_KEY_KP_EQUALS; key_xlat[KEY_BACKQUOTE] = MOO_KEY_BACKQUOTE; key_xlat[KEY_SEMICOLON] = MOO_KEY_SEMICOLON; /* KEY_COMMAND */ /* key_xlat[KEY_KP_PERIOD] = MOO_KEY_KP_PERIOD; key_xlat[KEY_CLEAR] = MOO_KEY_CLEAR; key_xlat[KEY_EXCLAIM] = MOO_KEY_EXCLAIM; key_xlat[KEY_QUOTEDBL] = MOO_KEY_QUOTEDBL; key_xlat[KEY_HASH] = MOO_KEY_HASH; key_xlat[KEY_DOLLAR] = MOO_KEY_DOLLAR; key_xlat[KEY_AMPERSAND] = MOO_KEY_AMPERSAND; key_xlat[KEY_LEFTPAREN] = MOO_KEY_LEFTPAREN; key_xlat[KEY_RIGHTPAREN] = MOO_KEY_RIGHTPAREN; key_xlat[KEY_PLUS] = MOO_KEY_PLUS; key_xlat[KEY_PERIOD] = MOO_KEY_PERIOD; key_xlat[KEY_LESS] = MOO_KEY_LESS; key_xlat[KEY_GREATER] = MOO_KEY_GREATER; key_xlat[KEY_QUESTION] = MOO_KEY_QUESTION; key_xlat[KEY_LEFTBRACKET] = MOO_KEY_LEFTBRACKET; key_xlat[KEY_RIGHTBRACKET] = MOO_KEY_RIGHTBRACKET; key_xlat[KEY_CARET] = MOO_KEY_CARET; key_xlat[KEY_UNDERSCORE] = MOO_KEY_UNDERSCORE; key_xlat[KEY_RMETA] = MOO_KEY_RMETA; key_xlat[KEY_LMETA] = MOO_KEY_LMETA; key_xlat[KEY_MODE] = MOO_KEY_MODE; key_xlat[KEY_COMPOSE] = MOO_KEY_COMPOSE; key_xlat[KEY_HELP] = MOO_KEY_HELP; key_xlat[KEY_SYSREQ] = MOO_KEY_SYSREQ; key_xlat[KEY_BREAK] = MOO_KEY_BREAK; key_xlat[KEY_POWER] = MOO_KEY_POWER; key_xlat[KEY_EURO] = MOO_KEY_EURO; key_xlat[KEY_UNDO] = MOO_KEY_UNDO; */ } /* -------------------------------------------------------------------------- */ #include "hwalleg.c" /* -------------------------------------------------------------------------- */ volatile int64_t hw_timer_count = 0; static void hw_timer_tick(void) { ++hw_timer_count; } END_OF_STATIC_FUNCTION(hw_timer_tick) /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { return main_1oom(argc, argv); } END_OF_MAIN() int hw_early_init(void) { return 0; } int hw_init(void) { log_message_direct("allegro_init, version " ALLEGRO_VERSION_STR "\n"); if (allegro_init()) { log_error("allegro_init failed!\n"); return -1; } if (install_keyboard() < 0) { log_error("install_keyboard failed!\n"); return -1; } if (install_mouse() < 0) { log_error("install_mouse failed!\n"); return -1; } enable_hardware_cursor(); show_mouse(NULL); if (install_timer() < 0) { log_error("install_timer failed!\n"); return -1; } if (install_int_ex(hw_timer_tick, MSEC_TO_TIMER(1)) != 0) { log_error("install_int_ex failed!\n"); return -1; } LOCK_VARIABLE(hw_timer_count); LOCK_FUNCTION(hw_timer_tick); if (hw_audio_init()) { return 12; } build_key_xlat(); return 0; } void hw_shutdown(void) { hw_audio_shutdown(); hw_video_shutdown(); log_message_direct("allegro_exit\n"); allegro_exit(); } void hw_textinput_start(void) { } void hw_textinput_stop(void) { } int hw_event_handle(void) { if (keyboard_needs_poll()) { poll_keyboard(); } while (keypressed()) { uint32_t k, smod; k = readkey(); smod = key_shifts; if (!(hw_kbd_check_hotkey(k, smod))) { mookey_t key; uint32_t mod; char c; mod = 0; if (smod & KB_SHIFT_FLAG) { mod |= MOO_MOD_SHIFT; } if (smod & KB_ALT_FLAG) { mod |= MOO_MOD_ALT; } if (smod & KB_CTRL_FLAG) { mod |= MOO_MOD_CTRL; } c = scancode_to_ascii(k >> 8); if (((k >> 8) >= KEY_0_PAD) && ((k >> 8) <= KEY_9_PAD)) { c = k & 0xff; } key = key_xlat[(k >> 8)]; kbd_add_keypress(key, mod, c); } } { uint32_t mod = 0; if (key_shifts & KB_SHIFT_FLAG) { mod |= MOO_MOD_SHIFT; } if (key_shifts & KB_CTRL_FLAG) { mod |= MOO_MOD_CTRL; } if (key_shifts & KB_ALT_FLAG) { mod |= MOO_MOD_ALT; } kbd_set_pressed(MOO_KEY_UNKNOWN, mod, false); } if (mouse_needs_poll()) { poll_mouse(); } { static int prev_x = -1, prev_y, prev_z; int pos, x, y, z; pos = mouse_pos; x = ((unsigned int)pos) >> 16; y = pos & 0x0000ffff; z = mouse_z; if (prev_x < 0) { prev_x = x; prev_y = y; prev_z = z; } if (hw_opt_relmouse) { hw_mouse_move(x - prev_x, y - prev_y); if ((x <= 10) || (x >= (hw_mouse_w - 10)) || (y <= 10) || (y >= (hw_mouse_h - 10))) { x = hw_mouse_w / 2; y = hw_mouse_h / 2; position_mouse(x, y); } } else { mouse_set_xy_from_hw(x, y); } prev_x = x; prev_y = y; if (prev_z != z) { hw_mouse_scroll((prev_z < z) ? -1 : 1); prev_z = z; } } hw_mouse_buttons(mouse_b); /* rest(10) here would be nice for multitasking OSs, but seems to cause crashes on DOS mouse handler (?!) */ return 0; } int64_t hw_get_time_us(void) { return hw_timer_count * 1000; } bool hw_kbd_set_repeat(bool enabled) { if (enabled) { set_keyboard_rate(250, 33); } else { set_keyboard_rate(0, 0); } return true; } 1oom-1.11.2/src/hw/alleg/4/hwalleg4_audio.c000066400000000000000000000000331476061725400201470ustar00rootroot00000000000000#include "hwalleg_audio.c" 1oom-1.11.2/src/hw/alleg/4/hwalleg4_mouse.c000066400000000000000000000000331476061725400201760ustar00rootroot00000000000000#include "hwalleg_mouse.c" 1oom-1.11.2/src/hw/alleg/4/hwalleg4_opt.c000066400000000000000000000010661476061725400176570ustar00rootroot00000000000000#include "config.h" #include #include "hw.h" #include "cfg.h" #include "hwalleg_opt.h" #include "lib.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ const struct cfg_items_s hw_cfg_items_extra[] = { CFG_ITEM_END }; #include "hwalleg_opt.c" const struct cmdline_options_s hw_cmdline_options_extra[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; void hw_opt_menu_make_page_video(void) {} 1oom-1.11.2/src/hw/alleg/4/hwalleg4_video.c000066400000000000000000000052641476061725400201670ustar00rootroot00000000000000#include "config.h" #include #include #include "types.h" #include #include "hw.h" #include "hwalleg_video.h" #include "hwalleg_mouse.h" #include "hwalleg_opt.h" #include "lib.h" #include "log.h" #include "palette.h" /* -------------------------------------------------------------------------- */ /* double buffering + 2 aux buffers */ #define NUM_VIDEOBUF 4 static struct alleg_video_s { BITMAP *bm; void (*render)(int bufi); void (*update)(void); void (*setpal)(const uint8_t *pal, int first, int num); /* buffers used by UI */ uint8_t *buf[NUM_VIDEOBUF]; int bufw; int bufh; int bufi; RGB color[256]; } video = { 0 }; /* -------------------------------------------------------------------------- */ static void video_render_8bpp(int bufi) { BITMAP *bm = video.bm; uint8_t *p, *q = video.buf[bufi]; for (int y = 0; y < video.bufh; ++y) { p = bm->line[y]; memcpy(p, q, video.bufw); q += video.bufw; } } static void video_update_8bpp(void) { blit(video.bm, screen, 0, 0, 0, 0, video.bufw, video.bufh); } static void video_setpal_8bpp(const uint8_t *pal, int first, int num) { for (int i = first; i < (first + num); ++i) { video.color[i].r = *pal++; video.color[i].g = *pal++; video.color[i].b = *pal++; } set_palette_range(video.color, first, first + num - 1, 1); } /* -------------------------------------------------------------------------- */ int hw_video_init(int w, int h) { video.bufw = w; video.bufh = h; video.render = video_render_8bpp; video.update = video_update_8bpp; video.setpal = video_setpal_8bpp; set_color_depth(8); if (hw_opt_fullscreen || (set_gfx_mode(GFX_AUTODETECT_WINDOWED, w, h, 0, 0) != 0)) { if (set_gfx_mode(GFX_AUTODETECT, w, h, 0, 0) != 0) { log_error("set_gfx_mode(..., %i, %i, 0, 0) failed!\n", w, h); return -1; } } hw_mouse_set_limits(w, h); hw_video_in_gfx = true; set_mouse_speed(hw_opt_mouse_slowdown_x, hw_opt_mouse_slowdown_y); video.bm = create_bitmap(w, h); video.buf[0] = lib_malloc(video.bufw * video.bufh * NUM_VIDEOBUF); for (int i = 1; i < NUM_VIDEOBUF; ++i) { video.buf[i] = video.buf[0] + video.bufw * video.bufh * i; } video.bufi = 0; return 0; } void hw_video_shutdown(void) { #if 0 /* FIXME doing this crashes the program */ if (video.bm) { destroy_bitmap(video.bm); video.bm = NULL; } #endif lib_free(video.buf[0]); for (int i = 0; i < NUM_VIDEOBUF; ++i) { video.buf[i] = NULL; } } void hw_video_input_grab(bool grab) { } #include "hwalleg_video.c" 1oom-1.11.2/src/hw/alleg/Makefile.am000066400000000000000000000004401476061725400170060ustar00rootroot00000000000000SUBDIRS = if COMPILE_HW_ALLEG4 SUBDIRS += 4 endif DIST_SUBDIRS = 4 noinst_HEADERS = \ hwalleg_audio.h \ hwalleg_mouse.h \ hwalleg_opt.h \ hwalleg_video.h EXTRA_DIST = \ hwalleg.c \ hwalleg_audio.c \ hwalleg_mouse.c \ hwalleg_opt.c \ hwalleg_video.c 1oom-1.11.2/src/hw/alleg/hwalleg.c000066400000000000000000000026251476061725400165500ustar00rootroot00000000000000static bool hw_kbd_check_hotkey(uint32_t key, uint32_t smod) { if ((smod & KB_CTRL_FLAG) && (!(smod & KB_ALT_FLAG))) { if ((key >> 8) == KEY_ESC) { log_message("Alleg: got Ctrl-ESC, quitting now\n"); exit(EXIT_SUCCESS); #if 0 } else if ((key >> 8) == KEY_F10) { hw_mouse_toggle_grab(); return true; #endif } else if ((key >> 8) == KEY_CLOSEBRACE) { if (smod & KB_SHIFT_FLAG) { hw_audio_music_volume(opt_music_volume + 4); } else { hw_audio_sfx_volume(opt_sfx_volume + 4); } return true; } else if ((key >> 8) == KEY_OPENBRACE) { if (smod & KB_SHIFT_FLAG) { hw_audio_music_volume(opt_music_volume - 4); } else { hw_audio_sfx_volume(opt_sfx_volume - 4); } return true; } } return false; } /* -------------------------------------------------------------------------- */ void hw_log_message(const char *msg) { if (!hw_video_in_gfx) { fputs(msg, stdout); } } void hw_log_warning(const char *msg) { if (!hw_video_in_gfx) { fputs(msg, stderr); } } void hw_log_error(const char *msg) { if (!hw_video_in_gfx) { fputs(msg, stderr); } } int hw_icon_set(const uint8_t *data, const uint8_t *pal, int w, int h) { return 0; } 1oom-1.11.2/src/hw/alleg/hwalleg_audio.c000066400000000000000000000216331476061725400177310ustar00rootroot00000000000000#include "config.h" #include #include #include "types.h" #include #include "hw.h" #include "hwalleg_audio.h" #include "fmt_mus.h" #include "fmt_sfx.h" #include "hwalleg_opt.h" #include "lib.h" #include "log.h" #include "options.h" #include "util.h" /* -------------------------------------------------------------------------- */ static bool audio_initialized = false; static int audio_rate = 0, audio_bits = 0, audio_channels = 0; struct sfx_s { struct SAMPLE *s; }; static int sfx_num = 0; static struct sfx_s *sfxtbl = NULL; static int sfx_playing; struct mus_s { mus_type_t type; struct MIDI *music; bool loops; }; static int mus_num = 0; static struct mus_s *mustbl = NULL; static int mus_playing; /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int hw_audio_init(void) { if (opt_audio_enabled) { reserve_voices(1, -1); set_volume_per_voice(0); if (install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL) != 0) { log_error("initialising Allegro sound: %s\n", allegro_error); return -1; } audio_rate = get_mixer_frequency(); audio_bits = get_mixer_bits(); audio_channels = get_mixer_channels(); log_message("Audio: Sound %s: %s\n", digi_driver->name, digi_driver->desc); log_message("Audio: Sound %i bit, %i Hz, %i ch\n", audio_bits, audio_rate, audio_channels); log_message("Audio: Music %s: %s\n", midi_driver->name, midi_driver->desc); if ((audio_bits == 8) && (audio_channels == 1)) { log_error("8 bit 1 ch sound currently not supported! Set sbtype=sb16 in your dosbox-*.conf, buy some new hardware, or start with -noaudio.\n"); return -1; } sfx_playing = -1; mus_playing = -1; audio_initialized = true; { int volume; volume = opt_sfx_volume; opt_sfx_volume = -1; hw_audio_sfx_volume(volume); volume = opt_music_volume; opt_music_volume = -1; hw_audio_music_volume(volume); } } return 0; } void hw_audio_shutdown(void) { if (audio_initialized) { log_message("Audio: shutdown\n"); remove_sound(); for (int i = 0; i < sfx_num; ++i) { hw_audio_sfx_release(i); } lib_free(sfxtbl); sfxtbl = NULL; audio_initialized = false; } } int hw_audio_music_init(int mus_index, const uint8_t *data_in, uint32_t len_in) { const uint8_t *data = NULL; uint8_t *buf = NULL; uint32_t len = 0; struct mus_s *m; int res; if (!audio_initialized) { return 0; } if (mus_index >= mus_num) { int old_mus_num = mus_num; mus_num = (mus_index + 1); mustbl = lib_realloc(mustbl, mus_num * sizeof(struct mus_s)); for (int i = old_mus_num; i < mus_num; ++i) { mustbl[i].type = MUS_TYPE_UNKNOWN; mustbl[i].music = NULL; } } m = &mustbl[mus_index]; if (m->type != MUS_TYPE_UNKNOWN) { hw_audio_music_release(mus_index); } m->type = fmt_mus_detect(data_in, len_in); switch (m->type) { case MUS_TYPE_LBXXMID: if (fmt_mus_convert_xmid(data_in, len_in, &buf, &len, &m->loops)) { data = buf; } else { m->type = MUS_TYPE_UNKNOWN; } break; case MUS_TYPE_MIDI: break; case MUS_TYPE_UNKNOWN: break; default: log_error("Audio: unsupported music type %i\n", m->type); m->type = MUS_TYPE_UNKNOWN; break; } if (m->type == MUS_TYPE_UNKNOWN) { log_error("Audio: failed to init music %i\n", mus_index); return -1; } /* HACK Allegro provides no way to read a MIDI file in memory. Use a temp file. */ res = util_file_save("1tempmus.mid", data, len); lib_free(buf); buf = 0; data = 0; if (res) { log_error("Audio: failed to create temp file\n"); m->type = MUS_TYPE_UNKNOWN; return -1; } m->music = load_midi("1tempmus.mid"); unlink("1tempmus.mid"); if (!m->music) { log_error("Audio: load_midi failed on music %i (type %i)\n", mus_index, m->type); m->type = MUS_TYPE_UNKNOWN; return -1; } return 0; } void hw_audio_music_release(int mus_index) { if (mus_index < mus_num) { if (mustbl[mus_index].music) { destroy_midi(mustbl[mus_index].music); mustbl[mus_index].music = NULL; } mustbl[mus_index].type = MUS_TYPE_UNKNOWN; } } void hw_audio_music_play(int mus_index) { if (audio_initialized && opt_music_enabled && (mus_index < mus_num)) { stop_midi(); play_midi(mustbl[mus_index].music, mustbl[mus_index].loops ? 1 : 0); mus_playing = mus_index; } } void hw_audio_music_fadeout(void) { /* TODO */ hw_audio_music_stop(); } void hw_audio_music_stop(void) { if (audio_initialized && opt_music_enabled && (mus_playing >= 0)) { stop_midi(); mus_playing = -1; } } bool hw_audio_music_volume(int volume) { if (volume < 0) { volume = 0; } if (volume > 128) { volume = 128; } if (audio_initialized && opt_music_enabled) { set_volume(-1, volume * 2); } if (opt_music_volume != volume) { log_message("Audio: music volume %i\n", volume); opt_music_volume = volume; } return true; } /* -------------------------------------------------------------------------- */ int hw_audio_sfx_batch_start(int sfx_index_max) { return 0; } int hw_audio_sfx_batch_end(void) { return 0; } int hw_audio_sfx_init(int sfx_index, const uint8_t *data_in, uint32_t len_in) { uint8_t *data = NULL; uint32_t len = 0; if (!audio_initialized) { return 0; } if (sfx_index >= sfx_num) { int old_sfx_num = sfx_num; sfx_num = (sfx_index + 1); sfxtbl = lib_realloc(sfxtbl, sfx_num * sizeof(struct sfx_s)); for (int i = old_sfx_num; i < sfx_num; ++i) { sfxtbl[i].s = NULL; } } if (sfxtbl[sfx_index].s) { hw_audio_sfx_release(sfx_index); } if (fmt_sfx_convert(data_in, len_in, &data, &len, NULL, audio_rate, false)) { SAMPLE *s; const int16_t *q; s = create_sample(audio_bits, audio_channels, audio_rate, len / 4); if (!s) { log_error("Audio: failed to init sound %i\n", sfx_index); return -1; } q = (const int16_t *)data; /* convert signed to unsigned, (if needed) stereo to mono and 16 to 8 bits */ if (audio_bits == 16) { uint16_t *p; p = s->data; if (audio_channels == 2) { for (int i = 0; i < (len / 2); ++i) { *p++ = *q++ ^ 0x8000; } } else { for (int i = 0; i < (len / 4); ++i) { int v; v = *q++; v += *q++; v = ((v / 2) & 0xffff); *p++ = v ^ 0x8000; } } } else { uint8_t *p; p = s->data; if (audio_channels == 2) { for (int i = 0; i < (len / 2); ++i) { *p++ = ((((uint16_t)*q++) >> 9) ^ 0x40) | 0x80; } } else { for (int i = 0; i < (len / 4); ++i) { int v; v = *q++; v += *q++; v = ((v / 2) & 0xffff); *p++ = ((((uint16_t)v) >> 9) ^ 0x40) | 0x80; } } } sfxtbl[sfx_index].s = s; lib_free(data); } else { log_error("Audio: failed to init sound %i\n", sfx_index); return -1; } return 0; } void hw_audio_sfx_release(int sfx_index) { if (sfx_index < sfx_num) { if (sfxtbl[sfx_index].s) { destroy_sample(sfxtbl[sfx_index].s); sfxtbl[sfx_index].s = NULL; } } } void hw_audio_sfx_play(int sfx_index) { if (audio_initialized && opt_sfx_enabled && (sfx_index < sfx_num)) { play_sample(sfxtbl[sfx_index].s, 255, 128, 1000, 0); sfx_playing = sfx_index; } } void hw_audio_sfx_stop(void) { if (audio_initialized && opt_sfx_enabled && (sfx_playing >= 0)) { stop_sample(sfxtbl[sfx_playing].s); sfx_playing = -1; } } bool hw_audio_sfx_volume(int volume) { if (volume < 0) { volume = 0; } if (volume > 128) { volume = 128; } if (audio_initialized && opt_sfx_enabled) { set_volume(volume * 2, -1); } if (opt_sfx_volume != volume) { log_message("Audio: sfx volume %i\n", volume); opt_sfx_volume = volume; } return true; } 1oom-1.11.2/src/hw/alleg/hwalleg_audio.h000066400000000000000000000002141476061725400177260ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_AUDIO_H #define INC_1OOM_HWSDL_AUDIO_H extern int hw_audio_init(void); extern void hw_audio_shutdown(void); #endif 1oom-1.11.2/src/hw/alleg/hwalleg_mouse.c000066400000000000000000000035061476061725400177570ustar00rootroot00000000000000#include "config.h" #include "types.h" #include #include "hw.h" #include "hwalleg_mouse.h" #include "hwalleg_opt.h" #include "hwalleg_video.h" #include "mouse.h" /* -------------------------------------------------------------------------- */ bool hw_mouse_enabled = true; int hw_mouse_w; int hw_mouse_h; /* -------------------------------------------------------------------------- */ void hw_mouse_grab(void) { if (!hw_mouse_enabled) { hw_mouse_enabled = true; hw_video_input_grab(true); } } void hw_mouse_ungrab(void) { if (hw_mouse_enabled) { hw_mouse_enabled = false; hw_video_input_grab(false); } } void hw_mouse_toggle_grab(void) { if (hw_mouse_enabled) { hw_mouse_ungrab(); } else { hw_mouse_grab(); } } void hw_mouse_set_limits(int w, int h) { hw_mouse_w = w; hw_mouse_h = h; set_mouse_range(0, 0, w - 1, h - 1); } void hw_mouse_move(int dx, int dy) { int x, y; x = moouse_x + dx; if (x < 0) { x = 0; } if (x >= hw_mouse_w) { x = hw_mouse_w - 1; } y = moouse_y + dy; if (y < 0) { y = 0; } if (y >= hw_mouse_h) { y = hw_mouse_h - 1; } mouse_set_xy_from_hw(x, y); } void hw_mouse_set_xy(int mx, int my) { if (hw_opt_relmouse) { mouse_set_xy_from_hw(mx, my); } else { position_mouse(mx, my); } } void hw_mouse_buttons(int state) { if (hw_mouse_enabled) { int b = mouse_buttons; if (state & 1) { b |= MOUSE_BUTTON_MASK_LEFT; } else { b &= ~MOUSE_BUTTON_MASK_LEFT; } if (state & 2) { b |= MOUSE_BUTTON_MASK_RIGHT; } else { b &= ~MOUSE_BUTTON_MASK_RIGHT; } mouse_set_buttons_from_hw(b); } } void hw_mouse_scroll(int scroll) { mouse_set_scroll_from_hw(scroll); } 1oom-1.11.2/src/hw/alleg/hwalleg_mouse.h000066400000000000000000000007021476061725400177570ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_MOUSE_H #define INC_1OOM_HWSDL_MOUSE_H #include "types.h" extern bool hw_mouse_enabled; extern int hw_mouse_w; extern int hw_mouse_h; extern void hw_mouse_grab(void); extern void hw_mouse_ungrab(void); extern void hw_mouse_toggle_grab(void); extern void hw_mouse_set_limits(int w, int h); extern void hw_mouse_move(int dx, int dy); extern void hw_mouse_buttons(int state); extern void hw_mouse_scroll(int scroll); #endif 1oom-1.11.2/src/hw/alleg/hwalleg_opt.c000066400000000000000000000022171476061725400174270ustar00rootroot00000000000000/* already included by includer */ #if 0 #include "config.h" #include #include "hw.h" #include "hwalleg_opt.h" #include "options.h" #include "types.h" #endif /* -------------------------------------------------------------------------- */ bool hw_opt_fullscreen = true; bool hw_opt_relmouse = true; int hw_opt_mouse_slowdown_x = 1; int hw_opt_mouse_slowdown_y = 1; /* -------------------------------------------------------------------------- */ const struct cfg_items_s hw_cfg_items[] = { CFG_ITEM_BOOL("fs", &hw_opt_fullscreen), CFG_ITEM_BOOL("relmouse", &hw_opt_relmouse), CFG_ITEM_INT("mouse_slowdown_x", &hw_opt_mouse_slowdown_x, NULL), CFG_ITEM_INT("mouse_slowdown_y", &hw_opt_mouse_slowdown_y, NULL), CFG_ITEM_END }; /* -------------------------------------------------------------------------- */ const struct cmdline_options_s hw_cmdline_options[] = { { "-fs", 0, options_enable_bool_var, (void *)&hw_opt_fullscreen, NULL, "Enable fullscreen" }, { "-window", 0, options_disable_bool_var, (void *)&hw_opt_fullscreen, NULL, "Use windowed mode" }, { NULL, 0, NULL, NULL, NULL, NULL } }; 1oom-1.11.2/src/hw/alleg/hwalleg_opt.h000066400000000000000000000003071476061725400174320ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_OPT_H #define INC_1OOM_HWSDL_OPT_H extern bool hw_opt_fullscreen; extern bool hw_opt_relmouse; extern int hw_opt_mouse_slowdown_x; extern int hw_opt_mouse_slowdown_y; #endif 1oom-1.11.2/src/hw/alleg/hwalleg_video.c000066400000000000000000000030241476061725400177300ustar00rootroot00000000000000bool hw_video_in_gfx = false; void hw_video_refresh(int front) { video.render(video.bufi ^ front); video.update(); } void hw_video_update(void) { video.update(); } void hw_video_set_palette(const uint8_t *pal, int first, int num) { ui_palette_set(pal, first, num); video.setpal(pal, first, num); } void hw_video_set_palette_color(int i, uint8_t r, uint8_t g, uint8_t b) { ui_palette_set_color(i, r, g, b); } void hw_video_refresh_palette(void) { video.setpal(ui_palette, 0, 256); } uint8_t *hw_video_get_buf(void) { return video.buf[video.bufi]; } uint8_t *hw_video_get_buf_front(void) { return video.buf[video.bufi ^ 1]; } uint8_t *hw_video_draw_buf(void) { hw_video_refresh(0); video.bufi ^= 1; return video.buf[video.bufi]; } void hw_video_redraw_front(void) { hw_video_refresh(1); } void hw_video_copy_buf(void) { memcpy(video.buf[video.bufi], video.buf[video.bufi ^ 1], video.bufw * video.bufh); } void hw_video_copy_buf_out(uint8_t *buf) { memcpy(buf, video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_to_page2(void) { memcpy(video.buf[2], video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_from_page2(void) { memcpy(video.buf[video.bufi], video.buf[2], video.bufw * video.bufh); } void hw_video_copy_back_to_page3(void) { memcpy(video.buf[3], video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_from_page3(void) { memcpy(video.buf[video.bufi], video.buf[3], video.bufw * video.bufh); } 1oom-1.11.2/src/hw/alleg/hwalleg_video.h000066400000000000000000000004021476061725400177320ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_VIDEO_H #define INC_1OOM_HWSDL_VIDEO_H extern bool hw_video_in_gfx; extern void hw_video_shutdown(void); extern void hw_video_update(void); extern void hw_video_refresh(int front); extern void hw_video_input_grab(bool grab); #endif 1oom-1.11.2/src/hw/nop/000077500000000000000000000000001476061725400144645ustar00rootroot000000000000001oom-1.11.2/src/hw/nop/Makefile.am000066400000000000000000000001541476061725400165200ustar00rootroot00000000000000AM_CPPFLAGS = \ -I$(top_srcdir)/src noinst_LIBRARIES = libhwnop.a libhwnop_a_SOURCES = \ hwnop.c 1oom-1.11.2/src/hw/nop/hwnop.c000066400000000000000000000027421476061725400157700ustar00rootroot00000000000000#include "config.h" #include #include #include "hw.h" #include "cfg.h" #include "main.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ const struct cmdline_options_s hw_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; const struct cmdline_options_s hw_cmdline_options_extra[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; const struct cfg_items_s hw_cfg_items[] = { CFG_ITEM_END }; const struct cfg_items_s hw_cfg_items_extra[] = { CFG_ITEM_END }; /* -------------------------------------------------------------------------- */ const char *idstr_hw = "nop"; int main(int argc, char **argv) { return main_1oom(argc, argv); } int hw_early_init(void) { return 0; } int hw_init(void) { return 0; } void hw_shutdown(void) { } void hw_log_message(const char *msg) { fputs(msg, stdout); } void hw_log_warning(const char *msg) { fputs(msg, stderr); } void hw_log_error(const char *msg) { fputs(msg, stderr); } int64_t hw_get_time_us(void) { #ifndef IS_MSDOS struct timeval tv; gettimeofday(&tv, NULL); return (int64_t)tv.tv_usec + 1000000ll * (int64_t)tv.tv_sec; #else return 0; #endif } void hw_video_set_palette(const uint8_t *palette, int first, int num) { } uint8_t *hw_video_get_buf(void) { return 0; } bool hw_audio_sfx_volume(int volume) { return true; } bool hw_audio_music_volume(int volume) { return true; } 1oom-1.11.2/src/hw/sdl/000077500000000000000000000000001476061725400144525ustar00rootroot000000000000001oom-1.11.2/src/hw/sdl/1/000077500000000000000000000000001476061725400146125ustar00rootroot000000000000001oom-1.11.2/src/hw/sdl/1/Makefile.am000066400000000000000000000003751476061725400166530ustar00rootroot00000000000000AM_CFLAGS=@HW_SDL1_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/hw/sdl noinst_LIBRARIES = libhwsdl1.a libhwsdl1_a_SOURCES = \ hwsdl1.c \ hwsdl1_audio.c \ hwsdl1_mouse.c \ hwsdl1_opt.c \ hwsdl1_video.c 1oom-1.11.2/src/hw/sdl/1/hwsdl1.c000066400000000000000000000250201476061725400161570ustar00rootroot00000000000000#include "config.h" #include #include #ifdef HAVE_SDLMAIN #include "SDL_main.h" #endif #include "SDL.h" #include "SDL_keysym.h" #include "hw.h" #include "hwsdl_audio.h" #include "hwsdl_mouse.h" #include "hwsdl_opt.h" #include "hwsdl_video.h" #include "kbd.h" #include "log.h" #include "main.h" #include "options.h" #include "types.h" #include "version.h" /* -------------------------------------------------------------------------- */ const char *idstr_hw = "sdl1"; /* -------------------------------------------------------------------------- */ static mookey_t key_xlat[SDLK_LAST]; static void build_key_xlat(void) { memset(key_xlat, 0, sizeof(key_xlat)); key_xlat[SDLK_FIRST] = MOO_KEY_FIRST; key_xlat[SDLK_BACKSPACE] = MOO_KEY_BACKSPACE; key_xlat[SDLK_TAB] = MOO_KEY_TAB; key_xlat[SDLK_CLEAR] = MOO_KEY_CLEAR; key_xlat[SDLK_RETURN] = MOO_KEY_RETURN; key_xlat[SDLK_PAUSE] = MOO_KEY_PAUSE; key_xlat[SDLK_ESCAPE] = MOO_KEY_ESCAPE; key_xlat[SDLK_SPACE] = MOO_KEY_SPACE; key_xlat[SDLK_EXCLAIM] = MOO_KEY_EXCLAIM; key_xlat[SDLK_QUOTEDBL] = MOO_KEY_QUOTEDBL; key_xlat[SDLK_HASH] = MOO_KEY_HASH; key_xlat[SDLK_DOLLAR] = MOO_KEY_DOLLAR; key_xlat[SDLK_AMPERSAND] = MOO_KEY_AMPERSAND; key_xlat[SDLK_QUOTE] = MOO_KEY_QUOTE; key_xlat[SDLK_LEFTPAREN] = MOO_KEY_LEFTPAREN; key_xlat[SDLK_RIGHTPAREN] = MOO_KEY_RIGHTPAREN; key_xlat[SDLK_ASTERISK] = MOO_KEY_ASTERISK; key_xlat[SDLK_PLUS] = MOO_KEY_PLUS; key_xlat[SDLK_COMMA] = MOO_KEY_COMMA; key_xlat[SDLK_MINUS] = MOO_KEY_MINUS; key_xlat[SDLK_PERIOD] = MOO_KEY_PERIOD; key_xlat[SDLK_SLASH] = MOO_KEY_SLASH; key_xlat[SDLK_0] = MOO_KEY_0; key_xlat[SDLK_1] = MOO_KEY_1; key_xlat[SDLK_2] = MOO_KEY_2; key_xlat[SDLK_3] = MOO_KEY_3; key_xlat[SDLK_4] = MOO_KEY_4; key_xlat[SDLK_5] = MOO_KEY_5; key_xlat[SDLK_6] = MOO_KEY_6; key_xlat[SDLK_7] = MOO_KEY_7; key_xlat[SDLK_8] = MOO_KEY_8; key_xlat[SDLK_9] = MOO_KEY_9; key_xlat[SDLK_COLON] = MOO_KEY_COLON; key_xlat[SDLK_SEMICOLON] = MOO_KEY_SEMICOLON; key_xlat[SDLK_LESS] = MOO_KEY_LESS; key_xlat[SDLK_EQUALS] = MOO_KEY_EQUALS; key_xlat[SDLK_GREATER] = MOO_KEY_GREATER; key_xlat[SDLK_QUESTION] = MOO_KEY_QUESTION; key_xlat[SDLK_AT] = MOO_KEY_AT; key_xlat[SDLK_LEFTBRACKET] = MOO_KEY_LEFTBRACKET; key_xlat[SDLK_BACKSLASH] = MOO_KEY_BACKSLASH; key_xlat[SDLK_RIGHTBRACKET] = MOO_KEY_RIGHTBRACKET; key_xlat[SDLK_CARET] = MOO_KEY_CARET; key_xlat[SDLK_UNDERSCORE] = MOO_KEY_UNDERSCORE; key_xlat[SDLK_BACKQUOTE] = MOO_KEY_BACKQUOTE; key_xlat[SDLK_a] = MOO_KEY_a; key_xlat[SDLK_b] = MOO_KEY_b; key_xlat[SDLK_c] = MOO_KEY_c; key_xlat[SDLK_d] = MOO_KEY_d; key_xlat[SDLK_e] = MOO_KEY_e; key_xlat[SDLK_f] = MOO_KEY_f; key_xlat[SDLK_g] = MOO_KEY_g; key_xlat[SDLK_h] = MOO_KEY_h; key_xlat[SDLK_i] = MOO_KEY_i; key_xlat[SDLK_j] = MOO_KEY_j; key_xlat[SDLK_k] = MOO_KEY_k; key_xlat[SDLK_l] = MOO_KEY_l; key_xlat[SDLK_m] = MOO_KEY_m; key_xlat[SDLK_n] = MOO_KEY_n; key_xlat[SDLK_o] = MOO_KEY_o; key_xlat[SDLK_p] = MOO_KEY_p; key_xlat[SDLK_q] = MOO_KEY_q; key_xlat[SDLK_r] = MOO_KEY_r; key_xlat[SDLK_s] = MOO_KEY_s; key_xlat[SDLK_t] = MOO_KEY_t; key_xlat[SDLK_u] = MOO_KEY_u; key_xlat[SDLK_v] = MOO_KEY_v; key_xlat[SDLK_w] = MOO_KEY_w; key_xlat[SDLK_x] = MOO_KEY_x; key_xlat[SDLK_y] = MOO_KEY_y; key_xlat[SDLK_z] = MOO_KEY_z; key_xlat[SDLK_DELETE] = MOO_KEY_DELETE; key_xlat[SDLK_KP0] = MOO_KEY_KP0; key_xlat[SDLK_KP1] = MOO_KEY_KP1; key_xlat[SDLK_KP2] = MOO_KEY_KP2; key_xlat[SDLK_KP3] = MOO_KEY_KP3; key_xlat[SDLK_KP4] = MOO_KEY_KP4; key_xlat[SDLK_KP5] = MOO_KEY_KP5; key_xlat[SDLK_KP6] = MOO_KEY_KP6; key_xlat[SDLK_KP7] = MOO_KEY_KP7; key_xlat[SDLK_KP8] = MOO_KEY_KP8; key_xlat[SDLK_KP9] = MOO_KEY_KP9; key_xlat[SDLK_KP_PERIOD] = MOO_KEY_KP_PERIOD; key_xlat[SDLK_KP_DIVIDE] = MOO_KEY_KP_DIVIDE; key_xlat[SDLK_KP_MULTIPLY] = MOO_KEY_KP_MULTIPLY; key_xlat[SDLK_KP_MINUS] = MOO_KEY_KP_MINUS; key_xlat[SDLK_KP_PLUS] = MOO_KEY_KP_PLUS; key_xlat[SDLK_KP_ENTER] = MOO_KEY_RETURN; key_xlat[SDLK_KP_EQUALS] = MOO_KEY_KP_EQUALS; key_xlat[SDLK_UP] = MOO_KEY_UP; key_xlat[SDLK_DOWN] = MOO_KEY_DOWN; key_xlat[SDLK_RIGHT] = MOO_KEY_RIGHT; key_xlat[SDLK_LEFT] = MOO_KEY_LEFT; key_xlat[SDLK_INSERT] = MOO_KEY_INSERT; key_xlat[SDLK_HOME] = MOO_KEY_HOME; key_xlat[SDLK_END] = MOO_KEY_END; key_xlat[SDLK_PAGEUP] = MOO_KEY_PAGEUP; key_xlat[SDLK_PAGEDOWN] = MOO_KEY_PAGEDOWN; key_xlat[SDLK_F1] = MOO_KEY_F1; key_xlat[SDLK_F2] = MOO_KEY_F2; key_xlat[SDLK_F3] = MOO_KEY_F3; key_xlat[SDLK_F4] = MOO_KEY_F4; key_xlat[SDLK_F5] = MOO_KEY_F5; key_xlat[SDLK_F6] = MOO_KEY_F6; key_xlat[SDLK_F7] = MOO_KEY_F7; key_xlat[SDLK_F8] = MOO_KEY_F8; key_xlat[SDLK_F9] = MOO_KEY_F9; key_xlat[SDLK_F10] = MOO_KEY_F10; key_xlat[SDLK_F11] = MOO_KEY_F11; key_xlat[SDLK_F12] = MOO_KEY_F12; key_xlat[SDLK_F13] = MOO_KEY_F13; key_xlat[SDLK_F14] = MOO_KEY_F14; key_xlat[SDLK_F15] = MOO_KEY_F15; key_xlat[SDLK_NUMLOCK] = MOO_KEY_NUMLOCK; key_xlat[SDLK_CAPSLOCK] = MOO_KEY_CAPSLOCK; key_xlat[SDLK_SCROLLOCK] = MOO_KEY_SCROLLOCK; key_xlat[SDLK_RSHIFT] = MOO_KEY_RSHIFT; key_xlat[SDLK_LSHIFT] = MOO_KEY_LSHIFT; key_xlat[SDLK_RCTRL] = MOO_KEY_RCTRL; key_xlat[SDLK_LCTRL] = MOO_KEY_LCTRL; key_xlat[SDLK_RALT] = MOO_KEY_RALT; key_xlat[SDLK_LALT] = MOO_KEY_LALT; key_xlat[SDLK_RMETA] = MOO_KEY_RMETA; key_xlat[SDLK_LMETA] = MOO_KEY_LMETA; key_xlat[SDLK_LSUPER] = MOO_KEY_LSUPER; key_xlat[SDLK_RSUPER] = MOO_KEY_RSUPER; key_xlat[SDLK_MODE] = MOO_KEY_MODE; key_xlat[SDLK_COMPOSE] = MOO_KEY_COMPOSE; key_xlat[SDLK_HELP] = MOO_KEY_HELP; key_xlat[SDLK_PRINT] = MOO_KEY_PRINT; key_xlat[SDLK_SYSREQ] = MOO_KEY_SYSREQ; key_xlat[SDLK_BREAK] = MOO_KEY_BREAK; key_xlat[SDLK_MENU] = MOO_KEY_MENU; key_xlat[SDLK_POWER] = MOO_KEY_POWER; key_xlat[SDLK_EURO] = MOO_KEY_EURO; key_xlat[SDLK_UNDO] = MOO_KEY_UNDO; } static inline uint32_t mod_xlat(SDLMod smod) { uint32_t mod = 0; if (smod & KMOD_SHIFT) { mod |= MOO_MOD_SHIFT; } if (smod & KMOD_ALT) { mod |= MOO_MOD_ALT; } if (smod & KMOD_CTRL) { mod |= MOO_MOD_CTRL; } if (smod & KMOD_META) { mod |= MOO_MOD_META; } return mod; } /* -------------------------------------------------------------------------- */ #define SDL1or2Key SDLKey #define SDL1or2Mod SDLMod #include "hwsdl.c" /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { return main_1oom(argc, argv); } int hw_early_init(void) { return 0; } int hw_init(void) { int flags = SDL_INIT_VIDEO | (opt_audio_enabled ? SDL_INIT_AUDIO : 0); log_message("SDL_Init\n"); if (SDL_Init(flags) < 0) { log_error("SDL_Init(0x%x) failed: %s\n", flags, SDL_GetError()); return 11; } SDL_WM_SetCaption(PACKAGE_NAME " " VERSION_STR, PACKAGE_NAME " " VERSION_STR); if (hw_audio_init()) { return 12; } SDL_EnableUNICODE(1); build_key_xlat(); return 0; } void hw_shutdown(void) { hw_audio_shutdown(); hw_video_shutdown(); log_message("SDL_Quit\n"); SDL_Quit(); } void hw_textinput_start(void) { } void hw_textinput_stop(void) { } int hw_event_handle(void) { SDL_Event e; while (SDL_PollEvent(&e)) { switch (e.type) { uint32_t mod; case SDL_KEYDOWN: { uint16_t c; SDLMod smod; c = e.key.keysym.unicode; smod = e.key.keysym.mod; if (((c & 0xff80) == 0) && ((c & 0x7f) != 0)) { c &= 0x7f; } else { c = 0; } if (!(hw_kbd_check_hotkey(e.key.keysym.sym, smod, c))) { mookey_t key; key = key_xlat[e.key.keysym.sym]; mod = mod_xlat(smod); if (e.key.keysym.sym == SDLK_LCTRL || e.key.keysym.sym == SDLK_RCTRL) mod |= MOO_MOD_CTRL; if (e.key.keysym.sym == SDLK_LALT || e.key.keysym.sym == SDLK_RALT) mod |= MOO_MOD_ALT; if (e.key.keysym.sym == SDLK_LSHIFT || e.key.keysym.sym == SDLK_RSHIFT) mod |= MOO_MOD_SHIFT; kbd_add_keypress(key, mod, c); kbd_set_pressed(key, mod, true); } } break; case SDL_KEYUP: mod = mod_xlat(e.key.keysym.mod); if (e.key.keysym.sym == SDLK_LCTRL || e.key.keysym.sym == SDLK_RCTRL) mod &= ~MOO_MOD_CTRL; kbd_set_pressed(key_xlat[e.key.keysym.sym], mod, false); break; case SDL_MOUSEMOTION: if (hw_mouse_enabled) { hw_mouse_move((int)(e.motion.xrel), (int)(e.motion.yrel)); } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: if ((e.button.state == SDL_PRESSED) && ((e.button.button == SDL_BUTTON_WHEELUP) || (e.button.button == SDL_BUTTON_WHEELDOWN))) { hw_mouse_scroll((e.button.button == SDL_BUTTON_WHEELUP) ? -1 : 1); } else { hw_mouse_button((int)(e.button.button), (e.button.state == SDL_PRESSED)); } break; case SDL_QUIT: hw_audio_shutdown_pre(); exit(EXIT_SUCCESS); break; case SDL_VIDEORESIZE: hw_video_resize((unsigned int)e.resize.w, (unsigned int)e.resize.h); break; case SDL_VIDEOEXPOSE: hw_video_update(); break; case SDL_ACTIVEEVENT: { Uint8 state; state = SDL_GetAppState(); if ((state & (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) != (SDL_APPINPUTFOCUS | SDL_APPACTIVE)) { hw_mouse_ungrab(); } } break; default: break; } } if (hw_audio_check_process()) { exit(EXIT_FAILURE); } SDL_Delay(10); return 0; } bool hw_kbd_set_repeat(bool enabled) { if (enabled) { SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); } else { SDL_EnableKeyRepeat(0, 0); } return true; } 1oom-1.11.2/src/hw/sdl/1/hwsdl1_audio.c000066400000000000000000000004221476061725400173370ustar00rootroot00000000000000#include "config.h" #ifdef HAVE_SDL1MIXER #define HAVE_SDLMIXER #include "SDL.h" #include "SDL_mixer.h" #include "SDL_rwops.h" #define USE_SFX_INIT_THREAD #define HWSDLX_CreateThread(_func_) SDL_CreateThread(_func_, 0) #endif /* HAVE_SDL1MIXER */ #include "hwsdl_audio.c" 1oom-1.11.2/src/hw/sdl/1/hwsdl1_mouse.c000066400000000000000000000002141476061725400173650ustar00rootroot00000000000000#include "config.h" #include "SDL.h" #include "hwsdl_mouse.c" void hw_mouse_set_xy(int mx, int my) { mouse_set_xy_from_hw(mx, my); } 1oom-1.11.2/src/hw/sdl/1/hwsdl1_opt.c000066400000000000000000000047171476061725400170530ustar00rootroot00000000000000#include "config.h" #include #include "hw.h" #include "cfg.h" #include "hwsdl_opt.h" #include "hwsdl_audio.h" #include "hwsdl_video.h" #include "lib.h" #include "menu.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define HW_DEFAULT_FULLSCREEN false #ifdef HAVE_SDL1GL bool hw_opt_use_gl = true; int hw_opt_gl_filter = 1; int hw_opt_bpp = 0; #define HAVE_SDLX_ASPECT #endif /* HAVE_SDL1GL */ #ifdef HAVE_SDL1MIXER #define HAVE_SDLMIXER #endif /* HAVE_SDLMIXER1 */ /* -------------------------------------------------------------------------- */ #ifdef HAVE_SDL1GL static const char *hw_gl_filter_str[2] = { "Nearest", "Linear" }; static const char *hw_uiopts_filter_get(void) { return hw_gl_filter_str[hw_opt_gl_filter]; } static bool hw_uiopts_filter_next(void) { hw_opt_gl_filter = (hw_opt_gl_filter + 1) % 2; return true; } #endif /* HAVE_SDL1GL */ /* -------------------------------------------------------------------------- */ const struct cfg_items_s hw_cfg_items_extra[] = { #ifdef HAVE_SDL1GL CFG_ITEM_BOOL("gl", &hw_opt_use_gl), CFG_ITEM_INT("bpp", &hw_opt_bpp, 0), CFG_ITEM_INT("filter", &hw_opt_gl_filter, 0), #endif /* HAVE_SDL1GL */ CFG_ITEM_END }; #include "hwsdl_opt.c" const struct cmdline_options_s hw_cmdline_options_extra[] = { #ifdef HAVE_SDL1GL { "-gl", 0, options_enable_bool_var, (void *)&hw_opt_use_gl, NULL, "Enable OpenGL" }, { "-nogl", 0, options_disable_bool_var, (void *)&hw_opt_use_gl, NULL, "Disable OpenGL" }, { "-bpp", 1, options_set_int_var, (void *)&hw_opt_bpp, "BPP", "Set bits/pixel (0 = autodetect)" }, { "-filt", 1, options_set_int_var, (void *)&hw_opt_gl_filter, "FILTER", "Set OpenGL filter (0 = nearest, 1 = linear)" }, #endif /* HAVE_SDL1GL */ { NULL, 0, NULL, NULL, NULL, NULL } }; void hw_opt_menu_make_page_video(void) { menu_make_bool(menu_item_force_restart(menu_allocate_item()), "Borderless", &hw_opt_borderless, MOO_KEY_o); menu_make_bool_func(menu_allocate_item(), "Fullscreen", &hw_opt_fullscreen, hw_video_toggle_fullscreen, MOO_KEY_f); #ifdef HAVE_SDLX_ASPECT menu_make_str_func(menu_allocate_item(), "Aspect ratio", hw_uiopt_cb_aspect_get, hw_uiopt_cb_aspect_next, MOO_KEY_a); #endif #ifdef HAVE_SDL1GL menu_make_str_func(menu_allocate_item(), "Filter", hw_uiopts_filter_get, hw_uiopts_filter_next, MOO_KEY_i); #endif /* HAVE_SDL1GL */ } 1oom-1.11.2/src/hw/sdl/1/hwsdl1_video.c000066400000000000000000000357151476061725400173610ustar00rootroot00000000000000#include "config.h" #include #include #include "SDL.h" #ifdef HAVE_SDL1GL #include "SDL_opengl.h" #endif #include "hw.h" #include "hwsdl_video.h" #include "hwsdl_mouse.h" #include "hwsdl_opt.h" #include "lib.h" #include "log.h" #include "palette.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* double buffering + 2 aux buffers */ #define NUM_VIDEOBUF 4 static struct sdl_video_s { SDL_Surface *screen; #ifdef HAVE_SDL1GL SDL_Surface *hwrenderbuf; #endif void (*render)(int bufi); void (*update)(void); void (*setpal)(const uint8_t *pal, int first, int num); /* buffers used by UI */ uint8_t *buf[NUM_VIDEOBUF]; int bufw; int bufh; int bufi; #ifdef HAVE_SDL1GL /* precalculated palette for used >8 bpp */ union { uint8_t p8[256 * 3]; uint32_t p32[256]; } ppal; int bpp; int rgb_mode; int rsize, gsize, bsize; int actual_w, actual_h; #endif /* "best" video mode reported by SDL */ struct { int w, h, bpp; } bestmode; } video = { 0 }; /* -------------------------------------------------------------------------- */ #include "hwsdl_video.c" /* -------------------------------------------------------------------------- */ static void video_render_8bpp(int bufi) { int pitch = video.screen->pitch; Uint8 *p = (Uint8 *)video.screen->pixels; uint8_t *q = video.buf[bufi]; for (int y = 0; y < video.bufh; ++y) { memcpy(p, q, video.bufw); p += pitch; q += video.bufw; } } static void video_update_8bpp(void) { SDL_UpdateRect(video.screen, 0, 0, video.screen->w, video.screen->h); } static void video_setpal_8bpp(const uint8_t *pal, int first, int num) { SDL_Color color[256]; for (int i = first; i < (first + num); ++i) { color[i].r = (*pal << 2) | ((*pal >> 4) & 3); pal++; color[i].g = (*pal << 2) | ((*pal >> 4) & 3); pal++; color[i].b = (*pal << 2) | ((*pal >> 4) & 3); pal++; } SDL_SetColors(video.screen, &color[first], first, num); video_update_8bpp(); } #ifdef HAVE_SDL1GL static void video_render_gl_24bpp(int bufi) { int pitch_skip = (video.bufw * 3) - video.hwrenderbuf->pitch; uint8_t *p = (uint8_t *)video.hwrenderbuf->pixels; uint8_t *q = video.buf[bufi]; for (int y = 0; y < video.bufh; ++y) { for (int x = 0; x < video.bufw; ++x) { uint8_t *c; c = &(video.ppal.p8[*q++ * 3]); *p++ = *c++; *p++ = *c++; *p++ = *c++; } p += pitch_skip; } } static void video_setpal_gl_24bpp(const uint8_t *pal, int f, int num) { for (int i = 0; i < num; ++i) { for (int j = 0; j < 3; ++j) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN video.ppal.p8[(f + i) * 3 + 0] = (pal[i * 3 + 2] << 2) | ((pal[i * 3 + 2] >> 4) & 3); video.ppal.p8[(f + i) * 3 + 1] = (pal[i * 3 + 1] << 2) | ((pal[i * 3 + 1] >> 4) & 3); video.ppal.p8[(f + i) * 3 + 2] = (pal[i * 3 + 0] << 2) | ((pal[i * 3 + 0] >> 4) & 3); #else video.ppal.p8[(f + i) * 3 + 0] = (pal[i * 3 + 0] << 2) | ((pal[i * 3 + 0] >> 4) & 3); video.ppal.p8[(f + i) * 3 + 1] = (pal[i * 3 + 1] << 2) | ((pal[i * 3 + 1] >> 4) & 3); video.ppal.p8[(f + i) * 3 + 2] = (pal[i * 3 + 2] << 2) | ((pal[i * 3 + 2] >> 4) & 3); #endif } } hw_video_refresh(1); } static void video_render_gl_32bpp(int bufi) { int pitch_skip = ((video.bufw * sizeof(Uint32)) - video.hwrenderbuf->pitch) / sizeof(Uint32); Uint32 *p = (Uint32 *)video.hwrenderbuf->pixels; uint8_t *q = video.buf[bufi]; for (int y = 0; y < video.bufh; ++y) { for (int x = 0; x < video.bufw; ++x) { *p++ = video.ppal.p32[*q++]; } p += pitch_skip; } } static void video_update_gl(void) { glClear(GL_COLOR_BUFFER_BIT); glDisable(GL_DEPTH_TEST); glEnable(GL_TEXTURE_RECTANGLE_ARB); glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); { int tbl[] = { GL_NEAREST, GL_LINEAR }; int filter = tbl[hw_opt_gl_filter]; glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, filter); glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, filter); } glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, video.rgb_mode, video.bufw, video.bufh, 0, video.rgb_mode, GL_UNSIGNED_BYTE, video.hwrenderbuf->pixels); glBegin(GL_QUADS); /* Lower Right Of Texture */ glTexCoord2f(0.0f, 0.0f); glVertex2f(-1.0f, 1.0f); /* Upper Right Of Texture */ glTexCoord2f(0.0f, (float)(video.bufh)); glVertex2f(-1.0f, -1.0f); /* Upper Left Of Texture */ glTexCoord2f((float)(video.bufw), (float)(video.bufh)); glVertex2f(1.0f, -1.0f); /* Lower Left Of Texture */ glTexCoord2f((float)(video.bufw), 0.0f); glVertex2f(1.0f, 1.0f); glEnd(); SDL_GL_SwapBuffers(); } static void video_setpal_gl_32bpp(const uint8_t *pal, int f, int num) { for (int i = 0; i < num; ++i) { #if SDL_BYTEORDER == SDL_BIG_ENDIAN video.ppal.p32[f + i] = (palette_6bit_to_8bit(pal[i * 3 + 0]) << 24) | (palette_6bit_to_8bit(pal[i * 3 + 1]) << 16) | (palette_6bit_to_8bit(pal[i * 3 + 2]) << 8) ; #else video.ppal.p32[f + i] = (palette_6bit_to_8bit(pal[i * 3 + 0]) << 0) | (palette_6bit_to_8bit(pal[i * 3 + 1]) << 8) | (palette_6bit_to_8bit(pal[i * 3 + 2]) << 16) ; #endif } hw_video_refresh(1); } #endif /* HAVE_SDL1GL */ /* -------------------------------------------------------------------------- */ #ifdef HAVE_SDL1GL static void set_viewport(unsigned int src_w, unsigned int src_h, unsigned int dest_w, unsigned int dest_h) { int dest_x = 0, dest_y = 0; if (hw_opt_aspect != 0) { double aspect = ((double)(hw_opt_aspect)) / 1000000.; if (dest_w * src_h < src_w * aspect * dest_h) { dest_y = dest_h; dest_h = (unsigned int)((dest_w * src_h + src_w * aspect / 2) / (src_w * aspect)); dest_y = (dest_y - dest_h) / 2; } else { dest_x = dest_w; dest_w = (unsigned int)((dest_h * src_w * aspect + src_h / 2) / src_h); dest_x = (dest_x - dest_w) / 2; } } glViewport(dest_x, dest_y, dest_w, dest_h); } #endif /* HAVE_SDL1GL */ /* -------------------------------------------------------------------------- */ static int video_sw_set(int w, int h) { int flags; flags = SDL_SWSURFACE | SDL_DOUBLEBUF; if (hw_opt_borderless) { flags |= SDL_NOFRAME; } if (hw_opt_fullscreen) { flags |= SDL_FULLSCREEN; } log_message("SDL_SetVideoMode(%i, %i, %i, 0x%x)\n", w, h, 8, flags); video.screen = SDL_SetVideoMode(w, h, 8, flags); if (!video.screen) { log_error("SDL_SetVideoMode failed: %s\n", SDL_GetError()); return -1; } hw_mouse_set_scale(w, h); return 0; } /* -------------------------------------------------------------------------- */ int hw_video_resize(int w, int h) { #ifdef HAVE_SDL1GL unsigned int actual_w, actual_h; int flags; log_message("SDL: resize %ix%i (%s)\n", w, h, hw_opt_fullscreen ? "full" : "window"); if (!hw_opt_use_gl) { return 0; } if ((w < 0) || (h < 0)) { w = video.bufw; h = video.bufh; } flags = SDL_OPENGL | SDL_RESIZABLE; if (hw_opt_borderless) { flags |= SDL_NOFRAME; } if (hw_opt_fullscreen) { flags |= SDL_FULLSCREEN; if (hw_opt_screen_fsw && hw_opt_screen_fsh) { actual_w = hw_opt_screen_fsw; actual_h = hw_opt_screen_fsh; } else { actual_w = video.bestmode.w; actual_h = video.bestmode.h; } } else { hw_opt_screen_winw = actual_w = w; hw_opt_screen_winh = actual_h = h; } SDL_GL_SetAttribute(SDL_GL_RED_SIZE, video.rsize); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, video.gsize); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, video.bsize); log_message("SDL_SetVideoMode(%i, %i, %i, 0x%x)\n", actual_w, actual_h, video.bpp, flags); video.screen = SDL_SetVideoMode(actual_w, actual_h, video.bpp, flags); if (!video.screen) { log_error("SDL_SetVideoMode failed!\n"); log_error("Resize %s failed. Run with -%s or set width/height with -%sw W -%sh H.\n", hw_opt_fullscreen ? "fullscreen" : "window", hw_opt_fullscreen ? "window" : "fs", hw_opt_fullscreen ? "fs" : "win", hw_opt_fullscreen ? "fs" : "win" ); goto fail; } set_viewport(video.bufw, video.bufh, actual_w, actual_h); if (hw_opt_fullscreen) { hw_mouse_grab(); } hw_mouse_set_scale(actual_w, actual_h); video.actual_w = actual_w; video.actual_h = actual_h; return 0; fail: return -1; #else return 0; #endif } void hw_video_shrink(void) { } void hw_video_enlarge(void) { } bool hw_video_toggle_fullscreen(void) { int (*func)(int, int) = video_sw_set; #ifdef HAVE_SDL1GL if (hw_opt_use_gl) { func = hw_video_resize; } #endif /* HAVE_SDL1GL */ hw_opt_fullscreen = !hw_opt_fullscreen; if (func(hw_opt_screen_winw, hw_opt_screen_winh)) { hw_opt_fullscreen = !hw_opt_fullscreen; /* restore the setting for the config file */ return false; } #ifdef HAVE_SDL1GL if (!hw_opt_use_gl) #endif /* HAVE_SDL1GL */ { hw_video_refresh_palette(); } return true; } #ifdef HAVE_SDL1GL bool hw_video_update_aspect(void) { return (hw_video_resize(video.actual_w, video.actual_h) == 0); } #endif int hw_video_init(int w, int h) { hw_mouse_set_limits(w, h); video.bufw = w; video.bufh = h; { const SDL_VideoInfo *p = SDL_GetVideoInfo(); video.bestmode.w = p->current_w; video.bestmode.h = p->current_h; video.bestmode.bpp = p->vfmt->BitsPerPixel; log_message("SDL_GetVideoInfo -> %ix%i %ibpp\n", video.bestmode.w, video.bestmode.h, video.bestmode.bpp); } #ifdef HAVE_SDL1GL if (!hw_opt_use_gl) #endif { video.render = video_render_8bpp; video.update = video_update_8bpp; video.setpal = video_setpal_8bpp; if (video_sw_set(w, h)) { return -1; } } #ifdef HAVE_SDL1GL else { int texturebpp; Uint32 rmask, gmask, bmask, amask; #if SDL_BYTEORDER == SDL_BIG_ENDIAN rmask = 0xff000000; gmask = 0x00ff0000; bmask = 0x0000ff00; amask = 0x000000ff; #else rmask = 0x000000ff; gmask = 0x0000ff00; bmask = 0x00ff0000; amask = 0xff000000; #endif if (hw_opt_bpp != 0) { video.bpp = hw_opt_bpp; } else { video.bpp = video.bestmode.bpp; } video.rsize = 8; video.gsize = 8; video.bsize = 8; video.render = video_render_gl_24bpp; video.setpal = video_setpal_gl_24bpp; video.rgb_mode = GL_RGB; texturebpp = 24; switch (video.bpp) { case 15: video.rsize = 5; video.gsize = 5; video.bsize = 5; amask = 0; break; case 16: video.rsize = 5; video.gsize = 6; video.bsize = 5; amask = 0; break; case 24: amask = 0; break; case 32: video.render = video_render_gl_32bpp; video.setpal = video_setpal_gl_32bpp; video.rgb_mode = GL_RGBA; texturebpp = 32; break; default: log_error("SDL: %ibpp is unsupported, choose another with -bpp N or use -nogl\n", video.bpp); return -1; } video.update = video_update_gl; log_message("SDL_CreateRGBSurface(SDL_SWSURFACE, %i, %i, %i, 0x%x, 0x%x, 0x%x, 0x%x)\n", w, h, texturebpp, rmask, gmask, bmask, amask); video.hwrenderbuf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, texturebpp, rmask, gmask, bmask, amask); if (!video.hwrenderbuf) { log_error("SDL_CreateRGBSurface failed!\n"); log_error("Run with -nogl to disable OpenGL.\n"); return -1; } if ((video.hwrenderbuf->pitch % sizeof(Uint32)) != 0) { log_warning("SDL renderbuf pitch mod %i == %i\n", sizeof(Uint32), video.hwrenderbuf->pitch); } if (video_check_opt_screen_winwh() == 0) { w = hw_opt_screen_winw; h = hw_opt_screen_winh; } else { int scale = (video.bestmode.w - 50/*window borders*/) / video.bufw + 1; if (scale > 1) { do { --scale; h = video.bufh * scale; if (hw_opt_aspect != 0) { h = (int)(((double)(h) * 1000000.) / ((double)(hw_opt_aspect))); } } while ((scale > 1) && ((h + 50/*space for window borders, taskbar etc*/) > video.bestmode.h)); w = video.bufw * scale; } } if (hw_video_resize(w, h)) { return -1; } } #endif video.buf[0] = lib_malloc(video.bufw * video.bufh * NUM_VIDEOBUF); for (int i = 1; i < NUM_VIDEOBUF; ++i) { video.buf[i] = video.buf[0] + video.bufw * video.bufh * i; } video.bufi = 0; return 0; } void hw_video_shutdown(void) { if (video.screen) { SDL_FreeSurface(video.screen); video.screen = NULL; } #ifdef HAVE_SDL1GL if (video.hwrenderbuf) { SDL_FreeSurface(video.hwrenderbuf); video.hwrenderbuf = NULL; } #endif lib_free(video.buf[0]); for (int i = 0; i < NUM_VIDEOBUF; ++i) { video.buf[i] = NULL; } } void hw_video_input_grab(bool grab) { SDL_WM_GrabInput(grab ? SDL_GRAB_ON : SDL_GRAB_OFF); } int hw_icon_set(const uint8_t *data, const uint8_t *pal, int w, int h) { SDL_Color color[256]; SDL_Surface *icon; Uint8 *mask = 0; Uint8 *p; uint8_t maxb = 0; uint32_t mi = 0; icon = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); if (!icon) { log_error("Icon: SDL_CreateRGBSurface failed!\n"); return -1; } mask = lib_malloc((w * h + 7) / 8); p = (Uint8 *)icon->pixels; mi = 0; for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uint8_t b; b = *data++; p[x] = b; if (b) { mask[mi >> 3] |= (1 << (7 - (mi & 7))); if (b > maxb) { maxb = b; } } ++mi; } p += icon->pitch; } for (int i = 0; i < 256; ++i) { color[i].r = *pal++ << 2; color[i].g = *pal++ << 2; color[i].b = *pal++ << 2; } SDL_SetColors(icon, color, 0, maxb + 1); SDL_WM_SetIcon(icon, mask); SDL_FreeSurface(icon); icon = NULL; lib_free(mask); mask = NULL; return 0; } 1oom-1.11.2/src/hw/sdl/2/000077500000000000000000000000001476061725400146135ustar00rootroot000000000000001oom-1.11.2/src/hw/sdl/2/Makefile.am000066400000000000000000000004221476061725400166450ustar00rootroot00000000000000AM_CFLAGS=@HW_SDL2_CFLAGS@ AM_CPPFLAGS = \ -I$(top_srcdir)/src \ -I$(top_srcdir)/src/hw/sdl noinst_LIBRARIES = libhwsdl2.a libhwsdl2_a_SOURCES = \ hwsdl2.c \ hwsdl2_audio.c \ hwsdl2_mouse.c \ hwsdl2_opt.c \ hwsdl2_video.c \ hwsdl2_video.h 1oom-1.11.2/src/hw/sdl/2/hwsdl2.c000066400000000000000000000350721476061725400161710ustar00rootroot00000000000000#include "config.h" #include #include #ifdef HAVE_SDLMAIN #include "SDL_main.h" #endif #include "SDL.h" #include "SDL_keycode.h" #include "hw.h" #include "hwsdl_audio.h" #include "hwsdl_mouse.h" #include "hwsdl_opt.h" #include "hwsdl_video.h" #include "hwsdl2_video.h" #include "kbd.h" #include "log.h" #include "main.h" #include "mouse.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ const char *idstr_hw = "sdl2"; /* -------------------------------------------------------------------------- */ static mookey_t key_xlat_key[0x80]; static mookey_t key_xlat_scan[SDL_NUM_SCANCODES]; static char key_xlat_char[SDL_NUM_SCANCODES]; #define SDLK_TBLI_FROM_SCAN(i) ((i) & (~SDLK_SCANCODE_MASK)) static void build_key_xlat(void) { memset(key_xlat_key, 0, sizeof(key_xlat_key)); memset(key_xlat_scan, 0, sizeof(key_xlat_scan)); memset(key_xlat_char, 0, sizeof(key_xlat_char)); key_xlat_key[SDLK_BACKSPACE] = MOO_KEY_BACKSPACE; key_xlat_key[SDLK_TAB] = MOO_KEY_TAB; key_xlat_key[SDLK_RETURN] = MOO_KEY_RETURN; key_xlat_key[SDLK_ESCAPE] = MOO_KEY_ESCAPE; key_xlat_key[SDLK_SPACE] = MOO_KEY_SPACE; key_xlat_key[SDLK_EXCLAIM] = MOO_KEY_EXCLAIM; key_xlat_key[SDLK_QUOTEDBL] = MOO_KEY_QUOTEDBL; key_xlat_key[SDLK_HASH] = MOO_KEY_HASH; key_xlat_key[SDLK_DOLLAR] = MOO_KEY_DOLLAR; key_xlat_key[SDLK_AMPERSAND] = MOO_KEY_AMPERSAND; key_xlat_key[SDLK_QUOTE] = MOO_KEY_QUOTE; key_xlat_key[SDLK_LEFTPAREN] = MOO_KEY_LEFTPAREN; key_xlat_key[SDLK_RIGHTPAREN] = MOO_KEY_RIGHTPAREN; key_xlat_key[SDLK_ASTERISK] = MOO_KEY_ASTERISK; key_xlat_key[SDLK_PLUS] = MOO_KEY_PLUS; key_xlat_key[SDLK_COMMA] = MOO_KEY_COMMA; key_xlat_key[SDLK_MINUS] = MOO_KEY_MINUS; key_xlat_key[SDLK_PERIOD] = MOO_KEY_PERIOD; key_xlat_key[SDLK_SLASH] = MOO_KEY_SLASH; key_xlat_key[SDLK_0] = MOO_KEY_0; key_xlat_key[SDLK_1] = MOO_KEY_1; key_xlat_key[SDLK_2] = MOO_KEY_2; key_xlat_key[SDLK_3] = MOO_KEY_3; key_xlat_key[SDLK_4] = MOO_KEY_4; key_xlat_key[SDLK_5] = MOO_KEY_5; key_xlat_key[SDLK_6] = MOO_KEY_6; key_xlat_key[SDLK_7] = MOO_KEY_7; key_xlat_key[SDLK_8] = MOO_KEY_8; key_xlat_key[SDLK_9] = MOO_KEY_9; key_xlat_key[SDLK_COLON] = MOO_KEY_COLON; key_xlat_key[SDLK_SEMICOLON] = MOO_KEY_SEMICOLON; key_xlat_key[SDLK_LESS] = MOO_KEY_LESS; key_xlat_key[SDLK_EQUALS] = MOO_KEY_EQUALS; key_xlat_key[SDLK_GREATER] = MOO_KEY_GREATER; key_xlat_key[SDLK_QUESTION] = MOO_KEY_QUESTION; key_xlat_key[SDLK_AT] = MOO_KEY_AT; key_xlat_key[SDLK_LEFTBRACKET] = MOO_KEY_LEFTBRACKET; key_xlat_key[SDLK_BACKSLASH] = MOO_KEY_BACKSLASH; key_xlat_key[SDLK_RIGHTBRACKET] = MOO_KEY_RIGHTBRACKET; key_xlat_key[SDLK_CARET] = MOO_KEY_CARET; key_xlat_key[SDLK_UNDERSCORE] = MOO_KEY_UNDERSCORE; key_xlat_key[SDLK_BACKQUOTE] = MOO_KEY_BACKQUOTE; key_xlat_key[SDLK_a] = MOO_KEY_a; key_xlat_key[SDLK_b] = MOO_KEY_b; key_xlat_key[SDLK_c] = MOO_KEY_c; key_xlat_key[SDLK_d] = MOO_KEY_d; key_xlat_key[SDLK_e] = MOO_KEY_e; key_xlat_key[SDLK_f] = MOO_KEY_f; key_xlat_key[SDLK_g] = MOO_KEY_g; key_xlat_key[SDLK_h] = MOO_KEY_h; key_xlat_key[SDLK_i] = MOO_KEY_i; key_xlat_key[SDLK_j] = MOO_KEY_j; key_xlat_key[SDLK_k] = MOO_KEY_k; key_xlat_key[SDLK_l] = MOO_KEY_l; key_xlat_key[SDLK_m] = MOO_KEY_m; key_xlat_key[SDLK_n] = MOO_KEY_n; key_xlat_key[SDLK_o] = MOO_KEY_o; key_xlat_key[SDLK_p] = MOO_KEY_p; key_xlat_key[SDLK_q] = MOO_KEY_q; key_xlat_key[SDLK_r] = MOO_KEY_r; key_xlat_key[SDLK_s] = MOO_KEY_s; key_xlat_key[SDLK_t] = MOO_KEY_t; key_xlat_key[SDLK_u] = MOO_KEY_u; key_xlat_key[SDLK_v] = MOO_KEY_v; key_xlat_key[SDLK_w] = MOO_KEY_w; key_xlat_key[SDLK_x] = MOO_KEY_x; key_xlat_key[SDLK_y] = MOO_KEY_y; key_xlat_key[SDLK_z] = MOO_KEY_z; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_CAPSLOCK)] = MOO_KEY_CAPSLOCK; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F1)] = MOO_KEY_F1; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F2)] = MOO_KEY_F2; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F3)] = MOO_KEY_F3; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F4)] = MOO_KEY_F4; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F5)] = MOO_KEY_F5; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F6)] = MOO_KEY_F6; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F7)] = MOO_KEY_F7; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F8)] = MOO_KEY_F8; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F9)] = MOO_KEY_F9; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F10)] = MOO_KEY_F10; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F11)] = MOO_KEY_F11; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F12)] = MOO_KEY_F12; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_SCROLLLOCK)] = MOO_KEY_SCROLLOCK; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_PAUSE)] = MOO_KEY_PAUSE; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_INSERT)] = MOO_KEY_INSERT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_HOME)] = MOO_KEY_HOME; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_PAGEUP)] = MOO_KEY_PAGEUP; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_DELETE)] = MOO_KEY_DELETE; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_END)] = MOO_KEY_END; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_PAGEDOWN)] = MOO_KEY_PAGEDOWN; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_RIGHT)] = MOO_KEY_RIGHT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_LEFT)] = MOO_KEY_LEFT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_DOWN)] = MOO_KEY_DOWN; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_UP)] = MOO_KEY_UP; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_CLEAR)] = MOO_KEY_CLEAR; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F13)] = MOO_KEY_F13; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F14)] = MOO_KEY_F14; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_F15)] = MOO_KEY_F15; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_0)] = MOO_KEY_KP0; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_1)] = MOO_KEY_KP1; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_2)] = MOO_KEY_KP2; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_3)] = MOO_KEY_KP3; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_4)] = MOO_KEY_KP4; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_5)] = MOO_KEY_KP5; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_6)] = MOO_KEY_KP6; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_7)] = MOO_KEY_KP7; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_8)] = MOO_KEY_KP8; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_9)] = MOO_KEY_KP9; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_PERIOD)] = MOO_KEY_KP_PERIOD; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_DIVIDE)] = MOO_KEY_KP_DIVIDE; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_MULTIPLY)] = MOO_KEY_KP_MULTIPLY; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_MINUS)] = MOO_KEY_KP_MINUS; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_PLUS)] = MOO_KEY_KP_PLUS; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_ENTER)] = MOO_KEY_RETURN; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_KP_EQUALS)] = MOO_KEY_KP_EQUALS; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_NUMLOCKCLEAR)] = MOO_KEY_NUMLOCK; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_RSHIFT)] = MOO_KEY_RSHIFT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_LSHIFT)] = MOO_KEY_LSHIFT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_RCTRL)] = MOO_KEY_RCTRL; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_LCTRL)] = MOO_KEY_LCTRL; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_RALT)] = MOO_KEY_RALT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_LALT)] = MOO_KEY_LALT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_LGUI)] = MOO_KEY_LSUPER; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_RGUI)] = MOO_KEY_RSUPER; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_MODE)] = MOO_KEY_MODE; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_HELP)] = MOO_KEY_HELP; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_PRINTSCREEN)] = MOO_KEY_PRINT; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_SYSREQ)] = MOO_KEY_SYSREQ; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_MENU)] = MOO_KEY_MENU; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_POWER)] = MOO_KEY_POWER; key_xlat_scan[SDLK_TBLI_FROM_SCAN(SDLK_UNDO)] = MOO_KEY_UNDO; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_PERIOD)] = SDLK_PERIOD; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_DIVIDE)] = SDLK_SLASH; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_MULTIPLY)] = SDLK_ASTERISK; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_MINUS)] = SDLK_MINUS; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_PLUS)] = SDLK_PLUS; key_xlat_char[SDLK_TBLI_FROM_SCAN(SDLK_KP_EQUALS)] = SDLK_EQUALS; } static inline uint32_t mod_xlat(SDL_Keymod smod) { uint32_t mod = 0; if (smod & KMOD_SHIFT) { mod |= MOO_MOD_SHIFT; } if (smod & KMOD_ALT) { mod |= MOO_MOD_ALT; } if (smod & KMOD_CTRL) { mod |= MOO_MOD_CTRL; } return mod; } static bool hw_textinput_active = false; static bool hw_key_press_repeat_active = true; /* -------------------------------------------------------------------------- */ #define SDL1or2Key SDL_Keycode #define SDL1or2Mod SDL_Keymod #include "hwsdl.c" /* -------------------------------------------------------------------------- */ static void hw_event_handle_window(SDL_WindowEvent *e) { switch (e->event) { case SDL_WINDOWEVENT_RESIZED: hw_video_resize(0, 0); break; case SDL_WINDOWEVENT_EXPOSED: hw_video_update(); break; case SDL_WINDOWEVENT_FOCUS_LOST: hw_mouse_ungrab(); break; case SDL_WINDOWEVENT_MINIMIZED: hw_video_set_visible(false); break; case SDL_WINDOWEVENT_MAXIMIZED: case SDL_WINDOWEVENT_RESTORED: hw_video_set_visible(true); break; default: break; } } /* -------------------------------------------------------------------------- */ int main(int argc, char **argv) { return main_1oom(argc, argv); } int hw_early_init(void) { return 0; } int hw_init(void) { int flags = SDL_INIT_VIDEO | (opt_audio_enabled ? SDL_INIT_AUDIO : 0); log_message("SDL_Init\n"); if (SDL_Init(flags) < 0) { log_error("SDL_Init(0x%x) failed: %s\n", flags, SDL_GetError()); return 11; } if (hw_audio_init()) { return 12; } build_key_xlat(); if (hw_opt_relmouse) { SDL_EventState(SDL_MOUSEMOTION, SDL_IGNORE); } return 0; } void hw_shutdown(void) { hw_audio_shutdown(); hw_video_shutdown(); log_message("SDL_Quit\n"); SDL_Quit(); } void hw_textinput_start(void) { SDL_StartTextInput(); hw_textinput_active = true; } void hw_textinput_stop(void) { SDL_StopTextInput(); hw_textinput_active = false; } int hw_event_handle(void) { SDL_Event e; SDL_PumpEvents(); while (SDL_PollEvent(&e)) { switch (e.type) { uint32_t mod; case SDL_KEYDOWN: if (e.key.repeat && !hw_key_press_repeat_active) { break; } { SDL_Keycode sym; SDL_Keymod smod; char c; sym = e.key.keysym.sym; smod = e.key.keysym.mod; c = 0; if (!(hw_kbd_check_hotkey(sym, smod, c))) { mookey_t key; if (sym & SDLK_SCANCODE_MASK) { key = key_xlat_scan[SDLK_TBLI_FROM_SCAN(sym)]; c = 0; if (!hw_textinput_active) { c = key_xlat_char[SDLK_TBLI_FROM_SCAN(sym)]; } } else { key = key_xlat_key[sym]; c = (char)sym; /* TODO SDL 2 */ /* ignore ASCII range when expecting SDL_TEXTINPUT */ if (hw_textinput_active && ((key >= MOO_KEY_SPACE) && (key <= MOO_KEY_z))) { key = MOO_KEY_LAST; } } mod = mod_xlat(smod); if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) mod |= MOO_MOD_CTRL; if ((key != MOO_KEY_UNKNOWN) && (key < MOO_KEY_LAST)) { kbd_add_keypress(key, mod, c); } kbd_set_pressed(key, mod, true); } } break; case SDL_KEYUP: { SDL_Keycode sym; SDL_Keymod smod; mookey_t key; sym = e.key.keysym.sym; smod = e.key.keysym.mod; mod = mod_xlat(smod); if (sym == SDLK_LCTRL || sym == SDLK_RCTRL) mod &= ~MOO_MOD_CTRL; if (sym & SDLK_SCANCODE_MASK) { key = key_xlat_scan[SDLK_TBLI_FROM_SCAN(sym)]; } else { key = key_xlat_key[sym]; } kbd_set_pressed(key, mod, false); } break; case SDL_TEXTINPUT: if (hw_textinput_active && (e.text.text[0] != 0)) { char c = e.text.text[0]; SDL_StopTextInput(); SDL_StartTextInput(); kbd_add_keypress(MOO_KEY_UNKNOWN, 0, c); } break; case SDL_MOUSEMOTION: if (!hw_opt_relmouse && hw_mouse_enabled) { mouse_set_xy_from_hw(e.motion.x, e.motion.y); } break; case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONUP: hw_mouse_button((int)(e.button.button), (e.button.state == SDL_PRESSED)); break; case SDL_MOUSEWHEEL: if (e.wheel.y != 0) { hw_mouse_scroll((e.wheel.y > 0) ? -1 : 1); } break; case SDL_QUIT: hw_audio_shutdown_pre(); exit(EXIT_SUCCESS); break; case SDL_WINDOWEVENT: if (e.window.windowID == hw_video_get_window_id()) { hw_event_handle_window(&e.window); } default: break; } } if (hw_opt_relmouse) { int x, y; SDL_GetRelativeMouseState(&x, &y); if (hw_mouse_enabled) { if ((x != 0) || (y != 0)) { hw_mouse_move(x, y); } } } if (hw_audio_check_process()) { exit(EXIT_FAILURE); } SDL_Delay(10); return 0; } bool hw_kbd_set_repeat(bool enabled) { hw_key_press_repeat_active = enabled; return true; } 1oom-1.11.2/src/hw/sdl/2/hwsdl2_audio.c000066400000000000000000000004361476061725400173460ustar00rootroot00000000000000#include "config.h" #ifdef HAVE_SDL2MIXER #define HAVE_SDLMIXER #include "SDL.h" #include "SDL_mixer.h" #include "SDL_rwops.h" #define USE_SFX_INIT_THREAD #define HWSDLX_CreateThread(_func_) SDL_CreateThread(_func_, "SFX init", 0) #endif /* HAVE_SDL2MIXER */ #include "hwsdl_audio.c" 1oom-1.11.2/src/hw/sdl/2/hwsdl2_mouse.c000066400000000000000000000004211476061725400173670ustar00rootroot00000000000000#include "config.h" #include "types.h" #include "SDL.h" #include "hwsdl2_video.h" #include "hwsdl_mouse.c" void hw_mouse_set_xy(int mx, int my) { if (hw_opt_relmouse) { mouse_set_xy_from_hw(mx, my); } else { hw_video_mouse_warp(mx, my); } } 1oom-1.11.2/src/hw/sdl/2/hwsdl2_opt.c000066400000000000000000000076221476061725400170530ustar00rootroot00000000000000#include "config.h" #include #include #include "hw.h" #include "cfg.h" #include "hwsdl_opt.h" #include "hwsdl_audio.h" #include "hwsdl_video.h" #include "hwsdl2_video.h" #include "lib.h" #include "menu.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define HW_DEFAULT_FULLSCREEN false #define HAVE_SDLX_ASPECT bool hw_opt_force_sw = false; bool hw_opt_int_scaling = false; #if SDL_VERSION_ATLEAST(2, 0, 18) bool hw_opt_relmouse = false; #else bool hw_opt_relmouse = true; #endif bool hw_opt_autotrim = true; bool hw_opt_vsync = true; bool hw_opt_allow_upscaling = true; int hw_opt_scaling_quality = 0; #ifdef HAVE_SDL2MIXER #define HAVE_SDLMIXER #endif /* HAVE_SDL2MIXER */ #if SDL_VERSION_ATLEAST(2, 0, 12) static const char *hw_scaling_quality_str[3] = { "Nearest", "Linear", "Best" }; static const char *hw_uiopts_scaling_quality_get(void) { return hw_scaling_quality_str[hw_opt_scaling_quality]; } #endif /* -------------------------------------------------------------------------- */ const struct cfg_items_s hw_cfg_items_extra[] = { CFG_ITEM_BOOL("force_sw", &hw_opt_force_sw), CFG_ITEM_BOOL("int_scaling", &hw_opt_int_scaling), CFG_ITEM_BOOL("relmouse", &hw_opt_relmouse), CFG_ITEM_BOOL("autotrim", &hw_opt_autotrim), CFG_ITEM_BOOL("vsync", &hw_opt_vsync), CFG_ITEM_BOOL("allow_upscaling", &hw_opt_allow_upscaling), CFG_ITEM_INT("scaling_quality", &hw_opt_scaling_quality, 0), CFG_ITEM_END }; #include "hwsdl_opt.c" const struct cmdline_options_s hw_cmdline_options_extra[] = { { "-forcesw", 0, options_enable_bool_var, (void *)&hw_opt_force_sw, NULL, "Force software rendering" }, { "-noforcesw", 0, options_disable_bool_var, (void *)&hw_opt_force_sw, NULL, "Do not force software rendering" }, { "-intscaling", 0, options_enable_bool_var, (void *)&hw_opt_int_scaling, NULL, "Force integer scaling" }, { "-nointscaling", 0, options_disable_bool_var, (void *)&hw_opt_int_scaling, NULL, "Do not force integer scaling" }, { "-relmouse", 0, options_enable_bool_var, (void *)&hw_opt_relmouse, NULL, "Use relative mouse mode (default)" }, { "-norelmouse", 0, options_disable_bool_var, (void *)&hw_opt_relmouse, NULL, "Do not use relative mouse mode" }, { "-autotrim", 0, options_enable_bool_var, &hw_opt_autotrim, NULL, "Enable automatic resize" }, { "-noautotrim", 0, options_disable_bool_var, &hw_opt_autotrim, NULL, "Disable automatic resize" }, { "-vsync", 0, options_enable_bool_var, &hw_opt_vsync, NULL, "Enable V-sync" }, { "-novsync", 0, options_disable_bool_var, &hw_opt_vsync, NULL, "Disable V-sync" }, { "-filt", 1, options_set_int_var, (void *)&hw_opt_scaling_quality, "FILTER", "Set scaling quality (0 = nearest, 1 = linear, 2 = best)" }, { NULL, 0, NULL, NULL, NULL, NULL } }; void hw_opt_menu_make_page_video(void) { menu_make_bool_func(menu_allocate_item(), "Borderless", &hw_opt_borderless, hw_video_toggle_borderless, MOO_KEY_o); menu_make_bool_func(menu_allocate_item(), "Fullscreen", &hw_opt_fullscreen, hw_video_toggle_fullscreen, MOO_KEY_f); #ifdef HAVE_SDLX_ASPECT menu_make_str_func(menu_allocate_item(), "Aspect ratio", hw_uiopt_cb_aspect_get, hw_uiopt_cb_aspect_next, MOO_KEY_a); #endif #if SDL_VERSION_ATLEAST(2, 0, 18) menu_make_bool_func(menu_allocate_item(), "V-sync", &hw_opt_vsync, hw_video_toggle_vsync, MOO_KEY_v); #endif #if SDL_VERSION_ATLEAST(2, 0, 5) menu_make_bool_func(menu_allocate_item(), "Integer scaling", &hw_opt_int_scaling, hw_video_toggle_int_scaling, MOO_KEY_i); #endif #if SDL_VERSION_ATLEAST(2, 0, 12) menu_make_str_func(menu_allocate_item(), "Filter", hw_uiopts_scaling_quality_get, hw_video_filter_next, MOO_KEY_i); #endif } 1oom-1.11.2/src/hw/sdl/2/hwsdl2_video.c000066400000000000000000000640741476061725400173630ustar00rootroot00000000000000#include "config.h" #include #include #include "SDL.h" #include "hw.h" #include "comp.h" #include "hwsdl_video.h" #include "hwsdl_mouse.h" #include "hwsdl_opt.h" #include "lib.h" #include "log.h" #include "mouse.h" #include "palette.h" #include "types.h" #include "version.h" /* -------------------------------------------------------------------------- */ /* Most of the code and comments adapted from Chocolate Doom 3.0 i_video.c. Copyright(C) 2005-2014 Simon Howard */ /* -------------------------------------------------------------------------- */ /* double buffering + 2 aux buffers */ #define NUM_VIDEOBUF 4 #define RESIZE_DELAY 500 static struct sdl_video_s { /* These are (1) the window (or the full screen) that our game is rendered to and (2) the renderer that scales the texture (see below) into this window. */ SDL_Window *window; SDL_Renderer *renderer; /* These are (1) the bufw*bufh*8bpp paletted buffer that we copy the active buffer to, (2) the bufw*bufh intermediate buffer of the window/renderer's pixel format that we blit the former buffer to, (3) the intermediate bufw*bufh texture that we update with the intermediate's buffer data, and that we render into another texture (4) which is upscaled by an integer factor UPSCALE using "nearest" scaling and which in turn is finally rendered to screen using "linear" scaling. */ SDL_Surface *screen; SDL_Surface *interbuffer; SDL_Texture *texture; SDL_Texture *texture_upscaled; SDL_Rect blit_rect; uint32_t pixel_format; SDL_Surface *icon; SDL_Palette *iconpal; /* SDL display number on which to run. */ int display; int w_upscale, h_upscale; int actualh; bool noblit; bool need_resize; bool shrink, enlarge; int last_resize_time; void (*render)(int bufi); void (*update)(void); void (*setpal)(const uint8_t *pal, int first, int num); /* buffers used by UI */ uint8_t *buf[NUM_VIDEOBUF]; int bufw; int bufh; int bufi; /* palette as used by SDL */ SDL_Color color[256]; bool palette_to_set; } video = { 0 }; /* -------------------------------------------------------------------------- */ #include "hwsdl_video.c" /* -------------------------------------------------------------------------- */ static void video_create_texture(void) { const char *scaling_quality_str = NULL; if (video.texture != NULL) { SDL_DestroyTexture(video.texture); } /* Set the scaling quality for rendering the intermediate texture into the upscaled texture to "nearest" (by default), which is gritty and pixelated and resembles software scaling pretty well. */ switch (hw_opt_scaling_quality) { case 1: scaling_quality_str = "linear"; break; case 2: scaling_quality_str = "best"; break; default: scaling_quality_str = "nearest"; break; } SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, scaling_quality_str); /* Create the intermediate texture that the RGBA surface gets loaded into. The SDL_TEXTUREACCESS_STREAMING flag means that this texture's content is going to change frequently. */ log_message("SDL_CreateTexture: source, %d, %d, %s\n", video.bufw, video.bufh, scaling_quality_str); video.texture = SDL_CreateTexture(video.renderer, video.pixel_format, SDL_TEXTUREACCESS_STREAMING, video.bufw, video.bufh); } static void video_create_upscaled_texture(bool force) { if (!hw_opt_allow_upscaling || hw_opt_int_scaling) { if (video.texture_upscaled) { SDL_DestroyTexture(video.texture_upscaled); video.texture_upscaled = NULL; video.w_upscale = 0; video.h_upscale = 0; } return; } int w, h; int h_upscale, w_upscale; /* Get the size of the renderer output. The units this gives us will be real world pixels, which are not necessarily equivalent to the screen's window size (because of highdpi). */ if (SDL_GetRendererOutputSize(video.renderer, &w, &h) != 0) { log_fatal_and_die("SDL2: Failed to get renderer output size: %s\n", SDL_GetError()); } /* When the screen or window dimensions do not match the aspect ratio of the texture, the rendered area is scaled down to fit. Calculate the actual dimensions of the rendered area. */ if (w * video.actualh < h * video.bufw) { /* Tall window. */ h = (w * video.actualh) / video.bufw; } else { /* Wide window. */ w = (h * video.bufw) / video.actualh; } if ((w % video.bufw == 0) && (h % video.bufh == 0)) { if (video.texture_upscaled) { SDL_DestroyTexture(video.texture_upscaled); video.texture_upscaled = NULL; video.w_upscale = 0; video.h_upscale = 0; } return; } /* Pick texture size the next integer multiple of the screen dimensions. If one screen dimension matches an integer multiple of the original resolution, there is no need to overscale in this direction. */ w_upscale = (w + video.bufw - 1) / video.bufw; h_upscale = (h + video.bufh - 1) / video.bufh; /* Minimum texture dimensions of 320x200. */ SETMAX(w_upscale, 1); SETMAX(h_upscale, 1); /* LimitTextureSize(&w_upscale, &h_upscale); TODO SDL2 */ /* Create a new texture only if the upscale factors have actually changed. */ if (h_upscale == video.h_upscale && w_upscale == video.w_upscale && !force) { return; } video.h_upscale = h_upscale; video.w_upscale = w_upscale; if (video.texture_upscaled) { SDL_DestroyTexture(video.texture_upscaled); } /* Set the scaling quality for rendering the upscaled texture to "linear", which looks much softer and smoother than "nearest" but does a better job at downscaling from the upscaled texture to screen. */ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear"); log_message("SDL_CreateTexture: upscaled, %d, %d\n", w_upscale * video.bufw, h_upscale * video.bufh); video.texture_upscaled = SDL_CreateTexture(video.renderer, video.pixel_format, SDL_TEXTUREACCESS_TARGET, w_upscale * video.bufw, h_upscale * video.bufh ); } static void video_destroy_renderer(void) { if (video.renderer) { SDL_DestroyRenderer(video.renderer); // all associated textures get destroyed video.renderer = NULL; video.texture = NULL; video.texture_upscaled = NULL; video.w_upscale = 0; video.h_upscale = 0; } } /* -------------------------------------------------------------------------- */ static void video_render(int bufi) { if (video.noblit) { return; } int pitch = video.screen->pitch; Uint8 *p = (Uint8 *)video.screen->pixels; uint8_t *q = video.buf[bufi]; for (int y = 0; y < video.bufh; ++y) { memcpy(p, q, video.bufw); p += pitch; q += video.bufw; } } /* Adjust window_width / window_height variables to be an an aspect ratio consistent with the aspect_ratio_correct variable. */ static void video_adjust_window_size(int *wptr, int *hptr) { if (hw_opt_aspect != 0) { int w = *wptr, h = *hptr; if ((w * video.actualh) <= (h * video.bufw)) { /* We round up window_height if the ratio is not exact; this leaves the result stable. */ h = (w * video.actualh + video.bufw - 1) / video.bufw; } else { w = (h * video.bufw) / video.actualh; } bool do_resize = false; int scale = w / video.bufw; if (video.shrink || video.enlarge) { if (video.shrink) { --scale; if (w % video.bufw) { ++scale; } } else { ++scale; } do_resize = true; } else if (hw_opt_int_scaling) { if (video_check_opt_screen_winwh() == 0) { if ((hw_opt_screen_winw < *wptr) && (hw_opt_screen_winh <= *hptr)) { ++scale; } else if ((hw_opt_screen_winw <= *wptr) && (hw_opt_screen_winh < *hptr)) { ++scale; } } do_resize = true; } if (do_resize) { if (scale <= 0) { scale = 1; } w = video.bufw * scale; h = video.actualh * scale; } *wptr = w; *hptr = h; } } static void video_update(void) { if (video.noblit) { return; } if (video.need_resize) { if (SDL_GetTicks() > (video.last_resize_time + RESIZE_DELAY)) { int flags, w, h; /* When the window is resized (we're not in fullscreen mode and not maximized), save the new window size. */ flags = SDL_GetWindowFlags(video.window); SDL_GetWindowSize(video.window, &w, &h); if ((flags & (SDL_WINDOW_FULLSCREEN_DESKTOP | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_MAXIMIZED)) == 0) { /* Adjust the window by resizing again so that the window is the right aspect ratio. */ if (hw_opt_autotrim || video.shrink || video.enlarge) { video_adjust_window_size(&w, &h); } SDL_SetWindowSize(video.window, w, h); hw_opt_screen_winw = w; hw_opt_screen_winh = h; } hw_mouse_set_scale(w, h); video_create_upscaled_texture(false); video.need_resize = false; video.shrink = false; video.enlarge = false; video.palette_to_set = true; } else { return; } } if (video.palette_to_set) { SDL_SetPaletteColors(video.screen->format->palette, video.color, 0, 256); video.palette_to_set = false; } /* Blit from the paletted 8-bit screen buffer to the intermediate buffer that we can load into the texture. */ SDL_BlitSurface(video.screen, &video.blit_rect, video.interbuffer, &video.blit_rect); /* Update the intermediate texture with the contents of the intermediate buffer.*/ SDL_UpdateTexture(video.texture, NULL, video.interbuffer->pixels, video.interbuffer->pitch); /* Make sure the pillarboxes are kept clear each frame. */ SDL_RenderClear(video.renderer); if (video.texture_upscaled == NULL) { SDL_SetRenderTarget(video.renderer, NULL); SDL_RenderCopy(video.renderer, video.texture, NULL, NULL); SDL_RenderPresent(video.renderer); return; } /* Render this intermediate texture into the upscaled texture using hw_opt_scaling_quality integer scaling. */ SDL_SetRenderTarget(video.renderer, video.texture_upscaled); SDL_RenderCopy(video.renderer, video.texture, NULL, NULL); /* Finally, render this upscaled texture to screen using linear scaling. */ SDL_SetRenderTarget(video.renderer, NULL); SDL_RenderCopy(video.renderer, video.texture_upscaled, NULL, NULL); /* Draw! */ SDL_RenderPresent(video.renderer); } static void video_setpal(const uint8_t *pal, int first, int num) { for (int i = first; i < (first + num); ++i) { video.color[i].r = palette_6bit_to_8bit(*pal++); video.color[i].g = palette_6bit_to_8bit(*pal++); video.color[i].b = palette_6bit_to_8bit(*pal++); video.color[i].a = 255; } video.palette_to_set = true; video_update(); } /* -------------------------------------------------------------------------- */ void hw_video_set_visible(bool visible) { video.noblit = !visible; } #if SDL_VERSION_ATLEAST(2, 0, 18) bool hw_video_toggle_vsync(void) { hw_opt_vsync = !hw_opt_vsync; SDL_RenderSetVSync(video.renderer, hw_opt_vsync); return true; } #endif #if SDL_VERSION_ATLEAST(2, 0, 5) bool hw_video_toggle_int_scaling(void) { hw_opt_int_scaling = !hw_opt_int_scaling; SDL_RenderSetIntegerScale(video.renderer, hw_opt_int_scaling); return true; } #endif #if SDL_VERSION_ATLEAST(2, 0, 12) bool hw_video_filter_next(void) { hw_opt_scaling_quality = (hw_opt_scaling_quality + 1) % 3; SDL_SetTextureScaleMode(video.texture, hw_opt_scaling_quality); return true; } #endif /* -------------------------------------------------------------------------- */ /* Check the display bounds of the display referred to by 'video_display' and set x and y to a location that places the window in the center of that display. */ static void video_center_window(int *x, int *y, int w, int h) { SDL_Rect bounds; if (SDL_GetDisplayBounds(video.display, &bounds) < 0) { log_warning("SDL2: Failed to read display bounds for display #%d!\n", video.display); return; } *x = bounds.x + SDL_max((bounds.w - w) / 2, 0); *y = bounds.y + SDL_max((bounds.h - h) / 2, 0); } static void video_get_window_position(int *x, int *y, int w, int h) { /* TODO SDL2 stored x/y */ *x = SDL_WINDOWPOS_UNDEFINED; *y = SDL_WINDOWPOS_UNDEFINED; /* Check that video_display corresponds to a display that really exists, and if it doesn't, reset it. */ if (video.display < 0 || video.display >= SDL_GetNumVideoDisplays()) { log_warning("SDL2: We were configured to run on display #%d, " "but it no longer exists (max %d). Moving to display 0.\n", video.display, SDL_GetNumVideoDisplays() - 1 ); video.display = 0; } /* in fullscreen mode, the window "position" still matters, because we use it to control which display we run fullscreen on. */ if (hw_opt_fullscreen) { video_center_window(x, y, w, h); } } static void video_window_destroy(void) { video_destroy_renderer(); if (video.window) { SDL_DestroyWindow(video.window); video.window = NULL; } } static int video_sw_set(int w, int h) { int x, y; int window_flags = 0, renderer_flags = 0; SDL_DisplayMode mode; SDL_RendererInfo info; /* In windowed mode, the window can be resized while the game is running. */ window_flags = SDL_WINDOW_RESIZABLE; /* Set the highdpi flag - this makes a big difference on Macs with retina displays, especially when using small window sizes. */ window_flags |= SDL_WINDOW_ALLOW_HIGHDPI; if (hw_opt_borderless) { window_flags |= SDL_WINDOW_BORDERLESS; } if (hw_opt_fullscreen) { if (hw_opt_screen_fsw && hw_opt_screen_fsh) { w = hw_opt_screen_fsw; h = hw_opt_screen_fsh; window_flags |= SDL_WINDOW_FULLSCREEN; } else { window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; } } { int real_w = w, real_h = h; if (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { SDL_Rect bounds; if (SDL_GetDisplayBounds(video.display, &bounds) < 0) { log_warning("SDL2: Failed to read display bounds for display #%d!\n", video.display); } else { real_w = bounds.w; real_h = bounds.h; } } hw_mouse_set_scale(real_w, real_h); } /* Create window and renderer contexts. We leave the window position "undefined". If "window_flags" contains the fullscreen flag (see above), then w and h are ignored. */ video_get_window_position(&x, &y, w, h); if (!video.window) { log_message("SDL_CreateWindow(0, %i, %i, %i, %i, 0x%x)\n", x, y, w, h, window_flags); video.window = SDL_CreateWindow(0, x, y, w, h, window_flags); if (!video.window) { log_error("SDL_CreateWindow failed: %s\n", SDL_GetError()); return -1; } video.pixel_format = SDL_GetWindowPixelFormat(video.window); SDL_SetWindowMinimumSize(video.window, video.bufw, video.actualh); SDL_SetWindowTitle(video.window, PACKAGE_NAME " " VERSION_STR); if (video.icon) { SDL_SetWindowIcon(video.window, video.icon); } } /* The SDL_RENDERER_TARGETTEXTURE flag is required to render the intermediate texture into the upscaled texture. */ renderer_flags = SDL_RENDERER_TARGETTEXTURE; if (SDL_GetCurrentDisplayMode(video.display, &mode) != 0) { log_error("SDL2: Could not get display mode for video display #%d: %s\n", video.display, SDL_GetError()); return -1; } /* Turn on vsync */ if (hw_opt_vsync) { renderer_flags |= SDL_RENDERER_PRESENTVSYNC; } if (hw_opt_force_sw) { renderer_flags |= SDL_RENDERER_SOFTWARE; renderer_flags &= ~SDL_RENDERER_PRESENTVSYNC; } video_destroy_renderer(); video.renderer = SDL_CreateRenderer(video.window, -1, renderer_flags); if (video.renderer == NULL) { log_error("SDL2: Error creating renderer for screen window: %s\n", SDL_GetError()); return -1; } if (!SDL_GetRendererInfo(video.renderer, &info)) { log_message("SDL_GetRendererInfo: %s%s%s\n", info.name, (info.flags & SDL_RENDERER_ACCELERATED) ? ", accelerated" : "", (info.flags & SDL_RENDERER_PRESENTVSYNC) ? ", vsync" : ""); } if (hw_opt_aspect != 0) { /* Important: Set the "logical size" of the rendering context. At the same time this also defines the aspect ratio that is preserved while scaling and stretching the texture into the window. */ SDL_RenderSetLogicalSize(video.renderer, video.bufw, video.actualh); } else { /* Use full window. */ SDL_RenderSetViewport(video.renderer, NULL); } /* Force integer scales for resolution-independent rendering. */ #if SDL_VERSION_ATLEAST(2, 0, 5) SDL_RenderSetIntegerScale(video.renderer, hw_opt_int_scaling); #endif /* Blank out the full screen area in case there is any junk in the borders that won't otherwise be overwritten. */ SDL_SetRenderDrawColor(video.renderer, 0, 0, 0, 255); SDL_RenderClear(video.renderer); SDL_RenderPresent(video.renderer); /* Create the 8-bit paletted screenbuffer surface. */ if (video.screen == NULL) { video.screen = SDL_CreateRGBSurface(0, video.bufw, video.bufh, 8, 0, 0, 0, 0); SDL_FillRect(video.screen, NULL, 0); } /* Format of interbuffer must match the screen pixel format because we copy the surface data into the texture. */ if (video.interbuffer == NULL) { unsigned int rmask, gmask, bmask, amask; int bpp; log_message("video.pixel_format: %s\n", SDL_GetPixelFormatName(video.pixel_format)); if (SDL_PixelFormatEnumToMasks(video.pixel_format, &bpp, &rmask, &gmask, &bmask, &amask)) { log_message("SDL_PixelFormatEnumToMasks(%x) -> %d %x %x %x %x\n", video.pixel_format, bpp, rmask, gmask, bmask, amask); if (bpp < 15) { log_error("Unsupported bits per pixel: %d\n", bpp); return -1; } video.interbuffer = SDL_CreateRGBSurface(0, video.bufw, video.bufh, bpp, rmask, gmask, bmask, amask); if (video.interbuffer == NULL) { log_message("SDL_CreateRGBSurface(): %s\n", SDL_GetError()); return -1; } SDL_FillRect(video.interbuffer, NULL, 0); } else { log_message("SDL_PixelFormatEnumToMasks(%x): %s\n", video.pixel_format, SDL_GetError()); return -1; } } video_create_texture(); /* Initially create the upscaled texture for rendering to screen */ video_create_upscaled_texture(true); if (hw_opt_autotrim) { hw_video_resize(0, 0); } return 0; } static void hw_video_update_actual_h(void) { if (!hw_opt_aspect) { video.actualh = video.bufh; } else { video.actualh = (uint32_t)(video.bufh * 1000000) / hw_opt_aspect; } } /* -------------------------------------------------------------------------- */ int hw_video_get_window_id(void) { return SDL_GetWindowID(video.window); } int hw_video_resize(int w, int h) { video.need_resize = true; video.last_resize_time = SDL_GetTicks(); return 0; } void hw_video_shrink(void) { video.shrink = true; video.enlarge = false; hw_video_resize(0, 0); } void hw_video_enlarge(void) { video.shrink = false; video.enlarge = true; hw_video_resize(0, 0); } bool hw_video_toggle_borderless(void) { hw_opt_borderless = !hw_opt_borderless; video_window_destroy(); if (video_sw_set(hw_opt_screen_winw, hw_opt_screen_winh) != 0) { hw_opt_borderless = !hw_opt_borderless; /* restore the setting for the config file */ return false; } return true; } bool hw_video_toggle_fullscreen(void) { hw_opt_fullscreen = !hw_opt_fullscreen; video_window_destroy(); if (video_sw_set(hw_opt_screen_winw, hw_opt_screen_winh) != 0) { hw_opt_fullscreen = !hw_opt_fullscreen; /* restore the setting for the config file */ return false; } return true; } bool hw_video_update_aspect(void) { hw_video_update_actual_h(); video_window_destroy(); if (video_sw_set(hw_opt_screen_winw, hw_opt_screen_winh) != 0) { return false; } return true; } int hw_video_init(int w, int h) { hw_mouse_set_limits(w, h); video.bufw = w; video.bufh = h; video.window = NULL; video.renderer = NULL; video.screen = NULL; video.interbuffer = NULL; video.texture = NULL; video.texture_upscaled = NULL; video.display = 0; video.w_upscale = 0; video.h_upscale = 0; video.noblit = false; video.need_resize = false; video.shrink = false; video.enlarge = false; video.last_resize_time = 0; video.render = video_render; video.update = video_update; video.setpal = video_setpal; video.blit_rect.x = 0; video.blit_rect.y = 0; video.blit_rect.w = video.bufw; video.blit_rect.h = video.bufh; hw_video_update_actual_h(); SETMAX(h, video.actualh); if (video_check_opt_screen_winwh() == 0) { w = hw_opt_screen_winw; h = hw_opt_screen_winh; } else { SDL_Rect bounds; if (SDL_GetDisplayUsableBounds(video.display, &bounds) != 0) { log_error("SDL2: Could not get display usable bounds for video display #%d: %s\n", video.display, SDL_GetError()); return -1; } int maxw = bounds.w; int maxh = bounds.h; { int top, left, bottom, right; if (SDL_GetWindowBordersSize(video.window, &top, &left, &bottom, &right) == 0) { maxw -= (left + right); maxh -= (top + bottom); } else { maxw -= 50; maxh -= 50; } } { int scale_w = maxw / video.bufw; int scale_h = maxh / video.actualh; int scale = (scale_w > scale_h) ? scale_h : scale_w; if (scale <= 0) { scale = 1; } w = video.bufw * scale; h = video.actualh * scale; } } if (video_sw_set(w, h)) { return -1; } video.buf[0] = lib_malloc(video.bufw * video.bufh * NUM_VIDEOBUF); for (int i = 1; i < NUM_VIDEOBUF; ++i) { video.buf[i] = video.buf[0] + video.bufw * video.bufh * i; } video.bufi = 0; return 0; } void hw_video_shutdown(void) { video_window_destroy(); if (video.screen) { SDL_FreeSurface(video.screen); video.screen = NULL; } if (video.interbuffer) { SDL_FreeSurface(video.interbuffer); video.interbuffer = NULL; } if (video.icon) { SDL_FreeSurface(video.icon); video.icon = NULL; } if (video.iconpal) { SDL_FreePalette(video.iconpal); video.iconpal = NULL; } lib_free(video.buf[0]); for (int i = 0; i < NUM_VIDEOBUF; ++i) { video.buf[i] = NULL; } } void hw_video_input_grab(bool grab) { SDL_SetWindowGrab(video.window, grab); if (hw_opt_relmouse) { SDL_SetRelativeMouseMode(grab); } else { hw_mouse_set_xy(moouse_x, moouse_y); SDL_ShowCursor(grab ? SDL_DISABLE : SDL_ENABLE); } } void hw_video_mouse_warp(int mx, int my) { #if SDL_VERSION_ATLEAST(2, 0, 18) int x, y; SDL_RenderLogicalToWindow(video.renderer, mx, my, &x, &y); SDL_WarpMouseInWindow(video.window, x, y); #else mouse_set_xy_from_hw(mx, my); #endif } int hw_icon_set(const uint8_t *data, const uint8_t *pal, int w, int h) { SDL_Color color[256]; SDL_Surface *icon; Uint8 *p; video.icon = NULL; icon = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0); if (!icon) { log_error("Icon: SDL_CreateRGBSurface failed!\n"); return -1; } p = (Uint8 *)icon->pixels; for (int y = 0; y < h; ++y) { memcpy(p, data, w); data += w; p += icon->pitch; } for (int i = 0; i < 256; ++i) { color[i].r = palette_6bit_to_8bit(*pal++); color[i].g = palette_6bit_to_8bit(*pal++); color[i].b = palette_6bit_to_8bit(*pal++); color[i].a = 255; } color[0].a = 0; { SDL_Palette *sdlpal; sdlpal = SDL_AllocPalette(256); if (!sdlpal) { log_error("Icon: SDL_AllocPalette failed!\n"); SDL_FreeSurface(icon); return false; } if (SDL_SetPaletteColors(sdlpal, color, 0, 256)) { log_error("Icon: SetPaletteColors failed!\n"); SDL_FreePalette(sdlpal); SDL_FreeSurface(icon); return false; } if (SDL_SetSurfacePalette(icon, sdlpal)) { log_error("Icon: SetSurfacePalette failed! %s\n", SDL_GetError()); SDL_FreePalette(sdlpal); SDL_FreeSurface(icon); return false; } video.iconpal = sdlpal; } video.icon = icon; return 0; } 1oom-1.11.2/src/hw/sdl/2/hwsdl2_video.h000066400000000000000000000005241476061725400173560ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL2_VIDEO_H #define INC_1OOM_HWSDL2_VIDEO_H extern int hw_video_get_window_id(void); extern void hw_video_set_visible(bool visible); extern void hw_video_mouse_warp(int mx, int my); extern bool hw_video_toggle_vsync(void); extern bool hw_video_toggle_int_scaling(void); extern bool hw_video_filter_next(void); #endif 1oom-1.11.2/src/hw/sdl/Makefile.am000066400000000000000000000004641476061725400165120ustar00rootroot00000000000000SUBDIRS = if COMPILE_HW_SDL1 SUBDIRS += 1 endif if COMPILE_HW_SDL2 SUBDIRS += 2 endif DIST_SUBDIRS = 1 2 noinst_HEADERS = \ hwsdl_audio.h \ hwsdl_mouse.h \ hwsdl_opt.h \ hwsdl_video.h EXTRA_DIST = \ hwsdl.c \ hwsdl_audio.c \ hwsdl_mouse.c \ hwsdl_opt.c \ hwsdl_video.c 1oom-1.11.2/src/hw/sdl/hwsdl.c000066400000000000000000000034541476061725400157450ustar00rootroot00000000000000static bool hw_kbd_check_hotkey(SDL1or2Key key, SDL1or2Mod smod, char c) { if ((smod & KMOD_CTRL) && (!(smod & KMOD_ALT))) { if (key == SDLK_ESCAPE) { log_message("SDL: got Ctrl-ESC, quitting now\n"); hw_audio_shutdown_pre(); exit(EXIT_SUCCESS); } else if (key == SDLK_F10) { hw_mouse_toggle_grab(); return true; } else if (key == SDLK_RIGHTBRACKET) { if (smod & KMOD_SHIFT) { hw_audio_music_volume(opt_music_volume + 4); } else { hw_audio_sfx_volume(opt_sfx_volume + 4); } return true; } else if (key == SDLK_LEFTBRACKET) { if (smod & KMOD_SHIFT) { hw_audio_music_volume(opt_music_volume - 4); } else { hw_audio_sfx_volume(opt_sfx_volume - 4); } return true; } } else if ((smod & KMOD_ALT) && (!(smod & KMOD_CTRL))) { if (key == SDLK_RETURN) { if (!hw_video_toggle_fullscreen()) { log_message("SDL: fs toggle failure, quitting now\n"); exit(EXIT_FAILURE); } return true; } else if (key == SDLK_LEFTBRACKET) { hw_video_shrink(); } else if (key == SDLK_RIGHTBRACKET) { hw_video_enlarge(); } } return false; } /* -------------------------------------------------------------------------- */ void hw_log_message(const char *msg) { fputs(msg, stdout); } void hw_log_warning(const char *msg) { fputs(msg, stderr); } void hw_log_error(const char *msg) { fputs(msg, stderr); } /* -------------------------------------------------------------------------- */ int64_t hw_get_time_us(void) { return SDL_GetTicks() * 1000; } 1oom-1.11.2/src/hw/sdl/hwsdl_audio.c000066400000000000000000000413151476061725400171240ustar00rootroot00000000000000#include "config.h" #include #include "hw.h" #include "hwsdl_audio.h" #include "hwsdl_opt.h" #include "log.h" #include "options.h" #include "types.h" #ifdef HAVE_SDLMIXER #include "fmt_mus.h" #include "fmt_sfx.h" #include "lib.h" #endif /* HAVE_SDLMIXER */ /* -------------------------------------------------------------------------- */ #ifdef HAVE_SDLMIXER static bool audio_initialized = false; static int audio_rate = 0; struct sfx_s { Mix_Chunk *chunk; bool pending; }; static int sfx_num = 0; static struct sfx_s *sfxtbl = NULL; static int sfx_playing; #ifdef USE_SFX_INIT_THREAD struct sfx_process_sfx_s { int sfxi; const uint8_t *data; uint32_t len; }; struct sfx_process_s { volatile bool working; volatile bool busy; bool started; int num, sfximax, error, errori; uint32_t t_start; struct sfx_process_sfx_s *tbl; }; static struct sfx_process_s sfx_process = { false, false, false, 0, 0, 0, 0, 0, NULL }; static SDL_Thread *sfx_process_thread = NULL; #endif /* USE_SFX_INIT_THREAD */ struct mus_s { mus_type_t type; Mix_Music *music; Mix_MusicType sdlmtype; uint8_t *buf; /* WAV music files need the data to be kept */ bool loops; }; static int mus_num = 0; static struct mus_s *mustbl = NULL; static int mus_playing; /* -------------------------------------------------------------------------- */ static int get_slice_size(void) { int limit; int n; limit = (opt_audiorate * opt_audioslice_ms) / 1000; /* Try all powers of two, not exceeding the limit. */ for (n = 0; ; ++n) { /* 2^n <= limit < 2^n+1 ? */ if ((1 << (n + 1)) > limit) { return (1 << n); } } /* Should never happen? */ return 1024; } static Mix_MusicType mus_type_to_sdlm(mus_type_t type) { switch (type) { case MUS_TYPE_LBXXMID: case MUS_TYPE_MIDI: return MUS_MID; case MUS_TYPE_WAV: return MUS_WAV; case MUS_TYPE_OGG: return MUS_OGG; case MUS_TYPE_FLAC: return MUS_FLAC; default: return MUS_NONE; } } /* -------------------------------------------------------------------------- */ int hw_audio_init(void) { if (opt_audio_enabled) { int num_output_channels; uint16_t mixer_format; int slice = get_slice_size(); if (Mix_OpenAudio(opt_audiorate, AUDIO_S16SYS, 2, slice) < 0) { log_error("initialising SDL_mixer (%i Hz, slice %i): %s\n", opt_audiorate, slice, Mix_GetError()); goto failnoclose; } if (Mix_QuerySpec(&audio_rate, &mixer_format, &num_output_channels) == 0) { log_error("Failed to read SDL_mixer query spec"); goto fail; } if (num_output_channels != 2) { log_warning("SDL_mixer gave %i output channels instead of 2\n", num_output_channels); } if (audio_rate != opt_audiorate) { log_warning("SDL_mixer gave %i Hz instead of %i Hz\n", audio_rate, opt_audiorate); } Mix_AllocateChannels(1); SDL_PauseAudio(0); sfx_playing = -1; mus_playing = -1; log_message("SDLA: init %i Hz slice %i\n", audio_rate, slice); { const char *sfstr; sfstr = Mix_GetSoundFonts(); if (sfstr) { log_message("SDLA: soundfonts '%s'\n", sfstr); } else { log_message("SDLA: no soundfonts\n"); } } if (hw_opt_sdlmixer_sf) { if (hw_audio_set_sdlmixer_sf(hw_opt_sdlmixer_sf) < 0) { goto fail; } } audio_initialized = true; { int volume; volume = opt_sfx_volume; opt_sfx_volume = -1; hw_audio_sfx_volume(volume); volume = opt_music_volume; opt_music_volume = -1; hw_audio_music_volume(volume); } } return 0; fail: Mix_CloseAudio(); failnoclose: log_error("Audio init failed! Run with -noaudio to play without sound.\n"); return -1; } void hw_audio_shutdown_pre(void) { #ifdef USE_SFX_INIT_THREAD sfx_process.working = false; #endif /* USE_SFX_INIT_THREAD */ } void hw_audio_shutdown(void) { if (audio_initialized) { log_message("SDLA: shutdown\n"); Mix_CloseAudio(); SDL_QuitSubSystem(SDL_INIT_AUDIO); #ifdef USE_SFX_INIT_THREAD sfx_process.working = false; if (sfx_process.busy) { int timeout = 20; while (sfx_process.busy && (--timeout)) { SDL_Delay(100); } if (!timeout) { log_warning("SDLA: timeout waiting for sfx process thread\n"); } } #endif /* USE_SFX_INIT_THREAD */ for (int i = 0; i < sfx_num; ++i) { hw_audio_sfx_release(i); } lib_free(sfxtbl); sfxtbl = NULL; audio_initialized = false; } lib_free(hw_opt_sdlmixer_sf); hw_opt_sdlmixer_sf = NULL; } int hw_audio_set_sdlmixer_sf(const char *path) { log_message("SDLA: setting soundfont to '%s'\n", path); if (Mix_SetSoundFonts(path) < 0) { log_error("SDLA: failed to set soundfonts to '%s'\n", path); return -1; } return 0; } int hw_audio_music_init(int mus_index, const uint8_t *data_in, uint32_t len_in) { const uint8_t *data = NULL; uint8_t *buf = NULL; uint32_t len = 0; struct mus_s *m; if (!audio_initialized) { return 0; } if (mus_index >= mus_num) { int old_mus_num = mus_num; mus_num = (mus_index + 1); mustbl = lib_realloc(mustbl, mus_num * sizeof(struct mus_s)); for (int i = old_mus_num; i < mus_num; ++i) { mustbl[i].type = MUS_TYPE_UNKNOWN; mustbl[i].music = NULL; mustbl[i].buf = NULL; } } m = &mustbl[mus_index]; if (m->type != MUS_TYPE_UNKNOWN) { hw_audio_music_release(mus_index); } m->type = fmt_mus_detect(data_in, len_in); switch (m->type) { case MUS_TYPE_LBXXMID: if (fmt_mus_convert_xmid(data_in, len_in, &buf, &len, &m->loops)) { data = buf; } else { m->type = MUS_TYPE_UNKNOWN; } break; case MUS_TYPE_WAV: if (fmt_sfx_convert(data_in, len_in, &buf, &len, NULL, audio_rate, true)) { data = buf; m->buf = buf; buf = NULL; } else { m->type = MUS_TYPE_UNKNOWN; } m->loops = false; /* FIXME */ break; case MUS_TYPE_UNKNOWN: break; default: data = data_in; len = len_in; m->loops = false; /* FIXME */ break; } m->sdlmtype = mus_type_to_sdlm(m->type); if (m->type == MUS_TYPE_UNKNOWN) { log_error("SDLA: failed to init music %i\n", mus_index); return -1; } { SDL_RWops *rw = SDL_RWFromConstMem(data, len); m->music = Mix_LoadMUSType_RW(rw, m->sdlmtype, 0); SDL_RWclose(rw); } lib_free(buf); if (!m->music) { log_error("SDLA: Mix_LoadMUSType_RW failed on music %i (type %i): %s\n", mus_index, m->type, Mix_GetError()); m->type = MUS_TYPE_UNKNOWN; m->sdlmtype = MUS_NONE; return -1; } return 0; } void hw_audio_music_release(int mus_index) { if (mus_index < mus_num) { if (mus_playing == mus_index) { hw_audio_music_stop(); } if (mustbl[mus_index].music) { Mix_FreeMusic(mustbl[mus_index].music); mustbl[mus_index].music = NULL; } if (mustbl[mus_index].buf) { lib_free(mustbl[mus_index].buf); mustbl[mus_index].buf = NULL; } mustbl[mus_index].type = MUS_TYPE_UNKNOWN; mustbl[mus_index].sdlmtype = MUS_NONE; } } void hw_audio_music_play(int mus_index) { if (audio_initialized && opt_music_enabled && (mus_index < mus_num)) { if (Mix_PlayingMusic()) { Mix_HaltMusic(); } Mix_PlayMusic(mustbl[mus_index].music, mustbl[mus_index].loops ? -1 : 0); Mix_VolumeMusic(opt_music_volume); mus_playing = mus_index; } } void hw_audio_music_fadeout(void) { if (audio_initialized && opt_music_enabled && Mix_PlayingMusic()) { Mix_FadeOutMusic(1000); } } void hw_audio_music_stop(void) { if (audio_initialized && opt_music_enabled) { Mix_HaltMusic(); mus_playing = -1; } } bool hw_audio_music_volume(int volume) { if (volume < 0) { volume = 0; } if (volume > 128) { volume = 128; } if (audio_initialized && opt_music_enabled) { Mix_VolumeMusic(volume); } if (opt_music_volume != volume) { log_message("SDLA: music volume %i\n", volume); opt_music_volume = volume; } return true; } /* -------------------------------------------------------------------------- */ static void hw_audio_sfx_init_alloc(int sfx_index) { if (sfx_index >= sfx_num) { int old_sfx_num = sfx_num; sfx_num = (sfx_index + 1); sfxtbl = lib_realloc(sfxtbl, sfx_num * sizeof(struct sfx_s)); for (int i = old_sfx_num; i < sfx_num; ++i) { sfxtbl[i].chunk = NULL; sfxtbl[i].pending = false; } } } static int hw_audio_sfx_init_do(int sfx_index, const uint8_t *data_in, uint32_t len_in) { uint8_t *data = NULL; uint32_t len = 0; hw_audio_sfx_init_alloc(sfx_index); if (sfxtbl[sfx_index].chunk) { hw_audio_sfx_release(sfx_index); } if (fmt_sfx_convert(data_in, len_in, &data, &len, NULL, audio_rate, true)) { sfxtbl[sfx_index].chunk = Mix_LoadWAV_RW(SDL_RWFromMem(data, len), 0); lib_free(data); sfxtbl[sfx_index].pending = false; } else { sfxtbl[sfx_index].pending = false; return -1; } return 0; } #ifdef USE_SFX_INIT_THREAD static int hw_audio_sfx_init_thread(void *data) { int i, res = 0; for (i = 0; (i < sfx_process.num) && sfx_process.working; ++i) { int sfxi; sfxi = sfx_process.tbl[i].sfxi; if (hw_audio_sfx_init_do(sfxi, sfx_process.tbl[i].data, sfx_process.tbl[i].len)) { sfx_process.error = 1; sfx_process.errori = sfxi; res = -1; break; } } for (; i < sfx_process.num; ++i) { int sfxi; sfxi = sfx_process.tbl[i].sfxi; sfxtbl[sfxi].pending = false; } lib_free(sfx_process.tbl); sfx_process.tbl = NULL; sfx_process.busy = false; sfx_process.working = false; sfx_process_thread = NULL; return res; } #endif /* USE_SFX_INIT_THREAD */ /* -------------------------------------------------------------------------- */ #ifdef USE_SFX_INIT_THREAD int hw_audio_sfx_batch_start(int sfx_index_max) { if ((!audio_initialized) || (!opt_sfx_init_parallel)) { return 0; } if (sfx_process.working) { while (sfx_process.busy) { SDL_Delay(100); hw_audio_check_process(); } } sfx_process.t_start = hw_get_time_us(); hw_audio_sfx_init_alloc(sfx_index_max); if (sfx_process.tbl) { lib_free(sfx_process.tbl); sfx_process.tbl = NULL; } sfx_process.tbl = lib_malloc(sfx_index_max * sizeof(struct sfx_process_sfx_s)); sfx_process.num = 0; sfx_process.sfximax = sfx_index_max; sfx_process.error = 0; sfx_process.errori = 0; hw_audio_sfx_init_alloc(sfx_index_max); sfx_process.started = true; sfx_process.working = false; sfx_process.busy = false; return 1; } int hw_audio_sfx_batch_end(void) { int res; if ((!audio_initialized) || (!opt_sfx_init_parallel)) { return 0; } sfx_process.busy = true; sfx_process.working = true; for (int i = 0; i < sfx_process.num; ++i) { sfxtbl[sfx_process.tbl[i].sfxi].pending = true; } sfx_process_thread = HWSDLX_CreateThread(hw_audio_sfx_init_thread); if (sfx_process_thread == NULL) { log_error("SDLA: Couldn't create thread: %s\n", SDL_GetError()); hw_audio_sfx_init_thread(0); res = 0; } else { log_message("SDLA: created sfx processing thread\n"); res = 1; } return res; } int hw_audio_sfx_init(int sfx_index, const uint8_t *data_in, uint32_t len_in) { if (!audio_initialized) { return 0; } if (!sfx_process.started) { if (hw_audio_sfx_init_do(sfx_index, data_in, len_in)) { log_error("SDLA: failed to init sound %i\n", sfx_index); return -1; } } else { if (sfx_index >= sfx_num) { log_error("SDLA: BUG: sfx %i >= max %i\n", sfx_index, sfx_num); return -1; } for (int i = 0; i < sfx_process.num; ++i) { if (sfx_process.tbl[i].sfxi == sfx_index) { log_warning("SDLA: BUG: sfx %i already selected for init\n", sfx_index); return 0; } } if (sfxtbl[sfx_index].chunk) { hw_audio_sfx_release(sfx_index); } sfx_process.tbl[sfx_process.num].sfxi = sfx_index; sfx_process.tbl[sfx_process.num].data = data_in; sfx_process.tbl[sfx_process.num].len = len_in; ++sfx_process.num; } return 0; } int hw_audio_check_process(void) { if (sfx_process.started) { if (!sfx_process.busy) { uint32_t t_end = hw_get_time_us(); sfx_process.started = false; if (sfx_process.error) { log_error("SDLA: failed to init sound %i\n", sfx_process.errori); return -1; } else { log_message("SDLA: sfx processing took %i ms\n", (t_end - sfx_process.t_start) / 1000); } } } return 0; } #else /* !USE_SFX_INIT_THREAD */ int hw_audio_sfx_batch_start(int sfx_index_max) { return 0; } int hw_audio_sfx_batch_end(void) { return 0; } int hw_audio_sfx_init(int sfx_index, const uint8_t *data_in, uint32_t len_in) { if (!audio_initialized) { return 0; } if (hw_audio_sfx_init_do(sfx_index, data_in, len_in)) { log_error("SDLA: failed to init sound %i\n", sfx_index); return -1; } return 0; } int hw_audio_check_process(void) { return 0; } #endif /* USE_SFX_INIT_THREAD */ void hw_audio_sfx_release(int sfx_index) { if (sfx_index < sfx_num) { #ifdef USE_SFX_INIT_THREAD while (sfxtbl[sfx_index].pending) { SDL_Delay(10); } #endif /* USE_SFX_INIT_THREAD */ if (sfxtbl[sfx_index].chunk) { if (sfx_playing == sfx_index) { hw_audio_sfx_stop(); } Mix_FreeChunk(sfxtbl[sfx_index].chunk); sfxtbl[sfx_index].chunk = NULL; } } } void hw_audio_sfx_play(int sfx_index) { if (audio_initialized && opt_sfx_enabled && (sfx_index < sfx_num)) { #ifdef USE_SFX_INIT_THREAD while (sfxtbl[sfx_index].pending) { SDL_Delay(10); } #endif /* USE_SFX_INIT_THREAD */ Mix_PlayChannel(0, sfxtbl[sfx_index].chunk, 0); sfx_playing = sfx_index; } } void hw_audio_sfx_stop(void) { if (audio_initialized && Mix_Playing(0)) { Mix_HaltChannel(0); sfx_playing = -1; } } bool hw_audio_sfx_volume(int volume) { if (volume < 0) { volume = 0; } if (volume > 128) { volume = 128; } if (audio_initialized && opt_sfx_enabled) { Mix_Volume(0, volume); } if (opt_sfx_volume != volume) { log_message("SDLA: sfx volume %i\n", volume); opt_sfx_volume = volume; } return true; } #else /* !HAVE_SDLMIXER */ int hw_audio_init(void) { if (opt_audio_enabled) { log_warning("SDLA: no audio since this build was made with SDL_mixer explicitly disabled!\n"); } return 0; } void hw_audio_shutdown_pre(void) { } void hw_audio_shutdown(void) { } int hw_audio_set_sdlmixer_sf(const char *path) { return 0; } int hw_audio_music_init(int mus_index, const uint8_t *data, uint32_t len) { return 0; } void hw_audio_music_release(int mus_index) { } void hw_audio_music_play(int mus_index) { } void hw_audio_music_fadeout(void) { } void hw_audio_music_stop(void) { } bool hw_audio_music_volume(int volume/*0..128*/) { return true; } int hw_audio_sfx_batch_start(int sfx_index_max) { return 0; } int hw_audio_sfx_batch_end(void) { return 0; } int hw_audio_sfx_init(int sfx_index, const uint8_t *data, uint32_t len) { return 0; } int hw_audio_check_process(void) { return 0; } void hw_audio_sfx_release(int sfx_index) { } void hw_audio_sfx_play(int sfx_index) { } void hw_audio_sfx_stop(void) { } bool hw_audio_sfx_volume(int volume/*0..128*/) { return true; } #endif /* HAVE_SDLMIXER1 */ 1oom-1.11.2/src/hw/sdl/hwsdl_audio.h000066400000000000000000000004251476061725400171260ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_AUDIO_H #define INC_1OOM_HWSDL_AUDIO_H extern int hw_audio_init(void); extern void hw_audio_shutdown_pre(void); extern void hw_audio_shutdown(void); extern int hw_audio_set_sdlmixer_sf(const char *path); extern int hw_audio_check_process(void); #endif 1oom-1.11.2/src/hw/sdl/hwsdl_mouse.c000066400000000000000000000054611476061725400171550ustar00rootroot00000000000000#include "config.h" #include "hw.h" #include "comp.h" #include "hwsdl_mouse.h" #include "hwsdl_video.h" #include "hwsdl_opt.h" #include "log.h" #include "mouse.h" #include "types.h" /* -------------------------------------------------------------------------- */ static int hw_mouse_game_w; static int hw_mouse_game_h; static int hw_mouse_dx_acc = 0; static int hw_mouse_dy_acc = 0; static int hw_mouse_sx = 1; static int hw_mouse_sy = 1; /* -------------------------------------------------------------------------- */ bool hw_mouse_enabled = false; /* -------------------------------------------------------------------------- */ void hw_mouse_grab(void) { if (!hw_mouse_enabled) { hw_mouse_enabled = true; SDL_ShowCursor(SDL_DISABLE); hw_video_input_grab(true); } } void hw_mouse_ungrab(void) { if (hw_mouse_enabled) { hw_mouse_enabled = false; SDL_ShowCursor(SDL_ENABLE); hw_video_input_grab(false); } } void hw_mouse_toggle_grab(void) { if (hw_mouse_enabled) { hw_mouse_ungrab(); } else { hw_mouse_grab(); } } void hw_mouse_set_limits(int w, int h) { hw_mouse_game_w = w; hw_mouse_game_h = h; } void hw_mouse_set_scale(int w, int h) { int v; v = w / hw_mouse_game_w; SETMAX(v, 1); v *= 100; hw_mouse_sx = v; v = h / hw_mouse_game_h; SETMAX(v, 1); v *= 100; hw_mouse_sy = v; } void hw_mouse_move(int dx, int dy) { int x, y; { hw_mouse_dx_acc += dx * hw_opt_mousespd; dx = hw_mouse_dx_acc / hw_mouse_sx; hw_mouse_dx_acc = hw_mouse_dx_acc % hw_mouse_sx; } { hw_mouse_dy_acc += dy * hw_opt_mousespd; dy = hw_mouse_dy_acc / hw_mouse_sy; hw_mouse_dy_acc = hw_mouse_dy_acc % hw_mouse_sy; } if ((dx == 0) && (dy == 0)) { return; } x = moouse_x + dx; SETRANGE(x, 0, hw_mouse_game_w - 1); y = moouse_y + dy; SETRANGE(y, 0, hw_mouse_game_h - 1); mouse_set_xy_from_hw(x, y); } void hw_mouse_button(int i, int pressed) { if (hw_mouse_enabled) { int b = mouse_buttons; if (i == (int)SDL_BUTTON_LEFT) { if (pressed) { b |= MOUSE_BUTTON_MASK_LEFT; } else { b &= ~MOUSE_BUTTON_MASK_LEFT; } } else if (i == (int)SDL_BUTTON_RIGHT) { if (pressed) { b |= MOUSE_BUTTON_MASK_RIGHT; } else { b &= ~MOUSE_BUTTON_MASK_RIGHT; } } mouse_set_buttons_from_hw(b); } if (pressed) { if (hw_mouse_enabled) { if (i == (int)SDL_BUTTON_MIDDLE) { hw_mouse_ungrab(); } } else { hw_mouse_grab(); } } } void hw_mouse_scroll(int scroll) { mouse_set_scroll_from_hw(scroll); } 1oom-1.11.2/src/hw/sdl/hwsdl_mouse.h000066400000000000000000000007121476061725400171540ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_MOUSE_H #define INC_1OOM_HWSDL_MOUSE_H #include "types.h" extern bool hw_mouse_enabled; extern void hw_mouse_grab(void); extern void hw_mouse_ungrab(void); extern void hw_mouse_toggle_grab(void); extern void hw_mouse_set_limits(int w, int h); extern void hw_mouse_set_scale(int w, int h); extern void hw_mouse_move(int dx, int dy); extern void hw_mouse_button(int i, int pressed); extern void hw_mouse_scroll(int scroll); #endif 1oom-1.11.2/src/hw/sdl/hwsdl_opt.c000066400000000000000000000066641476061725400166350ustar00rootroot00000000000000/* already included by includer */ #if 0 #include "config.h" #include #include "hw.h" #include "hwsdl_opt.h" #include "options.h" #include "types.h" #endif /* -------------------------------------------------------------------------- */ #define HW_DEFAULT_ASPECT 1000000 bool hw_opt_borderless = false; bool hw_opt_fullscreen = HW_DEFAULT_FULLSCREEN; int hw_opt_screen_winw = 0; int hw_opt_screen_winh = 0; int hw_opt_screen_fsw = 0; int hw_opt_screen_fsh = 0; int hw_opt_mousespd = 100; #ifdef HAVE_SDLX_ASPECT int hw_opt_aspect = HW_DEFAULT_ASPECT; #endif char *hw_opt_sdlmixer_sf = NULL; /* -------------------------------------------------------------------------- */ const struct cfg_items_s hw_cfg_items[] = { CFG_ITEM_BOOL("borderless", &hw_opt_borderless), CFG_ITEM_BOOL("fs", &hw_opt_fullscreen), CFG_ITEM_INT("winw", &hw_opt_screen_winw, 0), CFG_ITEM_INT("winh", &hw_opt_screen_winh, 0), CFG_ITEM_INT("fsw", &hw_opt_screen_fsw, 0), CFG_ITEM_INT("fsh", &hw_opt_screen_fsh, 0), CFG_ITEM_INT("mousespd", &hw_opt_mousespd, 0), #ifdef HAVE_SDLMIXER CFG_ITEM_STR("sdlmixersf", &hw_opt_sdlmixer_sf, 0), #endif #ifdef HAVE_SDLX_ASPECT CFG_ITEM_INT("aspect", &hw_opt_aspect, 0), #endif CFG_ITEM_END }; /* -------------------------------------------------------------------------- */ #ifdef HAVE_SDLX_ASPECT static const char *hw_uiopt_cb_aspect_get(void) { if (hw_opt_aspect == 833333) { return "VGA"; } else if (hw_opt_aspect == 1000000) { return "1:1"; } else if (hw_opt_aspect == 0) { return "Off"; } else { return "Custom"; } } static bool hw_uiopt_cb_aspect_next(void) { if (hw_opt_aspect == 833333) { hw_opt_aspect = 1000000; } else if (hw_opt_aspect == 1000000) { hw_opt_aspect = 0; } else { hw_opt_aspect = 833333; } return hw_video_update_aspect(); } #endif /* HAVE_SDLX_ASPECT */ /* -------------------------------------------------------------------------- */ #ifdef HAVE_SDLMIXER static int hw_opt_set_sdlmixer_sf(char **argv, void *var) { hw_opt_sdlmixer_sf = lib_stralloc(argv[1]); return hw_audio_set_sdlmixer_sf(hw_opt_sdlmixer_sf); } #endif /* -------------------------------------------------------------------------- */ const struct cmdline_options_s hw_cmdline_options[] = { { "-fs", 0, options_enable_bool_var, (void *)&hw_opt_fullscreen, NULL, "Enable fullscreen" }, { "-window", 0, options_disable_bool_var, (void *)&hw_opt_fullscreen, NULL, "Use windowed mode" }, { "-winw", 1, options_set_int_var, (void *)&hw_opt_screen_winw, "WIDTH", "Set window width" }, { "-winh", 1, options_set_int_var, (void *)&hw_opt_screen_winh, "HEIGHT", "Set window height" }, { "-fsw", 1, options_set_int_var, (void *)&hw_opt_screen_fsw, "WIDTH", "Set fullscreen width" }, { "-fsh", 1, options_set_int_var, (void *)&hw_opt_screen_fsh, "HEIGHT", "Set fullscreen height" }, { "-mousespd", 1, options_set_int_var, (void *)&hw_opt_mousespd, "SPEED", "Set mouse speed (default = 100)" }, #ifdef HAVE_SDLMIXER { "-sdlmixersf", 1, hw_opt_set_sdlmixer_sf, NULL, "FILE.SF2", "Set SDL_mixer soundfont" }, #endif #ifdef HAVE_SDLX_ASPECT { "-aspect", 1, options_set_int_var, (void *)&hw_opt_aspect, "ASPECT", "Set aspect ratio (*1000000, 0 = off)" }, #endif { NULL, 0, NULL, NULL, NULL, NULL } }; 1oom-1.11.2/src/hw/sdl/hwsdl_opt.h000066400000000000000000000012311476061725400166230ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_OPT_H #define INC_1OOM_HWSDL_OPT_H extern bool hw_opt_borderless; extern bool hw_opt_fullscreen; extern int hw_opt_screen_winw; extern int hw_opt_screen_winh; extern int hw_opt_screen_fsw; extern int hw_opt_screen_fsh; extern char *hw_opt_sdlmixer_sf; extern int hw_opt_aspect; extern int hw_opt_mousespd; /* for SDL1 */ extern bool hw_opt_use_gl; extern int hw_opt_gl_filter; extern int hw_opt_bpp; /* for SDL2 */ extern bool hw_opt_force_sw; extern bool hw_opt_int_scaling; extern bool hw_opt_relmouse; extern bool hw_opt_autotrim; extern bool hw_opt_vsync; extern bool hw_opt_allow_upscaling; extern int hw_opt_scaling_quality; #endif 1oom-1.11.2/src/hw/sdl/hwsdl_video.c000066400000000000000000000043361476061725400171330ustar00rootroot00000000000000static int video_check_opt_screen_winwh(void) { int minw = video.bufw; int minh = video.bufh; if ((hw_opt_screen_winw != 0) && (hw_opt_screen_winh != 0)) { if ((hw_opt_screen_winw < minw) || (hw_opt_screen_winh < minh)) { log_warning("ignoring too small configured resolution %ix%i < %ix%i\n", hw_opt_screen_winw, hw_opt_screen_winh, minw, minh); } else { return 0; } } return -1; } /* -------------------------------------------------------------------------- */ void hw_video_refresh(int front) { if (SDL_MUSTLOCK(video.screen)) { if (SDL_LockSurface(video.screen) < 0) { return; } } video.render(video.bufi ^ front); if (SDL_MUSTLOCK(video.screen)) { SDL_UnlockSurface(video.screen); } video.update(); } void hw_video_update(void) { video.update(); } void hw_video_set_palette(const uint8_t *pal, int first, int num) { ui_palette_set(pal, first, num); video.setpal(pal, first, num); } void hw_video_set_palette_color(int i, uint8_t r, uint8_t g, uint8_t b) { ui_palette_set_color(i, r, g, b); } void hw_video_refresh_palette(void) { video.setpal(ui_palette, 0, 256); } uint8_t *hw_video_get_buf(void) { return video.buf[video.bufi]; } uint8_t *hw_video_get_buf_front(void) { return video.buf[video.bufi ^ 1]; } uint8_t *hw_video_draw_buf(void) { hw_video_refresh(0); video.bufi ^= 1; return video.buf[video.bufi]; } void hw_video_redraw_front(void) { hw_video_refresh(1); } void hw_video_copy_buf(void) { memcpy(video.buf[video.bufi], video.buf[video.bufi ^ 1], video.bufw * video.bufh); } void hw_video_copy_buf_out(uint8_t *buf) { memcpy(buf, video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_to_page2(void) { memcpy(video.buf[2], video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_from_page2(void) { memcpy(video.buf[video.bufi], video.buf[2], video.bufw * video.bufh); } void hw_video_copy_back_to_page3(void) { memcpy(video.buf[3], video.buf[video.bufi], video.bufw * video.bufh); } void hw_video_copy_back_from_page3(void) { memcpy(video.buf[video.bufi], video.buf[3], video.bufw * video.bufh); } 1oom-1.11.2/src/hw/sdl/hwsdl_video.h000066400000000000000000000007331476061725400171350ustar00rootroot00000000000000#ifndef INC_1OOM_HWSDL_VIDEO_H #define INC_1OOM_HWSDL_VIDEO_H extern void hw_video_shutdown(void); extern void hw_video_update(void); extern void hw_video_refresh(int front); extern int hw_video_resize(int w, int h); extern void hw_video_shrink(void); extern void hw_video_enlarge(void); extern bool hw_video_toggle_borderless(void); extern bool hw_video_toggle_fullscreen(void); extern bool hw_video_update_aspect(void); extern void hw_video_input_grab(bool grab); #endif 1oom-1.11.2/src/kbd.c000066400000000000000000000040111476061725400141520ustar00rootroot00000000000000#include "config.h" #include "boolvec.h" #include "kbd.h" #include "log.h" #include "types.h" /* -------------------------------------------------------------------------- */ #define KBD_BUFSIZE 16 static struct { bool full; int head; int tail; uint32_t mod; uint32_t buf[KBD_BUFSIZE]; BOOLVEC_DECLARE(pressed, MOO_KEY_LAST); } kbd = { 0 }; /* -------------------------------------------------------------------------- */ void kbd_clear(void) { kbd.full = false; kbd.head = 0; kbd.tail = 0; kbd.mod = 0; BOOLVEC_CLEAR(kbd.pressed, MOO_KEY_LAST); } void kbd_add_keypress(mookey_t key, uint32_t mod, char c) { uint32_t value = ((uint32_t)key) | mod | (((uint32_t)c) << 8); if (key == MOO_KEY_LAST) { return; } if (key == MOO_KEY_RSHIFT || key == MOO_KEY_LSHIFT || key == MOO_KEY_RCTRL || key == MOO_KEY_LCTRL || key == MOO_KEY_RALT || key == MOO_KEY_LALT) { if (kbd_is_pressed(key, 0, 0)) { return; } } if (kbd.full) { log_warning("kbd: full while inserting 0x%x\n", value); } else { kbd.buf[kbd.head] = value; if (++kbd.head == KBD_BUFSIZE) { kbd.head = 0; } if (kbd.head == kbd.tail) { kbd.full = true; } } } bool kbd_have_keypress(void) { return kbd.full || (kbd.head != kbd.tail); } uint32_t kbd_get_keypress(void) { mookey_t key = MOO_KEY_UNKNOWN; if (kbd_have_keypress()) { key = kbd.buf[kbd.tail]; if (++kbd.tail == KBD_BUFSIZE) { kbd.tail = 0; } kbd.full = false; } return key; } void kbd_set_pressed(mookey_t key, uint32_t mod, bool pressed) { kbd.mod = mod; if ((key != MOO_KEY_UNKNOWN) && (key < MOO_KEY_LAST)) { BOOLVEC_SET(kbd.pressed, key, pressed); } } bool kbd_is_pressed(mookey_t key, uint32_t modon, uint32_t modoff) { return (((kbd.mod & modon) == modon) && ((kbd.mod & modoff) == 0) && BOOLVEC_IS1(kbd.pressed, key)); } bool kbd_is_modifier(uint32_t mod) { return kbd.mod & mod; } 1oom-1.11.2/src/kbd.h000066400000000000000000000141711476061725400141670ustar00rootroot00000000000000#ifndef INC_1OOM_KBD_H #define INC_1OOM_KBD_H #include "types.h" /* following enum based on SDL_keysym.h: */ /* SDL - Simple DirectMedia Layer Copyright (C) 1997-2012 Sam Lantinga This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Sam Lantinga slouken@libsdl.org */ typedef enum { MOO_KEY_UNKNOWN = 0, MOO_KEY_FIRST = 0, MOO_KEY_RELEASE = 1, MOO_KEY_BACKSPACE = 8, MOO_KEY_TAB = 9, MOO_KEY_CLEAR = 12, MOO_KEY_RETURN = 13, MOO_KEY_PAUSE = 19, MOO_KEY_ESCAPE = 27, MOO_KEY_SPACE = 32, MOO_KEY_EXCLAIM = 33, MOO_KEY_QUOTEDBL = 34, MOO_KEY_HASH = 35, MOO_KEY_DOLLAR = 36, MOO_KEY_AMPERSAND = 38, MOO_KEY_QUOTE = 39, MOO_KEY_LEFTPAREN = 40, MOO_KEY_RIGHTPAREN = 41, MOO_KEY_ASTERISK = 42, MOO_KEY_PLUS = 43, MOO_KEY_COMMA = 44, MOO_KEY_MINUS = 45, MOO_KEY_PERIOD = 46, MOO_KEY_SLASH = 47, MOO_KEY_0 = 48, MOO_KEY_1 = 49, MOO_KEY_2 = 50, MOO_KEY_3 = 51, MOO_KEY_4 = 52, MOO_KEY_5 = 53, MOO_KEY_6 = 54, MOO_KEY_7 = 55, MOO_KEY_8 = 56, MOO_KEY_9 = 57, MOO_KEY_COLON = 58, MOO_KEY_SEMICOLON = 59, MOO_KEY_LESS = 60, MOO_KEY_EQUALS = 61, MOO_KEY_GREATER = 62, MOO_KEY_QUESTION = 63, MOO_KEY_AT = 64, /* Skip uppercase letters */ MOO_KEY_LEFTBRACKET = 91, MOO_KEY_BACKSLASH = 92, MOO_KEY_RIGHTBRACKET= 93, MOO_KEY_CARET = 94, MOO_KEY_UNDERSCORE = 95, MOO_KEY_BACKQUOTE = 96, MOO_KEY_a = 97, MOO_KEY_b = 98, MOO_KEY_c = 99, MOO_KEY_d = 100, MOO_KEY_e = 101, MOO_KEY_f = 102, MOO_KEY_g = 103, MOO_KEY_h = 104, MOO_KEY_i = 105, MOO_KEY_j = 106, MOO_KEY_k = 107, MOO_KEY_l = 108, MOO_KEY_m = 109, MOO_KEY_n = 110, MOO_KEY_o = 111, MOO_KEY_p = 112, MOO_KEY_q = 113, MOO_KEY_r = 114, MOO_KEY_s = 115, MOO_KEY_t = 116, MOO_KEY_u = 117, MOO_KEY_v = 118, MOO_KEY_w = 119, MOO_KEY_x = 120, MOO_KEY_y = 121, MOO_KEY_z = 122, MOO_KEY_DELETE = 127, /* End of ASCII mapped keysyms */ /*@}*/ /** @name Numeric keypad */ /*@{*/ MOO_KEY_KP0 = 128, MOO_KEY_KP1, MOO_KEY_KP2, MOO_KEY_KP3, MOO_KEY_KP4, MOO_KEY_KP5, MOO_KEY_KP6, MOO_KEY_KP7, MOO_KEY_KP8, MOO_KEY_KP9, MOO_KEY_KP_PERIOD, MOO_KEY_KP_DIVIDE, MOO_KEY_KP_MULTIPLY, MOO_KEY_KP_MINUS, MOO_KEY_KP_PLUS, MOO_KEY_KP_NONE1, //MOO_KEY_KP_ENTER MOO_KEY_KP_EQUALS, /*@}*/ /** @name Arrows + Home/End pad */ /*@{*/ MOO_KEY_UP, MOO_KEY_DOWN, MOO_KEY_RIGHT, MOO_KEY_LEFT, MOO_KEY_INSERT, MOO_KEY_HOME, MOO_KEY_END, MOO_KEY_PAGEUP, MOO_KEY_PAGEDOWN, /*@}*/ /** @name Function keys */ /*@{*/ MOO_KEY_F1, MOO_KEY_F2, MOO_KEY_F3, MOO_KEY_F4, MOO_KEY_F5, MOO_KEY_F6, MOO_KEY_F7, MOO_KEY_F8, MOO_KEY_F9, MOO_KEY_F10, MOO_KEY_F11, MOO_KEY_F12, MOO_KEY_F13, MOO_KEY_F14, MOO_KEY_F15, /*@}*/ /** @name Key state modifier keys */ /*@{*/ MOO_KEY_NUMLOCK, MOO_KEY_CAPSLOCK, MOO_KEY_SCROLLOCK, MOO_KEY_RSHIFT, MOO_KEY_LSHIFT, MOO_KEY_RCTRL, MOO_KEY_LCTRL, MOO_KEY_RALT, MOO_KEY_LALT, MOO_KEY_RMETA, MOO_KEY_LMETA, MOO_KEY_LSUPER, /**< Left "Windows" key */ MOO_KEY_RSUPER, /**< Right "Windows" key */ MOO_KEY_MODE, /**< "Alt Gr" key */ MOO_KEY_COMPOSE, /**< Multi-key compose key */ /*@}*/ /** @name Miscellaneous function keys */ /*@{*/ MOO_KEY_HELP, MOO_KEY_PRINT, MOO_KEY_SYSREQ, MOO_KEY_BREAK, MOO_KEY_MENU, MOO_KEY_POWER, /**< Power Macintosh power key */ MOO_KEY_EURO, /**< Some european keyboards */ MOO_KEY_UNDO, /**< Atari keyboard has Undo */ /*@}*/ /* Add any other keys here */ MOO_KEY_LAST } mookey_t; #define MOO_MOD_SHIFT (1 << 16) #define MOO_MOD_ALT (1 << 17) #define MOO_MOD_CTRL (1 << 18) #define MOO_MOD_META (1 << 19) #define MOO_MOD_ALL (MOO_MOD_SHIFT | MOO_MOD_ALT | MOO_MOD_CTRL | MOO_MOD_META) #define KBD_GET_KEY(_k_) ((mookey_t)((_k_) & 0xff)) #define KBD_GET_CHAR(_k_) ((char)(((_k_) >> 8) & 0xff)) #define KBD_GET_MOD(_k_) ((_k_) & MOO_MOD_ALL) #define KBD_GET_KEYMOD(_k_) ((_k_) & (MOO_MOD_ALL | 0xff)) #define KBD_MOD_ONLY_SHIFT(_k_) (KBD_GET_MOD(_k_) == MOO_MOD_SHIFT) #define KBD_MOD_ONLY_CTRL(_k_) (KBD_GET_MOD(_k_) == MOO_MOD_CTRL) #define KBD_MOD_ONLY_ALT(_k_) ((((_k_) & (MOO_MOD_ALT | MOO_MOD_META)) != 0) && (((_k_) & (MOO_MOD_SHIFT | MOO_MOD_CTRL)) == 0)) extern void kbd_clear(void); extern void kbd_add_keypress(mookey_t key, uint32_t mod, char c); extern bool kbd_have_keypress(void); extern uint32_t kbd_get_keypress(void); extern void kbd_set_pressed(mookey_t key, uint32_t mod, bool pressed); extern bool kbd_is_pressed(mookey_t key, uint32_t modon, uint32_t modoff); extern bool kbd_is_modifier(uint32_t mod); #endif 1oom-1.11.2/src/lbx.c000066400000000000000000000347341476061725400142160ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include "lbx.h" #include "bits.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define LBX_HEADER_LEN 0x200 struct lbxpatch_s { struct lbxpatch_s *next; uint8_t *data; uint32_t len; uint32_t offs; uint16_t i; }; struct lbx_s { enum { LBX_MODE_NONE = 0, LBX_MODE_FILE_OPEN, LBX_MODE_MEMORY } mode; FILE *fd; uint32_t len; uint16_t entries; uint16_t type; uint8_t *header; uint8_t *data; int num_in_use; struct lbxpatch_s *patches; struct lbxpatch_s *overwrites; }; static const struct { const char *filename; bool in_memory; /* load whole file to memory */ } lbxinfo[LBXFILE_NUM] = { { "backgrnd.lbx", true }, { "colonies.lbx", true }, { "council.lbx", true }, { "design.lbx", true }, { "diplomat.lbx", true }, { "embassy.lbx", true }, { "eventmsg.lbx", true }, { "firing.lbx", true }, { "fonts.lbx", true }, { "help.lbx", true }, { "intro.lbx", false }, { "intro2.lbx", false }, { "introsnd.lbx", false }, { "landing.lbx", true }, { "missile.lbx", true }, { "music.lbx", true }, { "names.lbx", true }, { "nebula.lbx", true }, { "newscast.lbx", true }, { "planets.lbx", true }, { "research.lbx", true }, { "screens.lbx", true }, { "ships.lbx", true }, { "ships2.lbx", true }, { "soundfx.lbx", true }, { "space.lbx", true }, { "spies.lbx", true }, { "starmap.lbx", true }, { "starview.lbx", true }, { "techno.lbx", true }, { "v11.lbx", true }, { "vortex.lbx", true }, { "winlose.lbx", false } }; static struct lbx_s lbxtbl[LBXFILE_NUM] = { 0 }; static char entrynamebuf[32 + 1]; /* HACK */ /* -------------------------------------------------------------------------- */ static FILE *lbxfile_try_fopen(const char *path, const char *filename) { FILE *fd; char *fname; if (path) { fname = util_concat(path, FSDEV_DIR_SEP_STR, filename, NULL); } fd = fopen(path ? fname : filename, "rb"); if (path) { lib_free(fname); fname = NULL; } if (!fd) { char buf[32]; const char *p = filename; char *q = buf; while (*p) { *q++ = toupper(*p++); } *q = 0; if (path) { fname = util_concat(path, FSDEV_DIR_SEP_STR, buf, NULL); } fd = fopen(path ? fname : buf, "rb"); if (path) { lib_free(fname); fname = NULL; } } return fd; } static int lbxfile_open(struct lbx_s *p, const char *filename) { uint16_t v; p->fd = lbxfile_try_fopen(os_get_path_data(), filename); if (!p->fd) { log_error("opening file '%s'!\n", filename); goto fail; } p->header = lib_malloc(LBX_HEADER_LEN); if (fread(p->header, LBX_HEADER_LEN, 1, p->fd) < 1) { log_error("reading header of file '%s'!\n", filename); goto fail; } v = GET_LE_16(&p->header[0]); p->entries = v; v = GET_LE_16(&p->header[2]); if (v != 0xfead) { log_error("file '%s' has wrong signature 0x%04x!\n", filename, v); goto fail; } v = GET_LE_16(&p->header[4]); if (v != 0) { log_error("file '%s' has nonzero at offs 4: 0x%04x!\n", filename, v); } p->type = GET_LE_16(&p->header[6]); if (fseek(p->fd, 0, SEEK_END)) { log_error("error seeking file '%s'\n", filename); goto fail; } p->len = ftell(p->fd); rewind(p->fd); p->mode = LBX_MODE_FILE_OPEN; p->num_in_use = 0; return 0; fail: if (p->fd) { fclose(p->fd); p->fd = NULL; } lib_free(p->header); p->header = NULL; return -1; } static void lbxfile_close(lbxfile_e i) { switch (lbxtbl[i].mode) { case LBX_MODE_FILE_OPEN: fclose(lbxtbl[i].fd); lbxtbl[i].fd = NULL; lib_free(lbxtbl[i].header); lbxtbl[i].header = NULL; break; case LBX_MODE_MEMORY: lib_free(lbxtbl[i].data); lbxtbl[i].data = NULL; lbxtbl[i].header = NULL; break; case LBX_MODE_NONE: break; } lbxtbl[i].mode = LBX_MODE_NONE; } static int lbxfile_load(lbxfile_e i) { if (lbxfile_open(&lbxtbl[i], lbxinfo[i].filename)) { goto fail; } if (lbxinfo[i].in_memory) { lbxtbl[i].data = lib_malloc(lbxtbl[i].len); if (fread(lbxtbl[i].data, lbxtbl[i].len, 1, lbxtbl[i].fd) < 1) { log_error("problem reading file %s\n", lbxinfo[i].filename); lib_free(lbxtbl[i].data); lbxtbl[i].data = NULL; goto fail; } fclose(lbxtbl[i].fd); lbxtbl[i].fd = NULL; lib_free(lbxtbl[i].header); lbxtbl[i].header = lbxtbl[i].data; lbxtbl[i].mode = LBX_MODE_MEMORY; } return 0; fail: exit(EXIT_FAILURE); return 1; } static uint8_t *lbx_extract(struct lbx_s *p, uint16_t i, uint32_t *len_ptr, const char *filename) { if (!p) { return NULL; } if (i >= p->entries) { log_error("LBX: %s invalid id %i >= %i\n", filename, i, p->entries); return NULL; } uint32_t offs0, offs1, len; offs0 = GET_LE_32(&p->header[8 + i * 4]); offs1 = GET_LE_32(&p->header[8 + i * 4 + 4]); len = offs1 - offs0; if (len_ptr) { *len_ptr = len; } if (p->mode == LBX_MODE_FILE_OPEN) { if (fseek(p->fd, offs0, SEEK_SET)) { log_error("LBX: problem seeking %s to %i\n", filename, offs0); return NULL; } uint8_t *d = lib_malloc(len); if (fread(d, len, 1, p->fd) < 1) { log_error("LBX: problem reading file %s\n", filename); return NULL; } return d; } else if (p->mode == LBX_MODE_MEMORY) { return &p->data[offs0]; } else { log_error("LBX: extract without open\n"); return NULL; } } static uint8_t *lbxfile_get_patch(struct lbx_s *lbx, uint16_t i, uint32_t *len_ptr) { struct lbxpatch_s *p; if (!lbx) { return NULL; } p = lbx->patches; while (p) { if (p->i == i) { if (len_ptr) { *len_ptr = p->len; } return p->data; } p = p->next; } return NULL; } static bool lbxfile_apply_overwrites(struct lbx_s *lbx, uint16_t i, uint8_t *data, uint32_t len, const char *lbxname) { struct lbxpatch_s *p; if (!lbx) { return false; } p = lbx->overwrites; while (p) { if (p->i == i) { if ((p->offs >= len) || ((p->offs + p->len) > len)) { log_fatal_and_die("LBX: PBX overwrite for %s item %i offs 0x%x len 0x%x exceeds item len 0x%x!\n", lbxname, i, p->offs, p->len, len); return false; } memcpy(&data[p->offs], p->data, p->len); } p = p->next; } return true; } static uint8_t *lbxfile_item_get_do(lbxfile_e file_id, uint16_t entry_id, uint32_t *len_ptr) { uint8_t *p = NULL; struct lbx_s *lbx = &lbxtbl[file_id]; uint32_t len; p = lbxfile_get_patch(lbx, entry_id, &len); if (p == NULL) { if (lbx->mode == LBX_MODE_NONE) { if (lbxfile_load(file_id)) { goto fail; } } p = lbx_extract(lbx, entry_id, &len, lbxinfo[file_id].filename); if (p == NULL) { goto fail; } } if (!lbxfile_apply_overwrites(lbx, entry_id, p, len, lbxinfo[file_id].filename)) { goto fail; } if (len_ptr) { *len_ptr = len; } ++lbxtbl[file_id].num_in_use; return p; fail: return NULL; } static void lbxfile_shutdown_patch_list(struct lbxpatch_s *p) { struct lbxpatch_s *pn; while (p) { pn = p->next; p->next = NULL; lib_free(p->data); p->data = NULL; lib_free(p); p = pn; } } static void lbxfile_shutdown_patches(struct lbx_s *lbx) { struct lbxpatch_s *p; if (!lbx) { return; } p = lbx->patches; lbx->patches = NULL; lbxfile_shutdown_patch_list(p); p = lbx->overwrites; lbx->overwrites = NULL; lbxfile_shutdown_patch_list(p); } /* -------------------------------------------------------------------------- */ int lbxfile_init(void) { memset(lbxtbl, 0, sizeof(lbxtbl)); return 0; } void lbxfile_shutdown(void) { for (lbxfile_e i = LBXFILE_BACKGRND; i < LBXFILE_NUM; ++i) { lbxfile_close(i); lbxfile_shutdown_patches(&lbxtbl[i]); } } int lbxfile_find_dir(void) { const char **paths = os_get_paths_data(); const char **pp = paths; log_message_direct("LBX: seeking data directory\n"); while (*pp) { FILE *fd; log_message("LBX: trying '%s'\n", *pp); if ((fd = lbxfile_try_fopen(*pp, "fonts.lbx"))) { fclose(fd); break; } ++pp; } if (!*pp) { log_error("could not find the LBX files! Try running with -data path_to_moo1.\n"); return -1; } else { log_message("LBX: found data directory at '%s'\n", *pp); os_set_path_data(*pp); } return 0; } uint8_t *lbxfile_item_get(lbxfile_e file_id, uint16_t entry_id) { return lbxfile_item_get_do(file_id, entry_id, 0); } uint8_t *lbxfile_item_get_with_len(lbxfile_e file_id, uint16_t entry_id, uint32_t *len_ptr) { return lbxfile_item_get_do(file_id, entry_id, len_ptr); } void lbxfile_item_release(lbxfile_e file_id, uint8_t *ptr) { if (lbxtbl[file_id].num_in_use <= 0) { log_error("%s: release without use\n", lbxinfo[file_id].filename); return; } if (lbxtbl[file_id].mode == LBX_MODE_FILE_OPEN) { lib_free(ptr); } else if (lbxtbl[file_id].mode == LBX_MODE_MEMORY) { if (lbxtbl[file_id].type == LBX_TYPE_GFX) { /* restore gfx data to original state */ lbxgfx_set_frame_0(ptr); lbxgfx_set_epage(ptr, 0); } } --lbxtbl[file_id].num_in_use; if (lbxtbl[file_id].num_in_use <= 0) { lbxfile_close(file_id); } } void lbxfile_item_release_file(lbxfile_e file_id) { lbxfile_close(file_id); } bool lbxfile_exists(lbxfile_e file_id) { if (lbxtbl[file_id].mode != LBX_MODE_NONE) { return true; } else { FILE *fd = NULL; bool found; fd = lbxfile_try_fopen(os_get_path_data(), lbxinfo[file_id].filename); found = (fd != NULL); if (fd) { fclose(fd); fd = NULL; } return found; } } const char *lbxfile_name(lbxfile_e file_id) { return lbxinfo[file_id].filename; } lbxfile_e lbxfile_id(const char *filename) { for (lbxfile_e j = LBXFILE_BACKGRND; j < LBXFILE_NUM; ++j) { if (strcmp(lbxfile_name(j), filename) == 0) { return j; } } return LBXFILE_NUM; } int lbxfile_type(lbxfile_e file_id) { if ((lbxtbl[file_id].mode == LBX_MODE_NONE) && (lbxfile_load(file_id))) { goto fail; } return lbxtbl[file_id].type; fail: return -1; } int lbxfile_num_items(lbxfile_e file_id) { if ((lbxtbl[file_id].mode == LBX_MODE_NONE) && (lbxfile_load(file_id))) { goto fail; } return lbxtbl[file_id].entries; fail: return -1; } const char *lbxfile_item_name(lbxfile_e file_id, uint16_t entry_id) { if ((lbxtbl[file_id].mode == LBX_MODE_NONE) && (lbxfile_load(file_id))) { goto fail; } { struct lbx_s *p; p = &lbxtbl[file_id]; if (p->mode == LBX_MODE_FILE_OPEN) { if (fseek(p->fd, 0x200 + entry_id * 32, SEEK_SET)) { log_error("problem seeking to %i (of %i)\n", 0x200 + entry_id * 32, p->len); goto fail; } if (fread(entrynamebuf, 32, 1, p->fd) < 1) { log_error("problem reading file\n"); goto fail; } return entrynamebuf; } else { return (const char *)&p->data[0x200 + entry_id * 32]; } } fail: return NULL; } int lbxfile_item_len(lbxfile_e file_id, uint16_t entry_id) { if ((lbxtbl[file_id].mode == LBX_MODE_NONE) && (lbxfile_load(file_id))) { return -1; } { uint32_t offs0, offs1, len; struct lbx_s *p; p = &lbxtbl[file_id]; offs0 = GET_LE_32(&p->header[8 + entry_id * 4]); offs1 = GET_LE_32(&p->header[8 + entry_id * 4 + 4]); len = offs1 - offs0; return len; } } int lbxfile_item_offs(lbxfile_e file_id, uint16_t entry_id) { if ((lbxtbl[file_id].mode == LBX_MODE_NONE) && (lbxfile_load(file_id))) { return -1; } { uint32_t offs0; struct lbx_s *p; p = &lbxtbl[file_id]; offs0 = GET_LE_32(&p->header[8 + entry_id * 4]); return offs0; } } void lbxfile_add_patch(lbxfile_e file_id, uint16_t i, uint8_t *data, uint32_t len, const char *patchfilename) { struct lbxpatch_s *p, *pnew, *q = NULL; struct lbx_s *lbx = &lbxtbl[file_id]; pnew = lib_malloc(sizeof(struct lbxpatch_s)); pnew->next = NULL; pnew->data = data; pnew->len = len; pnew->i = i; p = lbx->patches; while (p && (i > p->i)) { q = p; p = p->next; } if (p && (i == p->i)) { log_warning("replacing patch on %s item %i with one from '%s'\n", lbxinfo[file_id].filename, i, patchfilename); if (!q) { lbx->patches = pnew; pnew->next = p->next; } else { q->next = pnew; pnew->next = p->next; } lib_free(p); } else { if (!q) { lbx->patches = pnew; pnew->next = p; } else { q->next = pnew; pnew->next = p; } } } void lbxfile_add_overwrite(lbxfile_e file_id, uint16_t i, uint32_t itemoffs, uint8_t *data, uint32_t len, const char *patchfilename) { struct lbxpatch_s *p, *pnew, *q = NULL; struct lbx_s *lbx = &lbxtbl[file_id]; pnew = lib_malloc(sizeof(struct lbxpatch_s)); pnew->next = NULL; pnew->data = data; pnew->len = len; pnew->offs = itemoffs; pnew->i = i; p = lbx->overwrites; while (p && (i >= p->i)) { q = p; p = p->next; } if (!q) { lbx->overwrites = pnew; pnew->next = p; } else { q->next = pnew; pnew->next = p; } } 1oom-1.11.2/src/lbx.h000066400000000000000000000040061476061725400142100ustar00rootroot00000000000000#ifndef INC_1OOM_LBX_H #define INC_1OOM_LBX_H #include "types.h" #define LBX_TYPE_GFX 0 #define LBX_TYPE_SOUND 1 #define LBX_TYPE_FONTS 2 #define LBX_TYPE_HELP 3 #define LBX_TYPE_DATA 5 struct lbx_s; typedef enum { LBXFILE_BACKGRND, LBXFILE_COLONIES, LBXFILE_COUNCIL, LBXFILE_DESIGN, LBXFILE_DIPLOMAT, LBXFILE_EMBASSY, LBXFILE_EVENTMSG, LBXFILE_FIRING, LBXFILE_FONTS, LBXFILE_HELP, LBXFILE_INTRO, LBXFILE_INTRO2, LBXFILE_INTROSND, LBXFILE_LANDING, LBXFILE_MISSILE, LBXFILE_MUSIC, LBXFILE_NAMES, LBXFILE_NEBULA, LBXFILE_NEWSCAST, LBXFILE_PLANETS, LBXFILE_RESEARCH, LBXFILE_SCREENS, LBXFILE_SHIPS, LBXFILE_SHIPS2, LBXFILE_SOUNDFX, LBXFILE_SPACE, LBXFILE_SPIES, LBXFILE_STARMAP, LBXFILE_STARVIEW, LBXFILE_TECHNO, LBXFILE_V11, LBXFILE_VORTEX, LBXFILE_WINLOSE, LBXFILE_NUM } lbxfile_e; extern int lbxfile_init(void); extern void lbxfile_shutdown(void); extern int lbxfile_find_dir(void); extern uint8_t *lbxfile_item_get(lbxfile_e file_id, uint16_t entry_id); extern uint8_t *lbxfile_item_get_with_len(lbxfile_e file_id, uint16_t entry_id, uint32_t *len_ptr); extern void lbxfile_item_release(lbxfile_e file_id, uint8_t *ptr); extern void lbxfile_item_release_file(lbxfile_e file_id); extern bool lbxfile_exists(lbxfile_e file_id); extern const char *lbxfile_name(lbxfile_e file_id); extern lbxfile_e lbxfile_id(const char *filename); extern int lbxfile_type(lbxfile_e file_id); extern int lbxfile_num_items(lbxfile_e file_id); extern const char *lbxfile_item_name(lbxfile_e file_id, uint16_t entry_id); extern int lbxfile_item_len(lbxfile_e file_id, uint16_t entry_id); extern int lbxfile_item_offs(lbxfile_e file_id, uint16_t entry_id); extern void lbxfile_add_patch(lbxfile_e file_id, uint16_t i, uint8_t *data, uint32_t len, const char *patchfilename); extern void lbxfile_add_overwrite(lbxfile_e file_id, uint16_t i, uint32_t itemoffs, uint8_t *data, uint32_t len, const char *patchfilename); #endif 1oom-1.11.2/src/lbxedit.c000066400000000000000000000452411476061725400150570ustar00rootroot00000000000000#include "config.h" #include #include #include #include "bits.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" #include "util_cstr.h" /* -------------------------------------------------------------------------- */ #ifdef FEATURE_MODEBUG int opt_modebug = 0; #endif #define SEP_CHAR ',' #define LBX_HEADER_LEN 0x200 #define LBX_DESC_LEN 0x20 #define LBX_MAX_ENTRIES ((LBX_HEADER_LEN - 4 - 4) / 4) static struct lbxedit_s { uint8_t *data; uint32_t len; const char *filename_lbx; uint8_t type; uint8_t entries; struct lbxedit_item_s { uint32_t start; uint32_t len; uint8_t *data; char desc[LBX_DESC_LEN + 1]; } item[LBX_MAX_ENTRIES + 1]; } lbxedit_ctx; /* -------------------------------------------------------------------------- */ static void lbxedit_init(struct lbxedit_s *ctx) { ctx->data = 0; } static void lbxedit_shutdown(struct lbxedit_s *ctx) { if (ctx->data) { lib_free(ctx->data); ctx->data = 0; } } static bool lbxedit_load_lbx(struct lbxedit_s *ctx, const char *filename) { uint32_t len; uint16_t v16; uint8_t num; uint8_t *data; ctx->filename_lbx = filename; data = util_file_load(filename, &len); if (!data) { return false; } ctx->data = data; if (len < LBX_HEADER_LEN) { log_error("file '%s' shorter than LBX header (%u < %u)\n", filename, len, LBX_HEADER_LEN); return false; } ctx->len = len; v16 = GET_LE_16(&data[2]); if (v16 != 0xfead) { log_error("file '%s' has wrong signature 0x%04x!\n", filename, v16); return false; } v16 = GET_LE_16(&data[6]); ctx->type = v16; v16 = GET_LE_16(data); if (v16 > LBX_MAX_ENTRIES) { log_error("file '%s' has too many entries (%u < %u)\n", filename, v16, LBX_MAX_ENTRIES); return false; } ctx->entries = num = v16; for (uint8_t i = 0; i < num; ++i) { memcpy(ctx->item[i].desc, (const char *)&(ctx->data[LBX_HEADER_LEN + LBX_DESC_LEN * i]), LBX_DESC_LEN); ctx->item[i].desc[LBX_DESC_LEN] = '\0'; } for (uint8_t i = 0; i < num; ++i) { uint32_t offs0, offs1; offs0 = GET_LE_32(&data[8 + i * 4]); offs1 = GET_LE_32(&data[8 + i * 4 + 4]); if ((offs0 > offs1) || (offs1 > len) || (offs0 < LBX_HEADER_LEN)) { log_error("file '%s' item %i invalid offsets 0x%x, 0x%x (len 0x%x)\n", filename, i, offs0, offs1, len); return false; } if (offs0 < (LBX_HEADER_LEN + LBX_DESC_LEN * num)) { uint8_t j; j = (offs0 - LBX_HEADER_LEN) / 0x20; log_warning("file '%s' item %i starts early at 0x%x (expected >= 0x%x), invalidating name/desc of items %i..%i\n", filename, i, offs0, LBX_HEADER_LEN + LBX_DESC_LEN * num, j, num - 1); for (; j < num; ++j) { memset(ctx->item[j].desc, 0, LBX_DESC_LEN); } } ctx->item[i].start = offs0; ctx->item[i].len = offs1 - offs0; ctx->item[i].data = &(ctx->data[offs0]); } { uint32_t offs0 = GET_LE_32(&data[8 + num * 4]); ctx->item[num].start = offs0; ctx->item[num].len = 0; ctx->item[num].data = 0; } return true; } static int lbxedit_dump_desc(FILE *fd, const char *str) { int len; if (fprintf(fd, "\"") < 0) { return -1; } for (len = LBX_DESC_LEN - 1; (len >= 0) && (str[len] == '\0'); --len); ++len; for (int i = 0; i < len; ++i) { char c, c0; c = str[i]; switch (c) { case '\\': case '"': c0 = '\\'; break; case '\n': c0 = '\\'; c = 'n'; break; case '\r': c0 = '\\'; c = 'r'; break; default: c0 = 0; if ((c < 0x20) || (c > 0x7e)) { const char hexchars[0x10] = "0123456789abcdef"; char buf[4]; buf[0] = '\\'; buf[1] = 'x'; buf[2] = hexchars[(c >> 4) & 0xf]; buf[3] = hexchars[c & 0xf]; c = 0; if (fwrite(buf, 4, 1, fd) < 1) { return -1; } } break; } if (0 || (c0 && (fputc(c0, fd) == EOF)) || (c && (fputc(c, fd) == EOF)) ) { return -1; } } if (fprintf(fd, "\"") < 0) { return -1; } return 0; } static int lbxedit_do_dump(struct lbxedit_s *ctx, const char *filename_lbx, const char *prefix_out, bool flag_write) { FILE *fd = 0; char *fname_lbxin = NULL, *dir = NULL, *fnam = NULL, *prefix = NULL, *prefix_file = NULL, *lbxin = NULL; int res = -1; if (!lbxedit_load_lbx(ctx, filename_lbx)) { return -1; } prefix = lib_stralloc(prefix_out ? prefix_out : filename_lbx); { char *p; p = strrchr(prefix, '.'); if (p && (strcasecmp(p + 1, "lbx") == 0) && ((*(p + 4)) == '\0')) { *p = '\0'; } } util_fname_split(prefix, &dir, &fnam); if (dir) { if (flag_write && os_make_path(dir)) { log_error("creating path '%s'\n", dir); return -1; } fname_lbxin = util_concat(dir, FSDEV_DIR_SEP_STR, fnam, ".lbxin", NULL); prefix_file = fnam; } else { prefix_file = prefix; fname_lbxin = util_concat(prefix, ".lbxin", NULL); } if (flag_write) { lbxin = fname_lbxin; fd = fopen(fname_lbxin, "w+"); if (!fd) { log_error("opening '%s' for writing\n", lbxin); goto fail; } } else { fd = stdout; lbxin = "(stdout)"; } if (fprintf(fd, "# 1oom_lbxedit dump of '%s', %u entries, len 0x%x\nt%i\n", filename_lbx, ctx->entries, ctx->len, ctx->type) < 0) { log_error("writing to '%s'\n", lbxin); goto fail; } for (uint8_t i = 0; i < ctx->entries; ++i) { char buf[FSDEV_PATH_MAX]; const struct lbxedit_item_s *p = &(ctx->item[i]); uint32_t len; len = p->len; if (len == 0) { lib_sprintf(buf, sizeof(buf), "0"); } else { lib_sprintf(buf, sizeof(buf), "%s_%03i.bin", prefix_file, i); } if (0 || (fprintf(fd, "# %i 0x%x..0x%x (0x%x)\n", i, p->start, p->start + len, len) < 0) || (lbxedit_dump_desc(fd, p->desc) < 0) || (fprintf(fd, "%c%s\n", SEP_CHAR, buf) < 0) ) { log_error("writing to '%s'\n", lbxin); goto fail; } if (flag_write && len) { lib_sprintf(buf, sizeof(buf), "%s_%03i.bin", prefix, i); if (util_file_save(buf, p->data, len) < 0) { log_error("writing '%s'!\n", buf); goto fail; } } } res = 0; fail: if (flag_write && fd) { fclose(fd); fd = NULL; } lib_free(fname_lbxin); lib_free(dir); lib_free(fnam); lib_free(prefix); return res; } static int lbxedit_do_extract(struct lbxedit_s *ctx, const char *filename_lbx, const char *filename_out, bool flag_write, int itemnum) { if (!lbxedit_load_lbx(ctx, filename_lbx)) { return -1; } if ((itemnum < 0) || (itemnum >= ctx->entries)) { fprintf(stderr, "invalid itemnum %i, must be 0 <= N < %u\n", itemnum, ctx->entries); return -1; } if (flag_write) { const struct lbxedit_item_s *p = &(ctx->item[itemnum]); if (util_file_save(filename_out, p->data, p->len) < 0) { log_error("writing '%s'!\n", filename_out); return -1; } } return 0; } static bool isnl(char c) { return (c == '\r') || (c == '\n'); } static bool isws(char c) { return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); } static int skipws(const char *str, int i, int len) { while ((i < len) && isws(str[i])) { ++i; } return i; } static int lbxedit_parsedesc(char *str, int i, int len, char *dst) { uint32_t dlen; int slen; memset(dst, 0, LBX_DESC_LEN + 1); if (str[i] != '\"') { log_error("missing start '\"' at %i\n", i); return -1; } if ((slen = util_cstr_parse(&(str[i]), &(str[i]), &dlen)) < 0) { return -1; } if (dlen > LBX_DESC_LEN) { log_error("desc too long (%i > %i)\n", dlen, LBX_DESC_LEN); return -1; } memcpy(dst, &(str[i]), dlen); i += slen; if (str[i] != SEP_CHAR) { log_error("missing '%c' after '\"' at %i\n", SEP_CHAR, i); return -1; } return ++i; } static int lbxedit_do_make(struct lbxedit_s *ctx, const char *filename_lbxin, const char *filename_lbx, bool flag_write) { FILE *fd = NULL; int i, num_items = 0, res = -1; uint32_t len = 0; char *dir = NULL; char *listfiledata = (char *)util_file_load(filename_lbxin, &len); if (!listfiledata) { return -1; } util_fname_split(filename_lbxin, &dir, NULL); i = 0; ctx->data = NULL; ctx->type = 0; while ((i < len) && (listfiledata[i] != '\0')) { i = skipws(listfiledata, i, len); if (listfiledata[i] == '\0') { break; } else if (listfiledata[i] == '#') { } else if (listfiledata[i] == 't') { ctx->type = listfiledata[++i] - '0'; } else { struct lbxedit_item_s *p; if (num_items >= LBX_MAX_ENTRIES) { log_error("too manu entries (max %i)\n", LBX_MAX_ENTRIES); goto fail; } p = &(ctx->item[num_items]); if ((i = lbxedit_parsedesc(listfiledata, i, len, p->desc)) < 0) { goto fail; } { const char *fname; char *fullname; uint32_t l; uint8_t *data; fname = (char *)&(listfiledata[i]); while ((i < len) && !isnl(listfiledata[i])) { ++i; } if ((i >= len) || !isnl(listfiledata[i])) { log_error("partial line near byte %i\n", i); return -1; } listfiledata[i] = '\0'; ++i; if (strcmp(fname, "0") == 0) { data = NULL; l = 0; } else { if (dir && *dir) { fullname = util_concat(dir, FSDEV_DIR_SEP_STR, fname, NULL); } else { fullname = lib_stralloc(fname); } data = util_file_load(fullname, &l); lib_free(fullname); if (!data) { goto fail; } } p->data = data; p->len = l; } ++num_items; } while ((i < len) && !isnl(listfiledata[i])) { ++i; } } /* make header */ { uint32_t offs; offs = LBX_HEADER_LEN + LBX_DESC_LEN * num_items; ctx->data = lib_malloc(offs); ctx->len = offs; SET_LE_16(&ctx->data[0], num_items); SET_LE_16(&ctx->data[2], 0xfead); SET_LE_16(&ctx->data[6], ctx->type); for (int i = 0; i < num_items; ++i) { struct lbxedit_item_s *p = &(ctx->item[i]); p->start = offs; SET_LE_32(&ctx->data[8 + i * 4], offs); offs += p->len; memcpy(&(ctx->data[LBX_HEADER_LEN + i * LBX_DESC_LEN]), p->desc, LBX_DESC_LEN); } SET_LE_32(&ctx->data[8 + num_items * 4], offs); } /* save lbx */ if (flag_write) { fd = fopen(filename_lbx, "wb"); if (0 || (!fd) || (fwrite(ctx->data, ctx->len, 1, fd) != 1) ) { perror(filename_lbx); goto fail; } for (int i = 0; i < num_items; ++i) { struct lbxedit_item_s *p = &(ctx->item[i]); if (p->len && (fwrite(p->data, p->len, 1, fd) != 1)) { perror(filename_lbx); goto fail; } } } res = 0; fail: if (fd) { fclose(fd); fd = NULL; } lib_free(listfiledata); listfiledata = NULL; lib_free(ctx->data); ctx->data = NULL; for (int i = 0; i < num_items; ++i) { struct lbxedit_item_s *p = &(ctx->item[i]); if (p->data) { lib_free(p->data); p->data = NULL; } } return res; } static int lbxedit_do_replace(struct lbxedit_s *ctx, const char *filename_lbx_in, const char *filename_lbx_out, const char *filename_in, bool flag_write, int itemnum) { if (!lbxedit_load_lbx(ctx, filename_lbx_in)) { return -1; } if ((itemnum < 0) || (itemnum >= ctx->entries)) { fprintf(stderr, "invalid itemnum %i, must be 0 <= N < %u\n", itemnum, ctx->entries); return -1; } { struct lbxedit_item_s *p = &(ctx->item[itemnum]); uint8_t *data = NULL, *lbxdata = NULL; uint32_t lenold, lennew = 0, o1old; int lendiff; if (strcmp(filename_in, "0") != 0) { data = util_file_load(filename_in, &lennew); if (!data) { return false; } } lenold = p->len; lendiff = lennew - lenold; p->data = data; p->len = lennew; o1old = p[1].start; for (int i = itemnum + 1; i <= ctx->entries; ++i) { struct lbxedit_item_s *q = &(ctx->item[i]); uint32_t offs; offs = q->start; offs += lendiff; q->start = offs; SET_LE_32(&ctx->data[8 + i * 4], offs); } lbxdata = lib_malloc(ctx->len + lendiff); { uint32_t pos = 0, len; len = p->start; memcpy(&lbxdata[pos], ctx->data, len); pos += len; len = lennew; memcpy(&lbxdata[pos], data, len); pos += len; len = ctx->len - o1old; if (len) { memcpy(&lbxdata[pos], &(ctx->data[o1old]), len); pos += len; } ctx->len = pos; } lib_free(data); lib_free(ctx->data); ctx->data = lbxdata; ctx->filename_lbx = filename_lbx_out; if (flag_write) { if (util_file_save(ctx->filename_lbx, ctx->data, ctx->len) < 0) { log_error("writing '%s'!\n", ctx->filename_lbx); return -1; } } } return 0; } /* -------------------------------------------------------------------------- */ static void show_usage(void) { fprintf(stderr, "Usage:\n" " 1oom_lbxedit [OPTIONS] d IN.LBX [OUTPREFIX]\n" " 1oom_lbxedit [OPTIONS] m LBXIN.TXT OUT.LBX\n" " 1oom_lbxedit [OPTIONS] e IN.LBX OUT.BIN ITEMNUM\n" " 1oom_lbxedit [OPTIONS] r FILE.LBX IN.BIN|0 ITEMNUM\n" "Commands:\n" " d Dump LBX file to LBXIN + bin files\n" " m Make LBX file from LBXIN + bin files\n" " e Extract item from LBX file\n" " r Replace item in LBX file\n" "Options:\n" " -w (d, r) Write files\n" " -o OUT.LBX (r) Set output LBX filename\n" ); } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { const char *filename_in; const char *filename_out = NULL, *filename_lbx_out = NULL; bool flag_write = false; char cmd; int i, res = 1; lbxedit_init(&lbxedit_ctx); i = 1; if (i >= argc) { goto fail; } while (argv[i][0] == '-') { if (argv[i][2] != '\0') { show_usage(); return 1; } switch (argv[i][1]) { case 'w': flag_write = true; break; case 'o': if (++i >= argc) { goto fail; } filename_lbx_out = argv[i]; break; default: goto fail; } ++i; } if ((i + 1) >= argc) { goto fail; } { const char *cmd_str; cmd_str = argv[i++]; if ((cmd_str[1] != '\0') || (strchr("edmr", cmd_str[0]) == 0)) { goto fail; } cmd = cmd_str[0]; } filename_in = argv[i++]; if (i < argc) { filename_out = argv[i++]; } switch (cmd) { case 'd': if (i < argc) { goto fail; } res = lbxedit_do_dump(&lbxedit_ctx, filename_in, filename_out, flag_write); break; case 'm': if (!filename_out) { fprintf(stderr, "output filename missing\n"); goto fail; } if (i < argc) { goto fail; } res = lbxedit_do_make(&lbxedit_ctx, filename_in, filename_out, true); break; case 'e': if (!filename_out) { fprintf(stderr, "output filename missing\n"); goto fail; } if (i >= argc) { fprintf(stderr, "item number missing\n"); goto fail; } { int itemnum; itemnum = atoi(argv[i++]); if (i < argc) { goto fail; } res = lbxedit_do_extract(&lbxedit_ctx, filename_in, filename_out, true, itemnum); } break; case 'r': if (!filename_out) { fprintf(stderr, "input filename missing\n"); goto fail; } if (i >= argc) { fprintf(stderr, "item number missing\n"); goto fail; } if (!filename_lbx_out) { filename_lbx_out = filename_in; } { int itemnum; itemnum = atoi(argv[i++]); if (i < argc) { goto fail; } res = lbxedit_do_replace(&lbxedit_ctx, filename_in, filename_lbx_out, filename_out, flag_write, itemnum); } break; default: break; } fail: lbxedit_shutdown(&lbxedit_ctx); if (res > 0) { show_usage(); } else if (res < 0) { res = -res; } return res; } 1oom-1.11.2/src/lbxfont.c000066400000000000000000000544661476061725400151110ustar00rootroot00000000000000#include "config.h" #include #include #include "lbxfont.h" #include "bits.h" #include "hw.h" #include "gfxscale.h" #include "lbx.h" #include "lbxpal.h" #include "lib.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ static uint8_t *lbxfontdata = 0; static uint8_t lbxfont_temp_color = 0; static int16_t lbxfont_temp_x = 0; static int16_t lbxfont_temp_y = 0; static uint8_t lbxfont_current_fontnum = 0; static uint8_t lbxfont_current_fonta2 = 0; static uint8_t lbxfont_current_fonta2b = 0; static uint8_t lbxfont_current_fonta4 = 0; #define SPLIT_STR_MAX_LINES 8 #define SPLIT_STR_MAX_LEN 1023 typedef struct split_str_s { int num; int x0[SPLIT_STR_MAX_LINES]; int x1[SPLIT_STR_MAX_LINES]; int y[SPLIT_STR_MAX_LINES]; int i[SPLIT_STR_MAX_LINES]; char buf[SPLIT_STR_MAX_LEN + 1]; } split_str_t; /* -------------------------------------------------------------------------- */ static int lbxfont_print_char_ret_x(int x, int y, char c, uint16_t pitch, int scale) { uint8_t *p = hw_video_get_buf() + (y * pitch + x) * scale; return x + lbxfont_plotchar(c, p, pitch, scale); } static void lbxfont_plotchar_limit(int x, int y, char c, int xskip, int char_w, int yskip, int char_h, uint16_t pitch, int scale) { uint16_t si = GET_LE_16(&lbxfontdata[0xaa + c * 2]); uint8_t *o, *q, *p = &lbxfontdata[si]; uint8_t *buf = hw_video_get_buf() + (y * pitch + x) * scale; while (xskip) { if (*p++ == 0x80) { --xskip; } } while (char_w) { uint8_t ybuf[0x50]; uint8_t b, h, col; for (int i = 0; i < char_h; ++i) { ybuf[i] = 0xff; } q = &ybuf[0]; while (1) { b = *p++; if (!(b & 0x80)) { h = (b >> 4); col = lbxfontdata[b & 0xf]; do { *q++ = col; } while (--h); } else if (b & 0x7f) { q += (b & 0x7f); } else { break; } } o = buf; buf += scale; q = &ybuf[yskip]; h = char_h - yskip; while (h--) { b = *q++; if (b == 0xff) { o += pitch * scale; } else { o = gfxscale_draw_pixel(o, b, pitch, scale); } } --char_w; } } static int lbxfont_print_char_ret_x_limit(int x, int y, char c, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { c -= 0x20; if ((c < 0) || (c > 0x5e)) { return x; } uint16_t char_h = lbxfontdata[0x10]; uint16_t gap_w = lbxfontdata[0x48]; int8_t char_w = lbxfontdata[0x4a + c]; if ((x < lx0) || ((x + char_w) > lx1) || (y < ly0) || ((y + char_h) > ly1)) { int xskip, yskip, h, x1 = x + char_w + gap_w; if (x < lx0) { xskip = lx0 - x; if (xskip >= char_w) { return x1; } x = lx0; char_w -= xskip; } else { xskip = 0; } if ((x + char_w) > lx1) { char_w = lx1 - x + 1; if (char_w < 1) { return x1; } } if (y < ly0) { yskip = ly0 - y; y = ly0; } else { yskip = 0; } if ((y + char_h) > ly1) { h = ly1 - y + 1; } else { h = char_h; } lbxfont_plotchar_limit(x, y, c, xskip, char_w, yskip, h, pitch, scale); return x1; } else { x = lbxfont_print_char_ret_x(x, y, c + 0x20, pitch, scale); } return x; } static int lbxfont_print_str_do(int x, int y, const char *str, bool change_color, int w, uint16_t pitch, int scale) { uint16_t i, v8 = 0, va = 0, vc = 0; char c; lbxfont_temp_x = x; lbxfont_temp_y = y; if (w != 0) { uint16_t num_space = 0; i = 0; while (1) { c = str[i]; if ((c == 0) || (c == 0x0d) || (c == 0x14) || (c == 0x19) || (c == 0x15) || (c == 0x1d)) { if (num_space == 0) { w = 0; } w -= lbxfont_calc_str_width(str); if (w <= 0) { w = 0; } else { va = w % num_space; vc = w / num_space; } break; } else { if (c == ' ') { ++num_space; } ++i; } } } i = 0; while ((c = str[i]) != 0) { switch (c) { case 1: if (change_color) { lbxfont_select_subcolors_0(); } break; case 2: case 4: if (change_color) { lbxfont_select_subcolors_13not1(); } break; case 3: if (change_color) { lbxfont_select_subcolors_13not2(); } break; case 0x0d: case 0x14: case 0x19: case 0x1d: lbxfont_temp_x = ((uint8_t)str[i + 1]) + x; ++i; break; case 0x15: return lbxfont_temp_x; default: lbxfont_temp_x = lbxfont_print_char_ret_x(lbxfont_temp_x, lbxfont_temp_y, c, pitch, scale); if ((w != 0) && (c == ' ')) { lbxfont_temp_x += vc; if (v8 < va) { ++lbxfont_temp_x; } ++v8; } break; } ++i; } return lbxfont_temp_x; } static int lbxfont_print_str_limit_do(int x, int y, const char *str, bool change_color, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { uint8_t h = lbxfontdata[0x10]; int w; lbxfont_temp_x = x; lbxfont_temp_y = y; char c; if (scale != 1) { lx0 /= scale; lx1 /= scale; ly0 /= scale; ly1 /= scale; } if ((y > ly1) || ((y + h) < ly0)) { return 0; } if (x > lx1) { return x; } w = lbxfont_calc_str_width(str); if ((x + w) < lx0) { return x + w; } while ((c = *str++) != 0) { switch (c) { case 1: if (change_color) { lbxfont_select_subcolors_0(); } break; case 2: case 4: if (change_color) { lbxfont_select_subcolors_13not1(); } break; case 3: if (change_color) { lbxfont_select_subcolors_13not2(); } break; case 0xd: return lbxfont_temp_x; default: lbxfont_temp_x = lbxfont_print_char_ret_x_limit(lbxfont_temp_x, lbxfont_temp_y, c, lx0, ly0, lx1, ly1, pitch, scale); break; } } return lbxfont_temp_x; } static int lbxfont_print_str_normal_do(int x, int y, const char *str, int w, uint16_t pitch, int scale) { uint16_t v2; v2 = lbxfontdata[0x12]; if (v2 != 0) { for (int i = 0; i < 0x10; ++i) { lbxfontdata[i] = lbxfont_temp_color; } if (v2 != 2) { lbxfont_print_str_do(x + 1, y + 1, str, false, w, pitch, scale); lbxfont_print_str_do(x, y + 1, str, false, w, pitch, scale); lbxfont_print_str_do(x + 1, y, str, false, w, pitch, scale); } if ((v2 != 1) && (v2 != 3)) { lbxfont_print_str_do(x - 1, y, str, false, w, pitch, scale); lbxfont_print_str_do(x - 1, y - 1, str, false, w, pitch, scale); lbxfont_print_str_do(x, y - 1, str, false, w, pitch, scale); } if ((v2 == 3) || (v2 == 5)) { lbxfont_print_str_do(x + 2, y + 2, str, false, w, pitch, scale); lbxfont_print_str_do(x + 1, y + 2, str, false, w, pitch, scale); lbxfont_print_str_do(x + 2, y + 1, str, false, w, pitch, scale); } if (v2 > 3) { lbxfont_print_str_do(x + 1, y - 1, str, false, w, pitch, scale); lbxfont_print_str_do(x - 1, y + 1, str, false, w, pitch, scale); } if (v2 == 5) { lbxfont_print_str_do(x + 2, y, str, false, w, pitch, scale); lbxfont_print_str_do(x, y + 2, str, false, w, pitch, scale); } lbxfont_select_subcolors(lbxfontdata[0x13]); } return lbxfont_print_str_do(x, y, str, true, w, pitch, scale); } static int lbxfont_print_str_normal_do_w0(int x, int y, const char *str, int w, uint16_t pitch, int scale) { if (w < 0) { w = 0; } return lbxfont_print_str_normal_do(x, y, str, w, pitch, scale); } static void lbxfont_split_str(int x, int y, int maxw, const char *str, split_str_t *s, uint16_t maxy) { int i = 0, j, x0, x1, w, pos_space, last_c, ty = y, xnext = -1; uint16_t line_h = lbxfontdata[0x44]; int16_t gap_w = lbxfontdata[0x48]; uint8_t char_h = lbxfontdata[0x10]; s->num = 0; strncpy(s->buf, str, SPLIT_STR_MAX_LEN); s->buf[SPLIT_STR_MAX_LEN] = 0; while (s->buf[i] != '\0') { if (xnext == -1) { x0 = x; } else { x0 = xnext; xnext = -1; } x1 = x + maxw - 1; { if ((ty + char_h) >= maxy) { s->num = 0; return; } w = x1 - x0 + 1; pos_space = -1; last_c = -1; for (j = i; -gap_w <= w; ++j) { uint8_t c; int cw; c = (uint8_t)s->buf[j]; if (c >= 0x20) { cw = lbxfontdata[0x4a + (c - 0x20)] + gap_w; w -= cw; if (c == 0x20) { pos_space = j; } } else { if ((c == 0x14) || (c == 0xd) || (c == 0) || (c == 0x19) || (c == 0x1d)) { w = -gap_w - 1; last_c = c; } } } if (last_c == 0) { --j; } s->x0[s->num] = x0; s->x1[s->num] = x1; s->y[s->num] = ty; s->i[s->num] = i; ++s->num; if (last_c != -1) { if (last_c == 0x19) { int v; v = (s->buf[j] - 0x30) * 10 + (s->buf[j/*bug?*/] - 0x30); ty = v - line_h; j += 2; } else if (last_c == 0x1d) { int v; v = (s->buf[j] - 0x30) * 10 + (s->buf[j/*bug?*/] - 0x30); ty -= line_h; xnext = v; j += 2; } i = j; } else { if (pos_space != -1) { s->buf[pos_space] = 0x15; i = pos_space + 1; } } } if ((x + maxw - 1) > x1) { xnext = x1 + 1; } else { ty += line_h; } } } static uint16_t lbxfont_plotchar_1x(char c, uint8_t *buf, uint16_t pitch) { uint8_t char_w = lbxfontdata[0x4a + c]; uint16_t gap_w = lbxfontdata[0x48]; uint16_t w = char_w + gap_w; uint16_t si = GET_LE_16(&lbxfontdata[0xaa + c * 2]); uint8_t *p = &lbxfontdata[si]; uint8_t *q = buf; while (char_w) { uint8_t b, h, col; b = *p++; if (!(b & 0x80)) { h = (b >> 4); col = lbxfontdata[b & 0xf]; do { *q = col; q += pitch; } while (--h); } else if (b & 0x7f) { q += (b & 0x7f) * pitch; } else { ++buf; q = buf; --char_w; } } return w; } static uint16_t lbxfont_plotchar_nx(char c, uint8_t *buf, uint16_t pitch, int scale) { uint8_t char_w = lbxfontdata[0x4a + c]; uint16_t gap_w = lbxfontdata[0x48]; uint16_t w = char_w + gap_w; uint16_t si = GET_LE_16(&lbxfontdata[0xaa + c * 2]); uint8_t *p = &lbxfontdata[si]; uint8_t *q = buf; while (char_w) { uint8_t b, h, col; b = *p++; if (!(b & 0x80)) { h = (b >> 4); col = lbxfontdata[b & 0xf]; do { q = gfxscale_draw_pixel(q, col, pitch, scale); } while (--h); } else if (b & 0x7f) { q += (b & 0x7f) * pitch * scale; } else { buf += scale; q = buf; --char_w; } } return w; } /* -------------------------------------------------------------------------- */ int lbxfont_init(void) { uint8_t *fontdata = lbxfile_item_get(LBXFILE_FONTS, 0); lbxfontdata = fontdata; return 0; } void lbxfont_shutdown(void) { if (lbxfontdata) { lbxfile_item_release(LBXFILE_FONTS, lbxfontdata); lbxfontdata = 0; } } void lbxfont_select(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3) { uint16_t t; if (a1 >= 0x10) { a1 = 0; } if (a2 >= 0x10) { a2 = 0; } if (a3 >= 0x10) { a3 = 0; } lbxfont_current_fontnum = a0; lbxfont_current_fonta2 = a1; lbxfont_current_fonta2b = a2; lbxfont_current_fonta4 = a3; memcpy(&(lbxfontdata[0x00]), &(lbxpal_fontcolors[a1 << 4]), 0x10); memcpy(&(lbxfontdata[0x14]), &(lbxpal_fontcolors[a1 << 4]), 0x10); memcpy(&(lbxfontdata[0x24]), &(lbxpal_fontcolors[a2 << 4]), 0x10); memcpy(&(lbxfontdata[0x34]), &(lbxpal_fontcolors[a3 << 4]), 0x10); memcpy(&(lbxfontdata[0x10]), &(lbxfontdata[(a0 << 1) + 0x16a]), 0x2); t = GET_LE_16(&(lbxfontdata[(a0 << 1) + 0x18a])); SET_LE_16(&(lbxfontdata[0x46]), t); t += GET_LE_16(&(lbxfontdata[0x10])); SET_LE_16(&(lbxfontdata[0x44]), t); t = GET_LE_16(&(lbxfontdata[(a0 << 1) + 0x17a])); SET_LE_16(&(lbxfontdata[0x48]), t); SET_LE_16(&(lbxfontdata[0x12]), 0); memcpy(&(lbxfontdata[0x4a]), &(lbxfontdata[(a0 * 0x60) + 0x19a]), 0x60); memcpy(&(lbxfontdata[0xaa]), &(lbxfontdata[(a0 * 0xc0) + 0x49a]), 0xc0); } void lbxfont_select_set_12_1(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3) { lbxfont_select(a0, a1, a2, a3); SET_LE_16(&(lbxfontdata[0x12]), 1); } void lbxfont_select_set_12_4(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3) { lbxfont_select(a0, a1, a2, a3); SET_LE_16(&(lbxfontdata[0x12]), 4); } void lbxfont_select_set_12_5(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3) { lbxfont_select(a0, a1, a2, a3); SET_LE_16(&(lbxfontdata[0x12]), 5); } uint16_t lbxfont_get_height(void) { return GET_LE_16(&(lbxfontdata[0x10])); } int lbxfont_get_gap_h(void) { return ((uint16_t)lbxfontdata[0x44]) - GET_LE_16(&(lbxfontdata[0x10])); } void lbxfont_set_gap_h(uint16_t value) { value += GET_LE_16(&(lbxfontdata[0x10])); SET_LE_16(&(lbxfontdata[0x44]), value); } void lbxfont_select_subcolors(uint16_t a0) { memcpy(&(lbxfontdata[0x00]), &(lbxfontdata[(a0 << 4) + 0x14]), 0x10); lbxfontdata[0x13] = a0; } void lbxfont_select_subcolors_0(void) { lbxfont_select_subcolors(0); } void lbxfont_select_subcolors_13not1(void) { lbxfont_select_subcolors((lbxfontdata[0x13] == 1) ? 0 : 1); } void lbxfont_select_subcolors_13not2(void) { lbxfont_select_subcolors((lbxfontdata[0x13] == 2) ? 0 : 2); } void lbxfont_set_colors(const uint8_t *colorptr) { memcpy(&(lbxfontdata[0x00]), colorptr, 0x10); } void lbxfont_set_colors_n(const uint8_t *colorptr, int num) { memcpy(&(lbxfontdata[0x00]), colorptr, num); } void lbxfont_set_color_c_n(uint8_t color, int num) { memset(&(lbxfontdata[0x00]), color, num); } void lbxfont_set_color0(uint8_t color) { lbxfontdata[0x00] = color; } void lbxfont_set_temp_color(uint8_t color) { lbxfont_temp_color = color; } void lbxfont_set_14_24(uint8_t color1, uint8_t color2) { for (int i = 0; i < 0x10; ++i) { lbxfontdata[0x14 + i] = color1; lbxfontdata[0x24 + i] = color2; } } uint16_t lbxfont_plotchar(char c, uint8_t *buf, uint16_t pitch, int scale) { if (c < 0x20) { return 0; } c -= 0x20; if (scale == 1) { return lbxfont_plotchar_1x(c, buf, pitch); } else { return lbxfont_plotchar_nx(c, buf, pitch, scale); } } void lbxfont_set_space_w(int w) { lbxfontdata[0x4a] = w; } int lbxfont_get_gap_w(void) { return lbxfontdata[0x48]; } int lbxfont_get_char_w(char c) { if ((c >= 0x20) && (c <= 0x7e)) { return lbxfontdata[0x4a + c - 0x20]; } return lbxfontdata[0x48]; } int lbxfont_calc_str_width(const char *str) { uint16_t gap_w = lbxfontdata[0x48]; uint16_t w = 0; int16_t c; while (1) { c = *str++; c -= 0x20; if (c < 0) { c += 0x20; if ((c == 0) || (c == 0xd) || (c == 0x14) || (c == 0x15) || (c == 0x19) || (c == 0x1d)) { return w - gap_w; } } else { if (c <= 0x5e) { w += lbxfontdata[0x4a + c]; } w += gap_w; } } } int lbxfont_calc_split_str_h(int maxw, const char *str) { split_str_t s; lbxfont_split_str(0, 0, maxw, str, &s, 200/*irrelevant*/); return s.y[s.num - 1] + GET_LE_16(&(lbxfontdata[0x10])); } int lbxfont_print_str_normal(int x, int y, const char *str, uint16_t pitch, int scale) { return lbxfont_print_str_normal_do(x, y, str, 0, pitch, scale); } int lbxfont_print_str_center(int x, int y, const char *str, uint16_t pitch, int scale) { int w = lbxfont_calc_str_width(str); return lbxfont_print_str_normal(x - w / 2, y, str, pitch, scale); } int lbxfont_print_str_right(int x, int y, const char *str, uint16_t pitch, int scale) { int w = lbxfont_calc_str_width(str) - 1; return lbxfont_print_str_normal(x - w, y, str, pitch, scale); } int lbxfont_print_str_normal_limit(int x, int y, const char *str, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { uint16_t v2; v2 = lbxfontdata[0x12]; if (v2 != 0) { for (int i = 0; i < 0x10; ++i) { lbxfontdata[i] = lbxfont_temp_color; } if (v2 != 2) { lbxfont_print_str_limit_do(x + 1, y + 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x, y + 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x + 1, y, str, false, lx0, ly0, lx1, ly1, pitch, scale); } if ((v2 != 1) && (v2 != 3)) { lbxfont_print_str_limit_do(x - 1, y, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x - 1, y - 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x, y - 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); } if ((v2 == 3) || (v2 == 5)) { lbxfont_print_str_limit_do(x + 2, y + 2, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x + 1, y + 2, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x + 2, y + 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); } if (v2 > 3) { lbxfont_print_str_limit_do(x + 1, y - 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x - 1, y + 1, str, false, lx0, ly0, lx1, ly1, pitch, scale); } if (v2 == 5) { lbxfont_print_str_limit_do(x + 2, y, str, false, lx0, ly0, lx1, ly1, pitch, scale); lbxfont_print_str_limit_do(x, y + 2, str, false, lx0, ly0, lx1, ly1, pitch, scale); } lbxfont_select_subcolors(lbxfontdata[0x13]); } return lbxfont_print_str_limit_do(x, y, str, true, lx0, ly0, lx1, ly1, pitch, scale); } int lbxfont_print_str_center_limit(int x, int y, const char *str, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { int w = lbxfont_calc_str_width(str); return lbxfont_print_str_normal_limit(x - w / 2, y, str, lx0, ly0, lx1, ly1, pitch, scale); } void lbxfont_print_str_split(int x, int y, int maxw, const char *str, int type, uint16_t pitch, uint16_t maxy, int scale) { split_str_t s; lbxfont_split_str(x, y, maxw, str, &s, maxy); for (int i = 0; i < s.num; ++i) { switch (type) { case 0: lbxfont_print_str_normal(s.x0[i], s.y[i], &s.buf[s.i[i]], pitch, scale); break; case 1: lbxfont_print_str_right(s.x1[i], s.y[i], &s.buf[s.i[i]], pitch, scale); break; case 2: lbxfont_print_str_center((s.x0[i] + s.x1[i]) / 2, s.y[i], &s.buf[s.i[i]], pitch, scale); break; case 3: if (i != (s.num - 1)) { lbxfont_print_str_normal_do_w0(s.x0[i], s.y[i], &s.buf[s.i[i]], s.x1[i] - s.x0[i], pitch, scale); } else { lbxfont_print_str_normal(s.x0[i], s.y[i], &s.buf[s.i[i]], pitch, scale); } break; default: break; } } } int lbxfont_print_num_normal(int x, int y, int num, uint16_t pitch, int scale) { char buf[16]; lib_sprintf(buf, sizeof(buf), "%i", num); return lbxfont_print_str_normal(x, y, buf, pitch, scale); } int lbxfont_print_num_center(int x, int y, int num, uint16_t pitch, int scale) { char buf[16]; lib_sprintf(buf, sizeof(buf), "%i", num); return lbxfont_print_str_center(x, y, buf, pitch, scale); } int lbxfont_print_num_right(int x, int y, int num, uint16_t pitch, int scale) { char buf[16]; lib_sprintf(buf, sizeof(buf), "%i", num); return lbxfont_print_str_right(x, y, buf, pitch, scale); } int lbxfont_print_range_right(int x, int y, int num0, int num1, uint16_t pitch, int scale) { char buf[32]; lib_sprintf(buf, sizeof(buf), "%i-%i", num0, num1); return lbxfont_print_str_right(x, y, buf, pitch, scale); } uint8_t lbxfont_get_current_fontnum(void) { return lbxfont_current_fontnum; } uint8_t lbxfont_get_current_fonta2(void) { return lbxfont_current_fonta2; } uint8_t lbxfont_get_current_fonta2b(void) { return lbxfont_current_fonta2b; } uint8_t lbxfont_get_current_fonta4(void) { return lbxfont_current_fonta4; } 1oom-1.11.2/src/lbxfont.h000066400000000000000000000052351476061725400151040ustar00rootroot00000000000000#ifndef INC_1OOM_LBXFONT_H #define INC_1OOM_LBXFONT_H #include "types.h" extern int lbxfont_init(void); extern void lbxfont_shutdown(void); extern void lbxfont_select(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3); extern void lbxfont_select_set_12_1(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3); extern void lbxfont_select_set_12_4(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3); extern void lbxfont_select_set_12_5(uint8_t a0, uint8_t a1, uint8_t a2, uint8_t a3); extern uint16_t lbxfont_get_height(void); extern int lbxfont_get_gap_h(void); extern void lbxfont_set_gap_h(uint16_t value); extern void lbxfont_select_subcolors(uint16_t a0); extern void lbxfont_select_subcolors_0(void); extern void lbxfont_select_subcolors_13not1(void); extern void lbxfont_select_subcolors_13not2(void); extern void lbxfont_set_colors(const uint8_t *colorptr); extern void lbxfont_set_colors_n(const uint8_t *colorptr, int num); extern void lbxfont_set_color_c_n(uint8_t color, int num); extern void lbxfont_set_color0(uint8_t color); extern void lbxfont_set_temp_color(uint8_t color); extern void lbxfont_set_14_24(uint8_t color1, uint8_t color2); extern void lbxfont_set_space_w(int w); extern int lbxfont_get_gap_w(void); extern int lbxfont_get_char_w(char c); extern int lbxfont_calc_str_width(const char *str); extern int lbxfont_calc_split_str_h(int maxw, const char *str); extern uint16_t lbxfont_plotchar(char c, uint8_t *buf, uint16_t pitch, int scale); extern int lbxfont_print_str_normal(int x, int y, const char *str, uint16_t pitch, int scale); extern int lbxfont_print_str_center(int x, int y, const char *str, uint16_t pitch, int scale); extern int lbxfont_print_str_right(int x, int y, const char *str, uint16_t pitch, int scale); extern void lbxfont_print_str_split(int x, int y, int maxw, const char *str, int type, uint16_t pitch, uint16_t maxy, int scale); extern int lbxfont_print_str_normal_limit(int x, int y, const char *str, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); extern int lbxfont_print_str_center_limit(int x, int y, const char *str, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); extern int lbxfont_print_num_normal(int x, int y, int num, uint16_t pitch, int scale); extern int lbxfont_print_num_center(int x, int y, int num, uint16_t pitch, int scale); extern int lbxfont_print_num_right(int x, int y, int num, uint16_t pitch, int scale); extern int lbxfont_print_range_right(int x, int y, int num0, int num1, uint16_t pitch, int scale); extern uint8_t lbxfont_get_current_fontnum(void); extern uint8_t lbxfont_get_current_fonta2(void); extern uint8_t lbxfont_get_current_fonta2b(void); extern uint8_t lbxfont_get_current_fonta4(void); #endif 1oom-1.11.2/src/lbxgfx.c000066400000000000000000000603511476061725400147150ustar00rootroot00000000000000#include "config.h" #include #include "lbxgfx.h" #include "comp.h" #include "hw.h" #include "gfxscale.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" /* -------------------------------------------------------------------------- */ static void lbxgfx_draw_pixels_fmt0(uint8_t *pixbuf, uint16_t w, uint8_t *data, uint16_t pitch) { uint8_t *q; uint8_t b, /*dh*/mode, /*dl*/len_total, len_run; while (w--) { q = pixbuf++; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular data */ do { len_run = *data++; q += pitch * *data++; len_total -= len_run + 2; do { *q = *data++; q += pitch; } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ do { len_run = *data++; q += pitch * *data++; len_total -= len_run + 2; do { b = *data++; if (b > 0xdf) { /* b-0xdf pixels, same color */ uint8_t len_compr; len_compr = b - 0xdf; --len_run; b = *data++; while (len_compr) { *q = b; q += pitch; --len_compr; } } else { *q = b; q += pitch; } } while (--len_run); } while (len_total >= 1); } } } static void lbxgfx_draw_pixels_fmt0_scale(uint8_t *pixbuf, uint16_t w, uint8_t *data, uint16_t pitch, int scale) { uint8_t *q; uint8_t b, /*dh*/mode, /*dl*/len_total, len_run; while (w--) { q = pixbuf; pixbuf += scale; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular data */ do { len_run = *data++; q += pitch * scale * *data++; len_total -= len_run + 2; do { b = *data++; q = gfxscale_draw_pixel(q, b, pitch, scale); } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ do { len_run = *data++; q += pitch * scale * *data++; len_total -= len_run + 2; do { b = *data++; if (b > 0xdf) { /* b-0xdf pixels, same color */ uint8_t len_compr; len_compr = b - 0xdf; --len_run; b = *data++; while (len_compr) { q = gfxscale_draw_pixel(q, b, pitch, scale); --len_compr; } } else { q = gfxscale_draw_pixel(q, b, pitch, scale); } } while (--len_run); } while (len_total >= 1); } } } static void lbxgfx_draw_pixels_offs_fmt0(int x0, int y0, int w, int h, int xskip, int yskip, uint8_t *data, uint16_t pitch) { /* FIXME this an unreadable goto mess */ uint8_t *p = hw_video_get_buf() + y0 * pitch + x0; uint8_t *q; uint8_t b, mode, len_total, len_run; int ylen; /* skip columns */ while (xskip--) { b = *data++; if (b != 0xff) { b = *data++; data += b; } } while (w--) { q = p++; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular data */ ylen = yskip; loc_10dcf: if (ylen != 0) { ylen -= data[1]; if (ylen > 0) { len_run = *data++; ylen -= len_run; if (ylen >= 0) { data += len_run + 1; len_total -= len_run + 2; if (len_total != 0) { goto loc_10dcf; } else { /*10e18*/ continue; /*goto loc_10e54*/ } } else { /*goto loc_10e83;*/ ++data; len_total -= len_run + 2; data += ylen + len_run; len_run = -ylen; ylen = h; goto loc_10e46; } } else { /*goto loc_10e78;*/ len_run = -ylen; ylen = h; goto loc_10e25; } } /*10e1b */ ylen = h; do { /*loc_10e20:*/ len_run = data[1]; /*really skip pixels...*/ loc_10e25: ylen -= len_run; q += len_run * pitch; len_run = *data++; ++data; len_total -= len_run + 2; loc_10e46: do { if (--ylen >= 0) { *q = *data++; q += pitch; } else { data += len_run; break; } } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ uint8_t len_compr; /*10e97*/ ylen = yskip; loc_10ea2: if (ylen != 0) { ylen -= data[1]; if (ylen > 0) { len_run = *data++; ++data; len_total -= len_run + 2; /*loc_10eb6:*/ do { b = *data++; if (b <= 0xdf) { if (--ylen >= 0) { /*continue;*/ } else { /*goto 10ec7*/ len_run += ylen; ylen = h - 1; ++len_run; goto loc_10f38; } } else { /*10ed3*/ ++data; ylen -= (b - 0xdf); if (ylen >= 0) { --len_run; /*continue;*/ } else { /*goto loc_10ef6;*/ --data; b = *data++; --len_run; len_compr = -ylen; ylen = h; goto loc_10f51; } } } while (--len_run); if (len_total >= 1) { goto loc_10ea2; } else { goto loc_10e54; } } else { /*goto loc_10eea;*/ len_run = -ylen; ylen = h; goto loc_10f0f; } } /*loc_10f05:*/ ylen = h; do { /*loc_10f0a:*/ len_run = data[1]; /*really skip pixels...*/ loc_10f0f: ylen -= len_run; q += len_run * pitch; len_run = *data++; ++data; len_total -= len_run + 2; /*loc_10f30:*/ do { if (--ylen >= 0) { b = *data++; if (b <= 0xdf) { loc_10f38: *q = b; q += pitch; } else { len_compr = b - 0xdf; b = *data++; --len_run; ++ylen; loc_10f51: do { if (--ylen >= 0) { *q = b; q += pitch; } else { --len_run; goto loc_10f7e; } } while (--len_compr); } } else { loc_10f7e: data += len_run; break; } } while (--len_run); } while (len_total >= 1); } loc_10e54: ; } } static void lbxgfx_draw_pixels_offs_fmt0_scale(int x0, int y0, int w, int h, int xskip, int yskip, uint8_t *data, uint16_t pitch, int scale) { /* FIXME this an unreadable goto mess */ uint8_t *p = hw_video_get_buf() + (y0 * pitch + x0) * scale; uint8_t *q; uint8_t b, mode, len_total, len_run; int ylen; /* skip columns */ while (xskip--) { b = *data++; if (b != 0xff) { b = *data++; data += b; } } while (w--) { q = p; p += scale; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular data */ ylen = yskip; locs_10dcf: if (ylen != 0) { ylen -= data[1]; if (ylen > 0) { len_run = *data++; ylen -= len_run; if (ylen >= 0) { data += len_run + 1; len_total -= len_run + 2; if (len_total != 0) { goto locs_10dcf; } else { continue; } } else { ++data; len_total -= len_run + 2; data += ylen + len_run; len_run = -ylen; ylen = h; goto locs_10e46; } } else { len_run = -ylen; ylen = h; goto locs_10e25; } } ylen = h; do { len_run = data[1]; /*really skip pixels...*/ locs_10e25: ylen -= len_run; q += len_run * pitch * scale; len_run = *data++; ++data; len_total -= len_run + 2; locs_10e46: do { if (--ylen >= 0) { q = gfxscale_draw_pixel(q, *data++, pitch, scale); } else { data += len_run; break; } } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ uint8_t len_compr; ylen = yskip; locs_10ea2: if (ylen != 0) { ylen -= data[1]; if (ylen > 0) { len_run = *data++; ++data; len_total -= len_run + 2; do { b = *data++; if (b <= 0xdf) { if (--ylen >= 0) { /*continue;*/ } else { len_run += ylen; ylen = h - 1; ++len_run; goto locs_10f38; } } else { ++data; ylen -= (b - 0xdf); if (ylen >= 0) { --len_run; /*continue;*/ } else { --data; b = *data++; --len_run; len_compr = -ylen; ylen = h; goto locs_10f51; } } } while (--len_run); if (len_total >= 1) { goto locs_10ea2; } else { goto locs_10e54; } } else { len_run = -ylen; ylen = h; goto locs_10f0f; } } ylen = h; do { len_run = data[1]; /*really skip pixels...*/ locs_10f0f: ylen -= len_run; q += len_run * pitch * scale; len_run = *data++; ++data; len_total -= len_run + 2; do { if (--ylen >= 0) { b = *data++; if (b <= 0xdf) { locs_10f38: q = gfxscale_draw_pixel(q, b, pitch, scale); } else { len_compr = b - 0xdf; b = *data++; --len_run; ++ylen; locs_10f51: do { if (--ylen >= 0) { q = gfxscale_draw_pixel(q, b, pitch, scale); } else { --len_run; goto locs_10f7e; } } while (--len_compr); } } else { locs_10f7e: data += len_run; break; } } while (--len_run); } while (len_total >= 1); } locs_10e54: ; } } static void lbxgfx_draw_pixels_fmt1(uint8_t *pixbuf, uint16_t w, uint8_t *data, uint16_t pitch) { uint8_t *q; uint8_t b, /*dh*/mode, /*dl*/len_total, len_run; while (w--) { q = pixbuf++; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular(ish) data */ do { len_run = *data++; q += pitch * *data++; len_total -= len_run + 2; do { /*loc_df66:*/ b = *data++; if (b >= 0xe8) { /*goto locs_df9c;*/ b -= 0xe8; b = lbxpal_colortable[b][*q]; } *q = b; q += pitch; } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ do { len_run = *data++; q += pitch * *data++; len_total -= len_run + 2; do { b = *data++; if (b > 0xdf) { /* b-0xdf pixels, same color */ uint8_t len_compr; len_compr = b - 0xdf; --len_run; b = *data++; if (b >= 0xe8) { uint8_t *tbl; b -= 0xe8; tbl = lbxpal_colortable[b]; while (len_compr) { b = tbl[*q]; *q = b; q += pitch; --len_compr; } } else { while (len_compr) { *q = b; q += pitch; --len_compr; } } } else { /* here is a test for b >= 0xe8 which is always false */ *q = b; q += pitch; } } while (--len_run); } while (len_total >= 1); } } } static void lbxgfx_draw_pixels_fmt1_scale(uint8_t *pixbuf, uint16_t w, uint8_t *data, uint16_t pitch, int scale) { uint8_t *q; uint8_t b, /*dh*/mode, /*dl*/len_total, len_run; while (w--) { q = pixbuf; pixbuf += scale; b = *data++; if (b == 0xff) { /* skip column */ continue; } mode = b; len_total = *data++; if ((mode & 0x80) == 0) { /* regular(ish) data */ do { len_run = *data++; q += pitch * scale * *data++; len_total -= len_run + 2; do { b = *data++; if (b >= 0xe8) { uint8_t *tbl; b -= 0xe8; tbl = lbxpal_colortable[b]; for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { q[sx] = tbl[q[sx]]; } q += pitch; } } else { q = gfxscale_draw_pixel(q, b, pitch, scale); } } while (--len_run); } while (len_total >= 1); } else { /* compressed data */ do { len_run = *data++; q += pitch * scale * *data++; len_total -= len_run + 2; do { b = *data++; if (b > 0xdf) { /* b-0xdf pixels, same color */ uint8_t len_compr; len_compr = b - 0xdf; --len_run; b = *data++; if (b >= 0xe8) { uint8_t *tbl; b -= 0xe8; tbl = lbxpal_colortable[b]; while (len_compr) { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { q[sx] = tbl[q[sx]]; } q += pitch; } --len_compr; } } else { while (len_compr) { q = gfxscale_draw_pixel(q, b, pitch, scale); --len_compr; } } } else { /* here is a test for b >= 0xe8 which is always false */ q = gfxscale_draw_pixel(q, b, pitch, scale); } } while (--len_run); } while (len_total >= 1); } } } /* -------------------------------------------------------------------------- */ void lbxgfx_draw_frame_do(uint8_t *p, uint8_t *data, uint16_t pitch, int scale) { uint16_t frame, next_frame, w; uint8_t *frameptr; w = lbxgfx_get_w(data); frame = lbxgfx_get_frame(data); frameptr = lbxgfx_get_frameptr(data, frame) + 1; if (lbxgfx_get_format(data) == 0) { if (scale == 1) { lbxgfx_draw_pixels_fmt0(p, w, frameptr, pitch); } else { lbxgfx_draw_pixels_fmt0_scale(p, w, frameptr, pitch, scale); } } else { if (scale == 1) { lbxgfx_draw_pixels_fmt1(p, w, frameptr, pitch); } else { lbxgfx_draw_pixels_fmt1_scale(p, w, frameptr, pitch, scale); } } next_frame = frame + 1; lbxgfx_set_frame(data, next_frame); if (next_frame >= lbxgfx_get_frames(data)) { next_frame = lbxgfx_get_frames2(data); } lbxgfx_set_frame(data, next_frame); } void lbxgfx_draw_frame(int x, int y, uint8_t *data, uint16_t pitch, int scale) { uint8_t *p = hw_video_get_buf() + (y * pitch + x) * scale; lbxgfx_draw_frame_do(p, data, pitch, scale); } void lbxgfx_draw_frame_pal(int x, int y, uint8_t *data, uint16_t pitch, int scale) { uint8_t *p; uint16_t frame; frame = lbxgfx_get_frame(data); if (frame == 0) { lbxgfx_apply_palette(data); } p = hw_video_get_buf() + (y * pitch + x) * scale; lbxgfx_draw_frame_do(p, data, pitch, scale); } void lbxgfx_draw_frame_offs_delay(int x, int y, bool next, uint8_t *data, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { int xskip, yskip, x0, y0, x1, y1, w, h; if ((x > lx1) || (y > ly1)) { return; } x1 = x + lbxgfx_get_w(data) - 1; if (x1 < lx0) { return; } y1 = y + lbxgfx_get_h(data) - 1; if (y1 < ly0) { return; } if (x >= lx0) { xskip = 0; x0 = x; } else { xskip = lx0 - x; x0 = lx0; } if (y >= ly0) { yskip = 0; y0 = y; } else { yskip = ly0 - y; y0 = ly0; } w = ((x1 < lx1) ? x1 : lx1) - x0 + 1; h = ((y1 < ly1) ? y1 : ly1) - y0 + 1; if (lbxgfx_get_epage(data) == 0) { lbxgfx_set_epage(data, 1); lbxgfx_apply_palette(data); } uint16_t frame; frame = lbxgfx_get_frame(data); if (lbxgfx_get_format(data) == 0) { if (scale == 1) { lbxgfx_draw_pixels_offs_fmt0(x0, y0, w, h, xskip, yskip, lbxgfx_get_frameptr(data, frame) + 1, pitch); } else { lbxgfx_draw_pixels_offs_fmt0_scale(x0, y0, w, h, xskip, yskip, lbxgfx_get_frameptr(data, frame) + 1, pitch, scale); } } else { log_fatal_and_die("%s: offs_fmt1 unimpl\n", __func__); } if (next) { ++frame; if (frame >= lbxgfx_get_frames(data)) { frame = lbxgfx_get_frames2(data); } lbxgfx_set_frame(data, frame); } } void lbxgfx_draw_frame_offs(int x, int y, uint8_t *data, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale) { lbxgfx_draw_frame_offs_delay(x, y, 1, data, lx0, ly0, lx1, ly1, pitch, scale); } void lbxgfx_set_new_frame(uint8_t *data, uint16_t newframe) { uint16_t frames = lbxgfx_get_frames(data); if (newframe >= frames) { uint16_t frames2 = lbxgfx_get_frames2(data); newframe = frames2 + (newframe - frames) % (frames - frames2); } lbxgfx_set_frame(data, newframe); } void lbxgfx_apply_colortable(int x0, int y0, int x1, int y1, uint8_t ctbli, uint16_t pitch, int scale) { uint8_t *pixbuf = hw_video_get_buf(); const uint8_t *tbl = lbxpal_colortable[ctbli]; x0 *= scale; y0 *= scale; x1 = x1 * scale + scale - 1; y1 = y1 * scale + scale - 1; for (int y = y0; y <= y1; ++y) { for (int x = x0; x <= x1; ++x) { pixbuf[y * pitch + x] = tbl[pixbuf[y * pitch + x]]; } } } void lbxgfx_apply_palette(uint8_t *data) { if (lbxgfx_has_palette(data)) { uint8_t *p = lbxgfx_get_palptr(data); int first = lbxgfx_get_palfirst(data); int num = lbxgfx_get_palnum(data); lbxpal_set_palette(p, first, num); } } 1oom-1.11.2/src/lbxgfx.h000066400000000000000000000050601476061725400147160ustar00rootroot00000000000000#ifndef INC_1OOM_LBXGFX_H #define INC_1OOM_LBXGFX_H #include "types.h" #include "bits.h" #define lbxgfx_get_w(_data_) GET_LE_16(&((_data_)[0x00])) #define lbxgfx_get_h(_data_) GET_LE_16(&((_data_)[0x02])) #define lbxgfx_get_frame(_data_) GET_LE_16(&((_data_)[0x04])) #define lbxgfx_set_frame(_data_, _v_) SET_LE_16(&((_data_)[0x04]), (_v_)) #define lbxgfx_set_frame_0(_data_) lbxgfx_set_frame((_data_), 0) #define lbxgfx_get_frames(_data_) GET_LE_16(&((_data_)[0x06])) #define lbxgfx_get_frames2(_data_) GET_LE_16(&((_data_)[0x08])) #define lbxgfx_get_ehandle(_data_) ((_data_)[0x0a]) #define lbxgfx_get_epage(_data_) ((_data_)[0x0b]) #define lbxgfx_set_epage(_data_, _v_) ((_data_)[0x0b] = (_v_)) #define lbxgfx_get_offs0c(_data_) GET_LE_16(&((_data_)[0x0c])) #define lbxgfx_get_paloffs(_data_) GET_LE_16(&((_data_)[0x0e])) #define lbxgfx_has_palette(_data_) (lbxgfx_get_paloffs(_data_) != 0) #define lbxgfx_get_indep(_data_) ((_data_)[0x10]) #define lbxgfx_get_format(_data_) ((_data_)[0x11]) #define lbxgfx_get_paldataoffs(_data_) GET_LE_16(&((_data_)[lbxgfx_get_paloffs(_data_)+0x00])) #define lbxgfx_get_palfirst(_data_) GET_LE_16(&((_data_)[lbxgfx_get_paloffs(_data_)+0x02])) #define lbxgfx_get_palnum(_data_) GET_LE_16(&((_data_)[lbxgfx_get_paloffs(_data_)+0x04])) #define lbxgfx_get_paloffs06(_data_) GET_LE_16(&((_data_)[lbxgfx_get_paloffs(_data_)+0x06])) #define lbxgfx_get_palptr(_data_) ((_data_) + lbxgfx_get_paldataoffs(_data_)) #define lbxgfx_get_frameoffs0(_data_, _frame_) (GET_LE_32(&((_data_)[0x12 + 4 * (_frame_)]))) #define lbxgfx_get_frameoffs1(_data_, _frame_) (GET_LE_32(&((_data_)[0x16 + 4 * (_frame_)]))) #define lbxgfx_get_frameptr(_data_, _frame_) ((_data_) + lbxgfx_get_frameoffs0((_data_), (_frame_))) #define lbxgfx_get_frameclearflag(_data_, _frame_) (*lbxgfx_get_frameptr((_data_), (_frame_))) extern void lbxgfx_draw_frame(int x, int y, uint8_t *data, uint16_t pitch, int scale); extern void lbxgfx_draw_frame_pal(int x, int y, uint8_t *data, uint16_t pitch, int scale); extern void lbxgfx_draw_frame_offs(int x, int y, uint8_t *data, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); extern void lbxgfx_draw_frame_offs_delay(int x, int y, bool next, uint8_t *data, int lx0, int ly0, int lx1, int ly1, uint16_t pitch, int scale); extern void lbxgfx_draw_frame_do(uint8_t *p, uint8_t *data, uint16_t pitch, int scale); extern void lbxgfx_set_new_frame(uint8_t *data, uint16_t newframe); extern void lbxgfx_apply_colortable(int x0, int y0, int x1, int y1, uint8_t ctbli, uint16_t pitch, int scale); extern void lbxgfx_apply_palette(uint8_t *data); #endif 1oom-1.11.2/src/lbxpal.c000066400000000000000000000145511476061725400147060ustar00rootroot00000000000000#include "config.h" #include #include #include "lbxpal.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "log.h" #include "types.h" /* -------------------------------------------------------------------------- */ uint8_t lbxpal_palette[256 * 3]; uint8_t lbxpal_update_flag[256]; uint8_t lbxpal_colortable[0x18][256]; uint8_t *lbxpal_palette_inlbx = 0; uint8_t *lbxpal_fontcolors = 0; uint8_t *lbxpal_cursors = 0; /* -------------------------------------------------------------------------- */ static uint8_t *lbxpal_ctableparam = 0; static void lbxpal_build_colortable(int ctablei, uint8_t pr, uint8_t pg, uint8_t pb, uint8_t percent) { uint8_t *tbl = lbxpal_colortable[ctablei]; int min_error_i, min_error_v; int v = 100 - percent; if (v > 0) { if (v < 100) { uint8_t temp_scale = (v * 0x100) / 100; uint8_t temp_mul = (percent * 0x100) / 100; uint8_t r_add = (pr * temp_mul) >> 8; uint8_t g_add = (pg * temp_mul) >> 8; uint8_t b_add = (pb * temp_mul) >> 8; for (int k = 0; k < 256; ++k) { uint8_t *p; uint8_t r, g, b; p = &lbxpal_palette_inlbx[k * 3]; r = (((*p++ * temp_scale) >> 8) + r_add) & 0xff; g = (((*p++ * temp_scale) >> 8) + g_add) & 0xff; b = (((*p++ * temp_scale) >> 8) + b_add) & 0xff; p = &lbxpal_palette_inlbx[0]; min_error_i = 0; min_error_v = 0x2710; for (int j = 0; j < 256; ++j) { uint16_t col_error; v = *p++ - r; if (v < 0) { v = -v; } p += 2; if (v >= 0x15) { continue; } col_error = v * v; p -= 2; v = *p++ - g; if (v < 0) { v = -v; } p += 1; if (v >= 0x15) { continue; } col_error += v * v; p -= 1; v = *p++ - b; if (v < 0) { v = -v; } if (v >= 0x15) { continue; } col_error += v * v; if (col_error < min_error_v) { min_error_v = col_error; min_error_i = j; } } tbl[k] = min_error_i; } } else { for (int i = 0; i < 256; ++i) { tbl[i] = i; } } } else { uint8_t *p; p = &lbxpal_palette_inlbx[0]; min_error_i = 0; min_error_v = 0x2710; for (int j = 0; j < 256; ++j) { uint16_t col_error; v = *p++ - pr; if (v < 0) { v = -v; } p += 2; if (v >= 0x15) { continue; } col_error = v * v; p -= 2; v = *p++ - pg; if (v < 0) { v = -v; } p += 1; if (v >= 0x15) { continue; } col_error += v * v; p -= 1; v = *p++ - pb; if (v < 0) { v = -v; } if (v >= 0x15) { continue; } col_error += v * v; if (col_error < min_error_v) { min_error_v = col_error; min_error_i = j; } } memset(tbl, min_error_i, 256); } } /* -------------------------------------------------------------------------- */ void lbxpal_select(int pal_index, int first/*or -1*/, int last) { uint8_t *pal = lbxfile_item_get(LBXFILE_FONTS, pal_index + 2); if (lbxpal_palette_inlbx) { lbxfile_item_release(LBXFILE_FONTS, lbxpal_palette_inlbx); } lbxpal_palette_inlbx = pal; lbxpal_fontcolors = pal + 0x300; lbxpal_cursors = pal + 0x500; lbxpal_ctableparam = pal + 0x1500; { int i, j, num; if (first < 0) { first = 0; num = 256; } else { num = last - first + 1; } i = first * 3; j = first; while (num) { uint8_t b; b = pal[i]; if (b != lbxpal_palette[i]) { lbxpal_update_flag[j] = 1; } lbxpal_palette[i++] = b; b = pal[i]; if (b != lbxpal_palette[i]) { lbxpal_update_flag[j] = 1; } lbxpal_palette[i++] = b; b = pal[i]; if (b != lbxpal_palette[i]) { lbxpal_update_flag[j] = 1; } lbxpal_palette[i++] = b; ++j; --num; } /* not done in MOO */ /*hw_video_set_palette(lbxpal_palette, 0, 256);*/ } lbxfont_select(0, 0, 0, 0); } void lbxpal_set_palette(uint8_t *pal, int first, int num) { memcpy(&lbxpal_palette[first * 3], pal, num * 3); lbxpal_set_update_range(first, first + num - 1); } void lbxpal_set_update_range(int from, int to) { while (from <= to) { lbxpal_update_flag[from++] = 1; } } void lbxpal_update(void) { memset(lbxpal_update_flag, 0, sizeof(lbxpal_update_flag)); hw_video_set_palette(lbxpal_palette, 0, 256); } void lbxpal_build_colortables(void) { lbxpal_build_colortable(0, 0, 0, 0, 0x32); for (int i = 1; i < 0x18; ++i) { uint8_t *p; p = lbxpal_ctableparam + i * 4; lbxpal_build_colortable(i, p[0], p[1], p[2], p[3]); } } uint8_t lbxpal_find_closest(uint8_t r, uint8_t g, uint8_t b) { uint8_t min_c = 0; int min_dist = 10000; uint8_t *p = lbxpal_palette; for (int i = 0; i < 256; ++i) { int dist; dist = abs(r - *p++); dist += abs(g - *p++); dist += abs(b - *p++); if (dist < min_dist) { min_dist = dist; min_c = i; if (dist == 0) { break; } } } return min_c; } int lbxpal_init(void) { memset(lbxpal_palette, 0, sizeof(lbxpal_palette)); lbxpal_update(); return 0; } void lbxpal_shutdown(void) { if (lbxpal_palette_inlbx) { lbxfile_item_release(LBXFILE_FONTS, lbxpal_palette_inlbx); lbxpal_palette_inlbx = 0; } } 1oom-1.11.2/src/lbxpal.h000066400000000000000000000013561476061725400147120ustar00rootroot00000000000000#ifndef INC_1OOM_LBXPAL_H #define INC_1OOM_LBXPAL_H #include "types.h" #define LBXPAL_NUM_PALETTES 10 extern uint8_t lbxpal_palette[256 * 3]; extern uint8_t lbxpal_update_flag[256]; extern uint8_t lbxpal_colortable[0x18][256]; extern uint8_t *lbxpal_palette_inlbx; extern uint8_t *lbxpal_fontcolors; extern uint8_t *lbxpal_cursors; extern int lbxpal_init(void); extern void lbxpal_shutdown(void); extern void lbxpal_select(int pal_index, int first/*or -1*/, int last); extern void lbxpal_set_palette(uint8_t *pal, int first, int num); extern void lbxpal_set_update_range(int from, int to); extern void lbxpal_update(void); extern void lbxpal_build_colortables(void); extern uint8_t lbxpal_find_closest(uint8_t r, uint8_t g, uint8_t b); #endif 1oom-1.11.2/src/lbxview.c000066400000000000000000000536231476061725400151070ustar00rootroot00000000000000#include "config.h" #include #include #include #include "main.h" #include "cfg.h" #include "comp.h" #include "fmt_mus.h" #include "fmt_pic.h" #include "fmt_sfx.h" #include "font8x8_draw.h" #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "options.h" #include "os.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ static const char *lbxview_font_filename = 0; /* -------------------------------------------------------------------------- */ const char *idstr_main = "lbxview"; bool main_use_lbx = true; bool main_use_cfg = true; bool ui_use_audio = true; void (*main_usage)(void) = 0; const struct cmdline_options_s main_cmdline_options_early[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; const struct cmdline_options_s main_cmdline_options[] = { { "-font", 1, options_set_str_var, (void *)&lbxview_font_filename, "FONT.BIN", "Set 8x8 font filename" }, { NULL, 0, NULL, NULL, NULL, NULL } }; const struct cfg_items_s game_cfg_items[] = { CFG_ITEM_STR("font", &lbxview_font_filename, 0), CFG_ITEM_END }; bool game_str_patch(const char *strid, const char *patchstr, int i) { /* ignore */ return true; } bool game_num_patch(const char *numid, int32_t *patchnums, int first, int num) { /* ignore */ return true; } void game_apply_rules(void) { } /* -------------------------------------------------------------------------- */ #define UI_SCREEN_W 320 #define UI_SCREEN_H 400 static bool in_lbx = false; static lbxfile_e cur_lbx; static int cur_items = LBXFILE_NUM; static int cursor_i = 0; static int cursor_offs = 0; static uint8_t *cur_ptr = NULL; static uint32_t cur_len = 0; static bool reset_frame = false; static bool advance_frame = false; static bool have_sfx = false; static bool have_mus = false; static bool flipx = false; static bool clearbeforedraw = false; static int test_rotate = 0; static int test_scale = 0; static uint8_t textcolor = 8; static uint32_t cur_key = 0; static int cur_xoff = 0; static int cur_yoff = 0; static struct gfx_aux_s gfxaux; static uint8_t romfont_08[256 * 8]; static bool have_romfont = false; /* -------------------------------------------------------------------------- */ static void drawchar_romfont(int dx, int dy, uint8_t c, uint8_t fg, uint8_t bg) { uint8_t *p = hw_video_get_buf() + dx + dy * 320; for (int y = 0; y < 8; ++y) { uint8_t b; b = romfont_08[c * 8 + y]; for (int x = 0; x < 8; ++x) { p[x] = (b & (1 << (7 - x))) ? fg : bg; } p += 320; } } static void drawchar(int dx, int dy, uint8_t c, uint8_t fg, uint8_t bg) { if (have_romfont) { drawchar_romfont(dx, dy, c, fg, bg); } else { font8x8_drawchar(dx, dy, 320, c, fg, bg); } } static void drawstr(int x, int y, const char *str, uint8_t fg, uint8_t bg) { char c; while ((c = *str++)) { drawchar(x, y, c, fg, bg); x += 8; if (x >= 320) { x = 0; y += 8; } } } static void drawstrlen(int x, int y, const char *str, int len, uint8_t fg, uint8_t bg) { char c; while (len--) { c = *str++; drawchar(x, y, c, fg, bg); x += 8; if (x >= 320) { x = 0; y += 8; } } } static void drawscreen_outlbx(void) { char linebuf[40 + 1]; for (lbxfile_e i = 0; i < LBXFILE_NUM; ++i) { drawstr(0, 0, " # Filename Type Items", textcolor, 0); lib_sprintf(linebuf, sizeof(linebuf), "%x", i); drawstr(1 * 8, 8 + ((int)i) * 8, linebuf, textcolor, 0); drawstr(4 * 8, 8 + ((int)i) * 8, lbxfile_name(i), textcolor, 0); if (lbxfile_exists(i)) { lib_sprintf(linebuf, sizeof(linebuf), "%u %u", lbxfile_type(i), lbxfile_num_items(i)); } else { lib_sprintf(linebuf, sizeof(linebuf), "? ?"); } drawstr(18 * 8, 8 + ((int)i) * 8, linebuf, textcolor, 0); drawchar(0, (cursor_i + 1) * 8, ' ', 0, textcolor); } for (int k = 0; k < 16; ++k) { uint8_t *p, *q; p = hw_video_get_buf() + 350 * 320 + k * 18; q = &lbxpal_cursors[16 * 16 * k]; for (int y = 0; y < 16; ++y) { for (int x = 0; x < 16; ++x) { p[x] = q[x * 16 + y]; } p += 320; } } lbxfont_select(5, 1, 0, 0); lbxfont_print_str_normal(0, 300 / (test_scale + 1), "Test string", UI_SCREEN_W, test_scale + 1); lib_sprintf(linebuf, sizeof(linebuf), "key 0x%x %c", cur_key, cur_key & 0xff); drawstr(0, 320, linebuf, textcolor, 0); } static void drawscreen_inlbx_rotate(void) { int x, y, x0, y0, x1, y1, angle, w, h, midx, midy, maxwh; midx = UI_SCREEN_W / 2; midy = 200 / 2; w = lbxgfx_get_w(cur_ptr); h = lbxgfx_get_h(cur_ptr); maxwh = MAX(w, h) * (test_scale + 1); if ((maxwh < 80) && (test_rotate == 1)) { angle = cur_xoff % 45; while (angle < 0) { angle += 360; } for (int i = 0; i < 8; ++i) { int xo, yo; x = util_math_angle_dist_cos(angle, maxwh); y = util_math_angle_dist_sin(angle, maxwh); xo = util_math_angle_dist_cos(angle, 90 - maxwh); yo = util_math_angle_dist_sin(angle, 90 - maxwh); x0 = (midx + xo - x / 2) / (test_scale + 1); y0 = (midy + yo - y / 2) / (test_scale + 1); x1 = (midx + xo + x / 2) / (test_scale + 1); y1 = (midy + yo + y / 2) / (test_scale + 1); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &gfxaux, 0, 0, UI_SCREEN_W - 1, 200 - 1, UI_SCREEN_W, test_scale + 1); angle = (angle + 45) % 360; } } else { angle = (cur_xoff + cur_yoff * 45) % 360; while (angle < 0) { angle += 360; } x = util_math_angle_dist_cos(angle, maxwh); y = util_math_angle_dist_sin(angle, maxwh); x0 = (midx - x / 2) / (test_scale + 1); y0 = (midy - y / 2) / (test_scale + 1); x1 = (midx + x / 2) / (test_scale + 1); y1 = (midy + y / 2) / (test_scale + 1); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &gfxaux, 0, 0, UI_SCREEN_W - 1, 200 - 1, UI_SCREEN_W, test_scale + 1); } } static void drawscreen_inlbx_data(const uint8_t *p, int len) { char linebuf[40 + 1]; int pos = cur_yoff * 40; if (pos >= len) { pos = (len / 40) * 40; if (pos == len) { pos -= 40; } SETMAX(pos, 0); } len -= pos; lib_sprintf(linebuf, sizeof(linebuf), "pos:%i (%x) len:%i", pos, pos, len); drawstr(0, 200 + 8 * 2, linebuf, textcolor, 0); SETMIN(len, 40 * 25); drawstrlen(0, 0, (const char *)&p[pos], len, textcolor, 0); } static void drawscreen_inlbx(void) { char linebuf[256]; if (cursor_i >= 19) { cursor_offs = cursor_i - 19; } if (cursor_i < cursor_offs) { cursor_offs = 0; } drawstr(8, 200 + 8 * 4, "# Name", textcolor, 0); for (int i = 0; i < 20; ++i) { int j = i + cursor_offs; if (j >= cur_items) { break; } lib_sprintf(linebuf, sizeof(linebuf), "%2x ", j); const char *name = lbxfile_item_name(cur_lbx, j); for (int k = 0; k < 32; ++k) { linebuf[3 + k] = name[k] ? name[k] : ' '; } linebuf[3 + 32] = 0; drawstr(8, 200 + 8 * (5 + i), linebuf, textcolor, 0); drawchar(0, 200 + (cursor_i - cursor_offs + 5) * 8, ' ', 0, textcolor); } { uint32_t offs, len; offs = lbxfile_item_offs(cur_lbx, cursor_i); len = lbxfile_item_len(cur_lbx, cursor_i); lib_sprintf(linebuf, sizeof(linebuf), "offs:%x:.%x len:%x (%i)", offs, offs+len, len, len); drawstr(0, 200 + 8 * 0, linebuf, textcolor, 0); } if (lbxfile_type(cur_lbx) == LBX_TYPE_GFX) { uint8_t *p = cur_ptr; uint8_t frame; frame = lbxgfx_get_frame(p); if (reset_frame) { reset_frame = false; lbxgfx_set_frame_0(p); frame = 0; } if (clearbeforedraw) { memset(hw_video_get_buf(), 0, 320 * 200); gfx_aux_setup(&gfxaux, p, 0); lbxgfx_draw_frame_do(gfxaux.data, p, gfxaux.w, test_scale + 1); } else { gfx_aux_draw_frame_to(p, &gfxaux); } if (flipx) { gfx_aux_flipx(&gfxaux); } if (test_rotate) { drawscreen_inlbx_rotate(); } else { gfx_aux_draw_frame_from_limit(cur_xoff, cur_yoff, &gfxaux, 0, 0, UI_SCREEN_W - 1, 200 - 1, UI_SCREEN_W, test_scale + 1); } if (advance_frame) { advance_frame = false; } else { lbxgfx_set_frame(p, frame); } lib_sprintf(linebuf, sizeof(linebuf), "%ix%i f:%i/%i(%i)%c (%x)(%x)(%x) if:%i fmt:%i | %i %i", lbxgfx_get_w(p), lbxgfx_get_h(p), frame, lbxgfx_get_frames(p), lbxgfx_get_frames2(p), lbxgfx_get_frameclearflag(p, frame) ? 'c' : '-', lbxgfx_get_ehandle(p), lbxgfx_get_epage(p), lbxgfx_get_offs0c(p), lbxgfx_get_indep(p), lbxgfx_get_format(p), cur_xoff, cur_yoff ); drawstr(0, 200 + 8 * 1, linebuf, textcolor, 0); if (lbxgfx_has_palette(p)) { lib_sprintf(linebuf, sizeof(linebuf), "pal o:%x do:%x f:%i n:%i (%02x)", lbxgfx_get_paloffs(p), lbxgfx_get_paldataoffs(p), lbxgfx_get_palfirst(p), lbxgfx_get_palnum(p), lbxgfx_get_paloffs06(p) ); drawstr(0, 200 + 8 * 2, linebuf, textcolor, 0); } } else if (lbxfile_type(cur_lbx) == LBX_TYPE_DATA) { uint16_t num, size, view; uint8_t *p = cur_ptr; num = GET_LE_16(p); size = GET_LE_16(p + 2); view = cur_xoff; SETRANGE(view, 0, num - 1); lib_sprintf(linebuf, sizeof(linebuf), "num:%i sz:%x v:%i", num, size, view); drawstr(0, 200 + 8 * 1, linebuf, textcolor, 0); p = cur_ptr + 4 + view * size; drawscreen_inlbx_data(p, size); } else { int len = lbxfile_item_len(cur_lbx, cursor_i); drawscreen_inlbx_data(cur_ptr, len); } } static void drawscreen(void) { memset(hw_video_get_buf(), 0, 320 * 400); if (!in_lbx) { drawscreen_outlbx(); } else { drawscreen_inlbx(); } } static void do_lbx_sound(uint32_t k) { if ((fmt_sfx_detect(cur_ptr, cur_len) != SFX_TYPE_UNKNOWN) && !KBD_MOD_ONLY_CTRL(k)) { if (KBD_GET_MOD(k) == 0) { if (!have_sfx) { if (hw_audio_sfx_init(0, cur_ptr, cur_len) == 0) { have_sfx = true; } } if (have_sfx) { hw_audio_sfx_play(0); } } if (KBD_MOD_ONLY_SHIFT(k)) { uint8_t *sdata = NULL; uint32_t slen = 0; if (fmt_sfx_convert(cur_ptr, cur_len, &sdata, &slen, NULL, 48000, true)) { util_file_save("z1.wav", sdata, slen); } } } else if (fmt_mus_detect(cur_ptr, cur_len) != MUS_TYPE_UNKNOWN) { if ((KBD_GET_MOD(k) == 0) || KBD_MOD_ONLY_CTRL(k)) { if (!have_mus) { if (hw_audio_music_init(0, cur_ptr, cur_len) == 0) { have_mus = true; } } if (have_mus) { hw_audio_music_play(0); } } if (KBD_MOD_ONLY_SHIFT(k)) { uint8_t *sdata = NULL; uint32_t slen = 0; bool loops = false; if (fmt_mus_convert_xmid(cur_ptr, cur_len, &sdata, &slen, &loops)) { util_file_save("z1.mid", sdata, slen); } } } } static void do_lbx_gfx(uint32_t k) { int w, h; w = lbxgfx_get_w(cur_ptr); h = lbxgfx_get_h(cur_ptr); if ((w > 0) && (w <= 320) && (h > 0) && (h <= 200)) { struct pic_s pic; pic.type = PIC_TYPE_PCX; pic.w = w; pic.h = h; pic.pitch = UI_SCREEN_W; pic.pal = lbxpal_palette; if (KBD_MOD_ONLY_SHIFT(k)) { pic.pix = hw_video_get_buf_front(); fmt_pic_save("z0.pcx", &pic); } else if (KBD_MOD_ONLY_CTRL(k)) { char bufname[16]; int frames = lbxgfx_get_frames(cur_ptr); lib_strcpy(bufname, lbxfile_name(cur_lbx), sizeof(bufname)); { char *p; p = strchr(bufname, '.'); if (p) { *p = 0; } } lbxgfx_set_frame_0(cur_ptr); memset(hw_video_get_buf(), 0, 320 * 200); pic.pix = hw_video_get_buf(); for (int f = 0; f < frames; ++f) { char fname[32]; lbxgfx_draw_frame(0, 0, cur_ptr, UI_SCREEN_W, 1); lib_sprintf(fname, sizeof(fname), "z_%s_%02x_%03i.pcx", bufname, cursor_i, f); fmt_pic_save(fname, &pic); } } } } static int loadfont(void) { FILE *fd; bool is_default; const char *fname; char *fnamealloc = 0; int res = -1; if (!lbxview_font_filename) { fnamealloc = util_concat(os_get_path_data(), FSDEV_DIR_SEP_STR, "romfont.bin", NULL); fname = fnamealloc; is_default = true; } else { fname = lbxview_font_filename; is_default = false; } log_message("Load font '%s'\n", fname); fd = fopen(fname, "rb"); if (fd && (fread(romfont_08, 256 * 8, 1, fd) == 1)) { res = 0; } else { log_error("loading font '%s'!\n", fname); if (is_default) { log_message("!! You need a 8x8 1bpp font (2048 bytes) file to use this program.\n" "!! If you have one ready elsewhere, use -font to use it.\n" "!! If you have DOSBox and base64;\n" "!! 1) Generate a font dumper: (source in doc/ext/fontdump.asm)\n" "!! echo uDARtwPNEAa6MwExybQ8zSFyGonDuQAIieoftEDNIXIMOch1CLQ+zSGwAHMCsAG0TM0hci5iaW4A | base64 -d > fontdump.com\n" "!! 2) Run fontdump.com in DOSBox to generate the font file r.bin.\n" "!! 3) Run lbxview again with -font r.bin\n" ); } } if (fd) { fclose(fd); fd = NULL; } lib_free(fnamealloc); fnamealloc = NULL; fname = NULL; return res; } void ui_early_show_message_box(const char *msg) { } /* -------------------------------------------------------------------------- */ int main_handle_option(const char *argv) { static int optn = 0; uint32_t v; if (!util_parse_number(argv, &v)) { log_error("parsing number '%s'\n", argv); return -1; } switch (optn) { case 0: if (v >= LBXFILE_NUM) { log_error("invalid LBX file ID 0x%x\n", v); return -1; } if (!lbxfile_exists(v)) { log_error("file %s missing\n", lbxfile_name(v)); return -1; } in_lbx = true; cur_lbx = v; cur_items = lbxfile_num_items(cur_lbx); cur_ptr = lbxfile_item_get_with_len(cur_lbx, cursor_i, &cur_len); ++optn; break; case 1: cursor_i = v; cursor_offs = v; { uint8_t *p = lbxfile_item_get_with_len(cur_lbx, cursor_i, &cur_len); if (cur_ptr) { lbxfile_item_release(cur_lbx, cur_ptr); } cur_ptr = p; } break; default: log_error("too many params'\n"); return -1; } return 0; } void main_do_shutdown(void) { } int main_do(void) { if (!loadfont()) { have_romfont = true; } if (hw_video_init(320, 400)) { return 1; } lbxfont_init(); lbxpal_init(); lbxpal_select(0, -1, 0); if (cur_ptr && (lbxfile_type(cur_lbx) == LBX_TYPE_GFX)) { lbxgfx_apply_palette(cur_ptr); } lbxpal_update(); textcolor = lbxpal_find_closest(0x1f, 0x1f, 0x1f); drawscreen(); hw_video_draw_buf(); while (1) { bool change_cur_ptr; hw_event_handle(); if (kbd_have_keypress()) { uint32_t k; k = kbd_get_keypress(); cur_key = k; change_cur_ptr = false; switch (k & 0xff) { case MOO_KEY_ESCAPE: if (in_lbx) { in_lbx = false; cursor_i = (int)cur_lbx; cursor_offs = 0; cur_items = LBXFILE_NUM; lbxfile_item_release(cur_lbx, cur_ptr); cur_ptr = NULL; } else { goto done; } break; case MOO_KEY_UP: if (--cursor_i < 0) { cursor_i = cur_items - 1; } change_cur_ptr = in_lbx; break; case MOO_KEY_DOWN: if (++cursor_i >= cur_items) { cursor_i = 0; } change_cur_ptr = in_lbx; break; case MOO_KEY_PAGEUP: cursor_i -= 15; if (cursor_i < 0) { cursor_i = cur_items - 1; } change_cur_ptr = in_lbx; break; case MOO_KEY_PAGEDOWN: cursor_i += 15; if (cursor_i >= cur_items) { cursor_i = 0; } change_cur_ptr = in_lbx; break; case MOO_KEY_RIGHT: advance_frame = true; break; case MOO_KEY_LEFT: reset_frame = true; break; case MOO_KEY_RETURN: if (!in_lbx) { if (lbxfile_exists(cursor_i)) { in_lbx = true; cur_lbx = cursor_i; cur_items = lbxfile_num_items(cur_lbx); cursor_i = 0; cursor_offs = 0; change_cur_ptr = true; } } else { if (lbxfile_type(cur_lbx) == LBX_TYPE_SOUND) { do_lbx_sound(k); } if (lbxfile_type(cur_lbx) == LBX_TYPE_GFX) { do_lbx_gfx(k); } } break; case MOO_KEY_w: --cur_yoff; break; case MOO_KEY_s: ++cur_yoff; break; case MOO_KEY_a: --cur_xoff; break; case MOO_KEY_d: ++cur_xoff; break; case MOO_KEY_f: hw_audio_music_fadeout(); break; case MOO_KEY_q: test_rotate = (test_rotate + 1) % 3; break; case MOO_KEY_z: test_scale = (test_scale + 1) % 3; break; case MOO_KEY_c: clearbeforedraw = !clearbeforedraw; break; case MOO_KEY_0: case MOO_KEY_1: case MOO_KEY_2: case MOO_KEY_3: case MOO_KEY_4: case MOO_KEY_5: case MOO_KEY_6: case MOO_KEY_7: case MOO_KEY_8: case MOO_KEY_9: lbxpal_select((k & 0xff) - MOO_KEY_0, -1, 0); lbxpal_update(); textcolor = lbxpal_find_closest(0x1f, 0x1f, 0x1f); break; case MOO_KEY_e: if (in_lbx) { char bufname[16]; char bufnum[4]; char *p, *name; lib_sprintf(bufnum, sizeof(bufnum), "%02x", cursor_i); lib_strcpy(bufname, lbxfile_name(cur_lbx), sizeof(bufname)); p = strchr(bufname, '.'); if (p) { *p = 0; } name = util_concat("z_", bufname, "_", bufnum, ".bin", NULL); util_file_save(name, cur_ptr, cur_len); lib_free(name); } break; } if (change_cur_ptr) { uint8_t *p = lbxfile_item_get_with_len(cur_lbx, cursor_i, &cur_len); if (cur_ptr) { lbxfile_item_release(cur_lbx, cur_ptr); } cur_ptr = p; if (lbxfile_type(cur_lbx) == LBX_TYPE_GFX) { lbxgfx_apply_palette(cur_ptr); lbxpal_update(); } reset_frame = true; advance_frame = false; cur_xoff = 0; cur_yoff = 0; if (have_sfx) { have_sfx = false; hw_audio_sfx_release(0); } if (have_mus) { have_mus = false; /* hw_audio_music_release(0); */ } textcolor = lbxpal_find_closest(0x1f, 0x1f, 0x1f); } drawscreen(); hw_video_draw_buf(); } else { hw_video_redraw_front(); } } done: if (have_sfx) { have_sfx = false; hw_audio_sfx_release(0); } if (have_mus) { have_mus = false; hw_audio_music_release(0); } lbxpal_shutdown(); lbxfont_shutdown(); return 0; } 1oom-1.11.2/src/lib.c000066400000000000000000000076071476061725400141760ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include "lib.h" #include "log.h" #include "types.h" /* -------------------------------------------------------------------------- */ void *lib_malloc(size_t size) { void *ptr = malloc(size); if ((ptr == NULL) && (size > 0)) { log_fatal_and_die("couldn't malloc %lu, out of memory!\n", size); } if (ptr) { memset(ptr, 0, size); } return ptr; } void *lib_realloc(void *ptr, size_t size) { void *new_ptr = realloc(ptr, size); if (new_ptr == NULL) { log_fatal_and_die("couldn't realloc %lu, out of memory!\n", size); } return new_ptr; } void lib_free(void *ptr) { free(ptr); } char *lib_stralloc(const char *str) { size_t size; char *ptr; if (str == NULL) { exit(EXIT_FAILURE); } size = strlen(str) + 1; ptr = lib_malloc(size); memcpy(ptr, str, size); return ptr; } char *lib_strcpy(char *dst, const char *src, size_t dst_bufsize) { if (strlen(src) >= dst_bufsize) { log_fatal_and_die("lib_strcpy: destination buffer too small, need %lu, have %lu\n", strlen(src) + 1, dst_bufsize); } return strcpy(dst, src); } char *lib_strcat(char *dst, const char *src, size_t dst_bufsize) { size_t combined_len = strlen(src) + strlen(dst); /* Check for wrap-around. */ if (combined_len < strlen(src)) { log_fatal_and_die("lib_strcat: Combined string length too large."); } if (combined_len >= dst_bufsize) { log_fatal_and_die("lib_strcat: destination buffer too small, need %lu, have %lu\n", combined_len + 1, dst_bufsize); } return strcat(dst, src); } int lib_sprintf(char *buf, size_t bufsize, const char *fmt, ...) { va_list args; int bytes_to_print; va_start(args, fmt); bytes_to_print = vsnprintf(buf, bufsize, fmt, args); if (bytes_to_print < 0) { /* Error */ log_fatal_and_die("lib_sprintf: vsnprintf: %s", strerror(errno)); } else if (bytes_to_print >= bufsize) { /* Truncated */ log_fatal_and_die("lib_sprintf: buffer too small, need %d, have %lu", bytes_to_print, bufsize); } return bytes_to_print; } /* strbuild_*: build up strings piece by piece, checking the buffer size. */ static void strbuild_fatal_too_small(struct strbuild_s *str) { log_fatal_and_die("string buffer too small for: \"%s...\"\n", str->str_start); } struct strbuild_s strbuild_init(char *buf, size_t bufsize) { if (bufsize > 0) { buf[0] = '\0'; } struct strbuild_s output = { buf, buf, bufsize }; return output; } /* Return the string being built and start a new one after it, storing multiple * strings in the same buffer. */ const char *strbuild_finish(struct strbuild_s *str) { const char *old_str = str->str_start; if (str->remaining > 0) { *++(str->str_end) = '\0'; str->remaining -= 1; } str->str_start = str->str_end; /* If str->remaining was 0, we will log_fatal_and_die when anything * more is written to this string. */ return old_str; } void strbuild_append_char(struct strbuild_s *str, char c) { if (str->remaining > 0) { *str->str_end++ = c; *str->str_end = '\0'; str->remaining -= 1; } else { strbuild_fatal_too_small(str); } } /* Print text at the end of the current string. */ void strbuild_catf(struct strbuild_s *str, const char *fmt, ...) { va_list args; va_start(args, fmt); int bytes_added = vsnprintf(str->str_end, str->remaining, fmt, args); if (bytes_added < 0) { /* Error */ log_fatal_and_die("str_catf: vsnprintf: %s", strerror(errno)); } else if (bytes_added >= str->remaining) { /* Truncated */ strbuild_fatal_too_small(str); } str->str_end += bytes_added; str->remaining -= bytes_added; } 1oom-1.11.2/src/lib.h000066400000000000000000000016561476061725400142010ustar00rootroot00000000000000#ifndef INC_1OOM_LIB_H #define INC_1OOM_LIB_H #include extern void *lib_malloc(size_t size); extern void *lib_realloc(void *p, size_t size); extern void lib_free(void *ptr); extern char *lib_stralloc(const char *str); extern char *lib_strcpy(char *dst, const char *src, size_t dst_bufsize); extern char *lib_strcat(char *dst, const char *src, size_t dst_bufsize); extern int lib_sprintf(char *buf, size_t bufsize, const char *fmt, ...); /* strbuild_*: build up strings piece by piece, checking the buffer size. */ struct strbuild_s { char *str_start; char *str_end; /* Points to the terminating '\0' byte. */ size_t remaining; /* Buffer size after str_end. */ }; struct strbuild_s strbuild_init(char *buf, size_t bufsize); const char *strbuild_finish(struct strbuild_s *str); void strbuild_append_char(struct strbuild_s *str, char c); void strbuild_catf(struct strbuild_s *str, const char *fmt, ...); #endif 1oom-1.11.2/src/log.c000066400000000000000000000055521476061725400142060ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include "log.h" #ifdef FEATURE_MODEBUG #include "options.h" #endif #include "hw.h" /* ------------------------------------------------------------------------- */ #define MAX_MSG_LEN (1024 * 2) static char msgbuf[MAX_MSG_LEN] = ""; static FILE *log_fd = NULL; /* ------------------------------------------------------------------------- */ static void log_file_write(const char *msg) { if (fputs(msg, log_fd) < 0) { log_file_close(); log_error("Log: writing failed!\n"); } else if (fflush(log_fd) != 0) { log_file_close(); log_error("Log: flush failed!\n"); } } /* ------------------------------------------------------------------------- */ int log_file_open(const char *filename) { if (filename && (filename[0] != '\0')) { log_fd = fopen(filename, "w"); if (!log_fd) { log_error("Log: opening %s failed!\n", filename); return -1; } } return 0; } void log_file_close(void) { if (log_fd) { fclose(log_fd); log_fd = NULL; } } void log_message_direct(const char *msg) { if (log_fd) { log_file_write(msg); } hw_log_message(msg); } void log_warning_direct(const char *msg) { if (log_fd) { log_file_write(msg); } hw_log_warning(msg); } void log_error_direct(const char *msg) { if (log_fd) { log_file_write(msg); } hw_log_error(msg); } void log_message(const char* format, ...) { va_list ap; va_start(ap, format); vsnprintf(msgbuf, MAX_MSG_LEN, format, ap); va_end(ap); log_message_direct(msgbuf); } void log_warning(const char *format, ...) { va_list ap; int len; len = snprintf(msgbuf, MAX_MSG_LEN, "warning: "); va_start(ap, format); vsnprintf(&msgbuf[len], MAX_MSG_LEN - len, format, ap); va_end(ap); log_warning_direct(msgbuf); } void log_error(const char *format, ...) { va_list ap; int len; len = snprintf(msgbuf, MAX_MSG_LEN, "error: "); va_start(ap, format); vsnprintf(&msgbuf[len], MAX_MSG_LEN - len, format, ap); va_end(ap); log_error_direct(msgbuf); } void log_fatal_and_die(const char *format, ...) { va_list ap; int len; len = snprintf(msgbuf, MAX_MSG_LEN, "FATAL: "); va_start(ap, format); vsnprintf(&msgbuf[len], MAX_MSG_LEN - len, format, ap); va_end(ap); log_error_direct(msgbuf); raise(SIGINT); exit(EXIT_FAILURE); } #ifdef FEATURE_MODEBUG static char dbgmsgbuf[MAX_MSG_LEN] = ""; void log_debug(int level, const char *format, ...) { va_list ap; if (opt_modebug < level) { return; } va_start(ap, format); vsnprintf(dbgmsgbuf, MAX_MSG_LEN, format, ap); va_end(ap); fflush(stdout); fputs(dbgmsgbuf, stderr); fflush(stderr); } #endif 1oom-1.11.2/src/log.h000066400000000000000000000012761476061725400142120ustar00rootroot00000000000000#ifndef IDACME_LOG_H #define IDACME_LOG_H extern int log_file_open(const char *filename); extern void log_file_close(void); extern void log_message_direct(const char *msg); extern void log_warning_direct(const char *msg); extern void log_error_direct(const char *msg); extern void log_message(const char *format, ...); extern void log_warning(const char *format, ...); extern void log_error(const char *format, ...); extern void log_fatal_and_die(const char *format, ...) __attribute__((noreturn)); #ifdef FEATURE_MODEBUG extern void log_debug(int level, const char *format, ...); #define LOG_DEBUG(x) log_debug x #define IF_DEBUG(x) x #else #define LOG_DEBUG(x) #define IF_DEBUG(x) #endif #endif 1oom-1.11.2/src/main.c000066400000000000000000000041471476061725400143500ustar00rootroot00000000000000#include "config.h" #include #include #include "main.h" #include "gameapi.h" #include "hw.h" #include "lbx.h" #include "log.h" #include "options.h" #include "os.h" #include "pbx.h" #include "ui.h" #include "version.h" /* -------------------------------------------------------------------------- */ static bool main_startup_ok = false; /* -------------------------------------------------------------------------- */ static int main_early_init(void) { if (0 || os_early_init() || hw_early_init() || ui_early_init() || lbxfile_init() ) { return 1; } return 0; } static int main_init(void) { if (0 || os_init() || hw_init() || ui_init() ) { return 1; } return 0; } static void main_shutdown(void) { options_shutdown(main_startup_ok); main_do_shutdown(); lbxfile_shutdown(); ui_shutdown(); hw_shutdown(); os_shutdown(); log_file_close(); log_message("Thanks for playing 1oom.\n"); } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { if (main_early_init()) { return 1; } if (options_parse_early(argc, argv)) { return 1; } log_message(PACKAGE_NAME " " VERSION_STR ": main:%s ui:%s hw:%s os:%s\n", idstr_main, idstr_ui, idstr_hw, idstr_os); atexit(main_shutdown); if (main_init()) { return 2; } if (options_parse(argc, argv)) { return 3; } if (lbxfile_find_dir()) { ui_early_show_message_box("Error: could not find\nthe LBX files!\n" "1oom requires a copy\nof the Master of Orion\n(v1.3) LBX files.\n" "Simply copy the EXE and\nDLLs to your MOO1\ndirectory.\n" "Alternatively copy your\nMOO1 LBX files to your\n1oom directory."); return 4; } game_apply_rules(); if (pbx_apply_queued_files()) { return 5; } log_message("USER: '%s'\n", os_get_path_user()); main_startup_ok = true; options_finish(); return main_do(); } 1oom-1.11.2/src/main.h000066400000000000000000000007651476061725400143570ustar00rootroot00000000000000#ifndef INC_1OOM_MAIN_H #define INC_1OOM_MAIN_H #include "options.h" #include "types.h" extern bool main_use_lbx; extern bool main_use_cfg; extern const char *idstr_main; extern const struct cmdline_options_s main_cmdline_options[]; extern const struct cmdline_options_s main_cmdline_options_early[]; extern int main_handle_option(const char *argv); extern void (*main_usage)(void); extern int main_1oom(int argc, char **argv); extern int main_do(void); extern void main_do_shutdown(void); #endif 1oom-1.11.2/src/menu.c000066400000000000000000000012151476061725400143610ustar00rootroot00000000000000#include #include "menu.h" static struct menu_item_data_s menu_items[MENU_MAX_ITEMS_PER_PAGE]; static uint32_t menu_item_count; void menu_clear(void) { memset(menu_items, 0, sizeof(menu_items)); menu_item_count = 0; } struct menu_item_data_s *menu_allocate_item(void) { struct menu_item_data_s *ret = &menu_items[menu_item_count]; ++menu_item_count; return ret; } const struct menu_item_data_s *menu_get_item(uint32_t i) { struct menu_item_data_s *ret = NULL; if (i < menu_item_count) { ret = &menu_items[i]; } return ret; } uint32_t menu_get_item_count(void) { return menu_item_count; } 1oom-1.11.2/src/menu.h000066400000000000000000000077061476061725400144010ustar00rootroot00000000000000#ifndef INC_1OOM_MENU_H #define INC_1OOM_MENU_H #include "kbd.h" #define MENU_MAX_ITEMS_PER_PAGE 32 typedef enum { MENU_ITEM_TYPE_NONE, MENU_ITEM_TYPE_RETURN, MENU_ITEM_TYPE_PAGE, MENU_ITEM_TYPE_PAGE_BACK, MENU_ITEM_TYPE_FUNCTION, MENU_ITEM_TYPE_BOOL, MENU_ITEM_TYPE_INT, MENU_ITEM_TYPE_ENUM, MENU_ITEM_TYPE_STR, } menu_item_type_t; struct menu_item_data_s { menu_item_type_t type; const char *text; mookey_t key; void *value_ptr; const char *(*get_text_value) (uint32_t); const char *(*get_text_value2)(void); bool (*func) (void); bool (*is_active) (void); uint32_t action_i; uint32_t value_min; uint32_t value_max; bool need_restart; }; static inline struct menu_item_data_s *menu_item_force_restart(struct menu_item_data_s *d) { d->need_restart = true; return d; } static inline void menu_make_page(struct menu_item_data_s *d, const char *text, uint32_t page, mookey_t key) { d->type = MENU_ITEM_TYPE_PAGE; d->text = text; d->key = key; d->action_i = page; } static inline void menu_make_page_conditional(struct menu_item_data_s *d, const char *text, uint32_t page, bool (*is_active)(void), mookey_t key) { menu_make_page(d, text, page, key); d->is_active = is_active; } static inline void menu_make_action(struct menu_item_data_s *d, const char *text, uint32_t action, mookey_t key) { d->type = MENU_ITEM_TYPE_RETURN; d->text = text; d->key = key; d->action_i = action; } static inline void menu_make_action_conditional(struct menu_item_data_s *d, const char *text, uint32_t action, bool (*is_active)(void), mookey_t key) { menu_make_action(d, text, action, key); d->is_active = is_active; } static inline void menu_make_func(struct menu_item_data_s *d, const char *text, bool (*func)(void), mookey_t key) { d->type = MENU_ITEM_TYPE_FUNCTION; d->text = text; d->key = key; d->func = func; } static inline void menu_make_bool(struct menu_item_data_s *d, const char *text, bool *value_ptr, mookey_t key) { d->type = MENU_ITEM_TYPE_BOOL; d->text = text; d->key = key; d->value_ptr = value_ptr; } static inline void menu_make_bool_func(struct menu_item_data_s *d, const char *text, bool *value_ptr, bool (*func)(void), mookey_t key) { menu_make_bool(d, text, value_ptr, key); d->func = func; } static inline void menu_make_int(struct menu_item_data_s *d, const char *text, uint32_t *value_ptr, uint32_t value_min, uint32_t value_max, mookey_t key) { d->type = MENU_ITEM_TYPE_INT; d->text = text; d->key = key; d->value_ptr = value_ptr; d->value_min = value_min; d->value_max = value_max; } static inline void menu_make_int_func(struct menu_item_data_s *d, const char *text, uint32_t *value_ptr, uint32_t value_min, uint32_t value_max, bool (*func)(void), mookey_t key) { menu_make_int(d, text, value_ptr, value_min, value_max, key); d->func = func; } static inline void menu_make_enum(struct menu_item_data_s *d, const char *text, const char *(*get_text_value) (uint32_t), uint32_t *value_ptr, uint32_t value_min, uint32_t value_max, mookey_t key) { d->type = MENU_ITEM_TYPE_ENUM; d->text = text; d->key = key; d->value_ptr = value_ptr; d->get_text_value = get_text_value; d->value_min = value_min; d->value_max = value_max; } static inline void menu_make_str_func(struct menu_item_data_s *d, const char *text, const char *(*value_ptr)(void), bool (*func)(void), mookey_t key) { d->type = MENU_ITEM_TYPE_STR; d->text = text; d->key = key; d->get_text_value2 = value_ptr; d->func = func; } static inline void menu_make_back(struct menu_item_data_s *d) { d->type = MENU_ITEM_TYPE_PAGE_BACK; d->text = "Back"; d->key = MOO_KEY_b; } extern void menu_clear(void); extern struct menu_item_data_s *menu_allocate_item(void); extern const struct menu_item_data_s *menu_get_item(uint32_t i); extern uint32_t menu_get_item_count(void); #endif 1oom-1.11.2/src/mouse.c000066400000000000000000000027031476061725400145500ustar00rootroot00000000000000#include "config.h" #include "mouse.h" /* ------------------------------------------------------------------------- */ static bool mouse_have_click_hw = false; static bool mouse_have_click_sw = false; /* ------------------------------------------------------------------------- */ int moouse_x = 0; int moouse_y = 0; int mouse_buttons = 0; int mouse_scroll = 0; int mouse_stored_x = 0; int mouse_stored_y = 0; int mouse_click_x = 0; int mouse_click_y = 0; int mouse_click_buttons = 0; int mouse_cursor_scale = 1; /* ------------------------------------------------------------------------- */ void mouse_set_xy_from_hw(int mx, int my) { moouse_x = mx; moouse_y = my; } void mouse_set_buttons_from_hw(int buttons) { buttons &= (MOUSE_BUTTON_MASK_LEFT | MOUSE_BUTTON_MASK_RIGHT); mouse_buttons = buttons; if (buttons) { mouse_click_buttons = buttons; mouse_click_x = moouse_x; mouse_click_y = moouse_y; mouse_have_click_hw = true; mouse_have_click_sw = true; } } void mouse_set_scroll_from_hw(int scroll) { mouse_scroll += scroll; } void mouse_set_click_xy(int mx, int my) { mouse_have_click_sw = true; mouse_click_x = mx; mouse_click_y = my; } bool mouse_getclear_click_hw(void) { bool r = mouse_have_click_hw; mouse_have_click_hw = false; return r; } bool mouse_getclear_click_sw(void) { bool r = mouse_have_click_sw; mouse_have_click_sw = false; return r; } 1oom-1.11.2/src/mouse.h000066400000000000000000000013411476061725400145520ustar00rootroot00000000000000#ifndef INC_1OOM_MOUSE_H #define INC_1OOM_MOUSE_H #include "types.h" #define MOUSE_BUTTON_MASK_LEFT 1 #define MOUSE_BUTTON_MASK_RIGHT 2 /* Allegro uses mouse_x and mouse_y */ extern int moouse_x; extern int moouse_y; extern int mouse_buttons; extern int mouse_scroll; extern int mouse_stored_x; extern int mouse_stored_y; extern int mouse_click_x; extern int mouse_click_y; extern int mouse_click_buttons; extern int mouse_cursor_scale; extern void mouse_set_xy_from_hw(int mx, int my); extern void mouse_set_buttons_from_hw(int buttons); extern void mouse_set_scroll_from_hw(int scroll); extern void mouse_set_click_xy(int mx, int my); extern bool mouse_getclear_click_hw(void); extern bool mouse_getclear_click_sw(void); #endif 1oom-1.11.2/src/options.c000066400000000000000000000366421476061725400151240ustar00rootroot00000000000000#include "config.h" #include #include #include #include "options.h" #include "cfg.h" #include "hw.h" #include "lib.h" #include "log.h" #include "main.h" #include "os.h" #include "pbx.h" #include "ui.h" #include "util.h" #include "version.h" /* -------------------------------------------------------------------------- */ /* local options */ static const char *opt_logfilename_in = 0; static const char *opt_configfilename_in = 0; /* used only for the -c option */ static char *opt_configfilename = 0; static bool opt_config_ro = false; static char *opt_datapath = 0; static bool opt_default = false; /* -------------------------------------------------------------------------- */ /* global options */ #ifdef FEATURE_MODEBUG int opt_modebug = 0; #endif bool opt_audio_enabled = true; bool opt_music_enabled = true; bool opt_sfx_enabled = true; bool opt_sfx_init_parallel = true; int opt_music_volume = 64; int opt_sfx_volume = 100; int opt_audiorate = 48000; int opt_audioslice_ms = 50; #ifdef HAVE_SAMPLERATE bool opt_use_libsamplerate = true; int opt_libsamplerate_scale = 65; int opt_libsamplerate_mode = 1; #endif /* -------------------------------------------------------------------------- */ static bool opt_cfg_set_datapath(void *var) { LOG_DEBUG((1, "%s: '%s'\n", __func__, (const char *)var)); os_set_path_data((const char *)var); return true; } const struct cfg_items_s opt_cfg_items[] = { CFG_ITEM_STR("data_path", &opt_datapath, opt_cfg_set_datapath), CFG_ITEM_END }; const struct cfg_items_s opt_cfg_items_audio[] = { CFG_ITEM_BOOL("audio", &opt_audio_enabled), CFG_ITEM_BOOL("music", &opt_music_enabled), CFG_ITEM_BOOL("sfx", &opt_sfx_enabled), CFG_ITEM_BOOL("sfxinitpar", &opt_sfx_init_parallel), CFG_ITEM_INT("music_volume", &opt_music_volume, 0), CFG_ITEM_INT("sfx_volume", &opt_sfx_volume, 0), CFG_ITEM_INT("audiorate", &opt_audiorate, 0), CFG_ITEM_INT("audioslice_ms", &opt_audioslice_ms, 0), #ifdef HAVE_SAMPLERATE CFG_ITEM_BOOL("use_libsamplerate", &opt_use_libsamplerate), CFG_ITEM_INT("libsamplerate_scale", &opt_libsamplerate_scale, 0), CFG_ITEM_INT("libsamplerate_mode", &opt_libsamplerate_mode, 0), #endif CFG_ITEM_END }; /* -------------------------------------------------------------------------- */ int options_enable_int_var(char **argv, void *var) { *((int *)var) = 1; return 0; } int options_disable_int_var(char **argv, void *var) { *((int *)var) = 0; return 0; } int options_set_int_var(char **argv, void *var) { *((int *)var) = atoi(argv[1]); return 0; } int options_set_str_var(char **argv, void *var) { *(const char **)var = argv[1]; return 0; } int options_unset_str_var(char **argv, void *var) { *(const char **)var = 0; return 0; } int options_empty_str_var(char **argv, void *var) { *(const char **)var = ""; return 0; } int options_enable_bool_var(char **argv, void *var) { *((bool *)var) = true; return 0; } int options_disable_bool_var(char **argv, void *var) { *((bool *)var) = false; return 0; } int options_notimpl(char **argv, void *var) { log_error("option '%s' is not implemented (yet)", argv[0]); return -1; } int options_nop(char **argv, void *var) { return 0; } /* -------------------------------------------------------------------------- */ static int options_set_userdir(char **argv, void *var) { log_message("Setting user directory to '%s'\n", argv[1]); os_set_path_user(argv[1]); return 0; } static int options_set_datadir(char **argv, void *var) { log_message("Setting data directory to '%s'\n", argv[1]); os_set_path_data(argv[1]); return 0; } static int options_add_patchfile(char **argv, void *var) { if (pbx_queue_file(argv[1]) < 0) { log_error("too many patchfiles"); return -1; } return 0; } /* -------------------------------------------------------------------------- */ static int show_usage(char **argv, void *var); static int load_default(char **argv, void *var); static const struct cmdline_options_s cmdline_options_early[] = { { "-?", 0, show_usage, NULL, NULL, "Show command line options" }, { "-default", 0, load_default, NULL, NULL, "Use default configuration" }, #ifdef FEATURE_MODEBUG { "-modebug", 1, options_set_int_var, (void *)&opt_modebug, "LEVEL", "Set debug level" }, #endif { NULL, 0, NULL, NULL, NULL, NULL } }; static const struct cmdline_options_s cmdline_options_cfg_early[] = { { "-c", 1, options_set_str_var, (void *)&opt_configfilename_in, "FILE.TXT", "Set config filename" }, { "-cro", 0, options_enable_bool_var, (void *)&opt_config_ro, NULL, "Do not write a config file" }, { "-user", 1, options_set_userdir, NULL, "PATH", "Set user directory" }, { "-log", 1, options_set_str_var, (void *)&opt_logfilename_in, "FILE.TXT", "Set log filename" }, { "-nolog", 0, options_empty_str_var, (void *)&opt_logfilename_in, NULL, "Do not create a log file" }, { NULL, 0, NULL, NULL, NULL, NULL } }; static const struct cmdline_options_s cmdline_options_lbx[] = { { "-data", 1, options_set_datadir, NULL, "PATH", "Set data directory" }, { NULL, 0, NULL, NULL, NULL, NULL } }; static const struct cmdline_options_s cmdline_options_pbxfile[] = { { "-file", 1, options_add_patchfile, NULL, "FILE.PBX", "Add PBX file" }, { NULL, 0, NULL, NULL, NULL, NULL } }; static const struct cmdline_options_s cmdline_options_audio_early[] = { { "-audio", 0, options_enable_bool_var, (void *)&opt_audio_enabled, NULL, "Enable audio" }, { "-noaudio", 0, options_disable_bool_var, (void *)&opt_audio_enabled, NULL, "Disable audio" }, { NULL, 0, NULL, NULL, NULL, NULL } }; static const struct cmdline_options_s cmdline_options_audio[] = { { "-music", 0, options_enable_bool_var, (void *)&opt_music_enabled, NULL, "Enable music" }, { "-nomusic", 0, options_disable_bool_var, (void *)&opt_music_enabled, NULL, "Disable music" }, { "-sfx", 0, options_enable_bool_var, (void *)&opt_sfx_enabled, NULL, "Enable SFX" }, { "-nosfx", 0, options_disable_bool_var, (void *)&opt_sfx_enabled, NULL, "Disable SFX" }, { "-sfxinitpar", 0, options_enable_bool_var, (void *)&opt_sfx_init_parallel, NULL, "Init SFX in parallel (if possible)" }, { "-nosfxinitpar", 0, options_disable_bool_var, (void *)&opt_sfx_init_parallel, NULL, "Do not init SFX in parallel" }, { "-musicvol", 1, options_set_int_var, (void *)&opt_music_volume, "VOLUME", "Set music volume (0..128)" }, { "-sfxvol", 1, options_set_int_var, (void *)&opt_sfx_volume, "VOLUME", "Set SFX volume (0..128)" }, { "-audiohz", 1, options_set_int_var, (void *)&opt_audiorate, "HZ", "Set audio sample rate (Hz)" }, { "-audioms", 1, options_set_int_var, (void *)&opt_audioslice_ms, "MS", "Set max audio slice size (ms)" }, #ifdef HAVE_SAMPLERATE { "-libsr", 0, options_enable_bool_var, (void *)&opt_use_libsamplerate, NULL, "Use libsamplerate" }, { "-nolibsr", 0, options_disable_bool_var, (void *)&opt_use_libsamplerate, NULL, "Do not use libsamplerate" }, { "-libsrscale", 1, options_set_int_var, (void *)&opt_libsamplerate_scale, "PERCENT", "libsamplerate scaling %" }, { "-libsrmode", 1, options_set_int_var, (void *)&opt_libsamplerate_mode, "MODE", "libsamplerate mode (0 = best, 4 = worst)" }, #endif { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ static int get_options_w(const struct cmdline_options_s *opts, int lmax) { int i = 0; while (opts[i].str != NULL) { int l; l = strlen(opts[i].str) + 1; if (opts[i].str_param) { l += strlen(opts[i].str_param); } if (l > lmax) { lmax = l; } ++i; } return lmax; } static void show_options(const struct cmdline_options_s *opts, int lmax) { int i = 0; char fmt1[16]; char fmt2[16]; lib_sprintf(fmt1, sizeof(fmt1), " %%-%is ", lmax); lib_sprintf(fmt2, sizeof(fmt2), "%%s\n%%-%is", lmax + 5); while (opts[i].str != NULL) { char buf[128]; if (opts[i].str_help) { const char *p, *q; lib_sprintf(buf, sizeof(buf), "%s %s", opts[i].str, opts[i].str_param ? opts[i].str_param : ""); log_message(fmt1, buf); p = opts[i].str_help; while ((q = strchr(p, '\n')) != NULL) { int len; len = q - p; memcpy(buf, p, len); buf[len] = '\0'; log_message(fmt2, buf, ""); p = q + 1; } log_message("%s\n", p); } ++i; } } static int show_usage(char **argv, void *var) { options_show_usage(); return -1; } static int load_default(char **argv, void *var) { opt_default = true; return 0; } /* -------------------------------------------------------------------------- */ static const struct cmdline_options_s *find_option_do(const char *name, const struct cmdline_options_s *cmds) { while (cmds->str != NULL) { if (strcmp(name, cmds->str) == 0) { return cmds; } ++cmds; } return NULL; } static const struct cmdline_options_s *find_option(const char *name, bool early, bool *was_early) { const struct cmdline_options_s *o = NULL; if (0 || (o = find_option_do(name, cmdline_options_early)) || (main_use_cfg && (o = find_option_do(name, cmdline_options_cfg_early))) || (ui_use_audio && (o = find_option_do(name, cmdline_options_audio_early))) || (o = find_option_do(name, main_cmdline_options_early)) ) { *was_early = true; return o; } if (0 || (main_use_lbx && (o = find_option_do(name, cmdline_options_lbx))) || (main_use_lbx && (o = find_option_do(name, cmdline_options_pbxfile))) || (ui_use_audio && (o = find_option_do(name, cmdline_options_audio))) || (o = find_option_do(name, os_cmdline_options)) || (o = find_option_do(name, hw_cmdline_options)) || (o = find_option_do(name, hw_cmdline_options_extra)) || (o = find_option_do(name, ui_cmdline_options)) || (o = find_option_do(name, main_cmdline_options)) ) { *was_early = false; return o; } return NULL; } /* -------------------------------------------------------------------------- */ static int options_parse_do(int argc, char **argv, bool early) { int i = 1; int num; bool was_early; const struct cmdline_options_s *o; while (i < argc) { switch (argv[i][0]) { case '+': case '-': o = find_option(argv[i], early, &was_early); if (!o) { log_error("unknown option '%s'\n", argv[i]); show_usage(NULL, NULL); return -1; } num = o->num_param; if (num >= (argc - i)) { log_error("option '%s' is missing the parameter\n", argv[i]); return -1; } if (early == was_early) { if (o->handle(&argv[i], o->var) < 0) { return -1; } } i += num; break; default: if (!early) { if (main_handle_option(argv[i]) < 0) { log_warning("ignoring unhandled parameter '%s'\n", argv[i]); } } break; } ++i; } return 0; } /* -------------------------------------------------------------------------- */ int options_parse_early(int argc, char **argv) { int res; /* parse options first to exit early on "-?" and open the log file */ res = options_parse_do(argc, argv, true); if (!res) { const char *filename = 0; char *filenamea = 0; if (opt_logfilename_in) { filename = opt_logfilename_in; } else { char namebuf[128]; if (os_get_fname_log(namebuf, sizeof(namebuf))) { const char *path = os_get_path_user(); filename = filenamea = util_concat(path, FSDEV_DIR_SEP_STR, namebuf, NULL); } } if (filename) { log_file_open(filename); if (filenamea) { lib_free(filenamea); filenamea = 0; } filename = 0; } } if ((!res) && main_use_cfg) { if (opt_configfilename_in != 0) { opt_configfilename = lib_stralloc(opt_configfilename_in); } else { opt_configfilename = cfg_cfgname(); } if (!opt_default && cfg_load(opt_configfilename)) { log_warning("Opt: problems loading config file '%s'\n", opt_configfilename); } /* parse options again to override configuration */ res = options_parse_do(argc, argv, true); } return res; } int options_parse(int argc, char **argv) { return options_parse_do(argc, argv, false); } void options_show_usage(void) { int lmax = 0; log_message_direct(PACKAGE_NAME " " VERSION_STR "\n"); if (main_usage) { main_usage(); } log_message_direct("Options:\n"); lmax = get_options_w(cmdline_options_early, lmax); if (main_use_cfg) { lmax = get_options_w(cmdline_options_cfg_early, lmax); } if (main_use_lbx) { lmax = get_options_w(cmdline_options_lbx, lmax); lmax = get_options_w(cmdline_options_pbxfile, lmax); } if (ui_use_audio) { lmax = get_options_w(cmdline_options_audio_early, lmax); lmax = get_options_w(cmdline_options_audio, lmax); } lmax = get_options_w(os_cmdline_options, lmax); lmax = get_options_w(hw_cmdline_options, lmax); lmax = get_options_w(hw_cmdline_options_extra, lmax); lmax = get_options_w(ui_cmdline_options, lmax); lmax = get_options_w(main_cmdline_options_early, lmax); lmax = get_options_w(main_cmdline_options, lmax); show_options(cmdline_options_early, lmax); if (main_use_cfg) { show_options(cmdline_options_cfg_early, lmax); } if (main_use_lbx) { show_options(cmdline_options_lbx, lmax); show_options(cmdline_options_pbxfile, lmax); } if (ui_use_audio) { show_options(cmdline_options_audio_early, lmax); show_options(cmdline_options_audio, lmax); } show_options(os_cmdline_options, lmax); show_options(hw_cmdline_options, lmax); show_options(hw_cmdline_options_extra, lmax); show_options(ui_cmdline_options, lmax); show_options(main_cmdline_options_early, lmax); show_options(main_cmdline_options, lmax); } void options_finish(void) { if (opt_datapath) { /* from config file */ lib_free(opt_datapath); } opt_datapath = lib_stralloc(os_get_path_data()); } void options_shutdown(bool save_config) { if (main_use_cfg && save_config && opt_configfilename && (!opt_config_ro)) { if (cfg_save(opt_configfilename) != 0) { log_error("Opt: problems saving config file '%s'\n", opt_configfilename); } } lib_free(opt_configfilename); opt_configfilename = 0; lib_free(opt_datapath); opt_datapath = 0; } 1oom-1.11.2/src/options.h000066400000000000000000000027461476061725400151270ustar00rootroot00000000000000#ifndef INC_1OOM_OPTIONS_H #define INC_1OOM_OPTIONS_H #include "cfg.h" #include "types.h" extern const struct cfg_items_s opt_cfg_items[]; extern const struct cfg_items_s opt_cfg_items_audio[]; #ifdef FEATURE_MODEBUG extern int opt_modebug; #endif extern bool opt_audio_enabled; extern bool opt_music_enabled; extern bool opt_sfx_enabled; extern bool opt_sfx_init_parallel; extern int opt_music_volume; extern int opt_sfx_volume; extern int opt_audiorate; extern int opt_audioslice_ms; #ifdef HAVE_SAMPLERATE extern bool opt_use_libsamplerate; extern int opt_libsamplerate_scale; extern int opt_libsamplerate_mode; #endif struct cmdline_options_s { const char *str; int num_param; int (*handle)(char **argv, void *var); void *var; const char *str_param; const char *str_help; }; extern int options_enable_int_var(char **argv, void *var); extern int options_disable_int_var(char **argv, void *var); extern int options_set_int_var(char **argv, void *var); extern int options_set_str_var(char **argv, void *var); extern int options_unset_str_var(char **argv, void *var); extern int options_empty_str_var(char **argv, void *var); extern int options_enable_bool_var(char **argv, void *var); extern int options_disable_bool_var(char **argv, void *var); extern int options_parse_early(int argc, char **argv); extern int options_parse(int argc, char **argv); extern void options_show_usage(void); extern void options_finish(void); extern void options_shutdown(bool save_config); #endif 1oom-1.11.2/src/os.h000066400000000000000000000020411476061725400140410ustar00rootroot00000000000000#ifndef INC_1OOM_OS_H #define INC_1OOM_OS_H /* API to os/ */ #include #include "osdefs.h" #include "options.h" #include "types.h" extern const char *idstr_os; extern int os_early_init(void); extern int os_init(void); extern void os_shutdown(void); extern const struct cmdline_options_s os_cmdline_options[]; extern const char **os_get_paths_data(void); extern const char *os_get_path_data(void); extern void os_set_path_data(const char *path); extern const char *os_get_path_user(void); extern void os_set_path_user(const char *path); extern int os_make_path(const char *path); extern int os_make_path_user(void); extern int os_make_path_for(const char *filename); extern const char *os_get_fname_save_slot(char *buf, size_t bufsize, int savei/*1..9*/); extern const char *os_get_fname_save_year(char *buf, size_t bufsize, int year/*2300..*/); extern const char *os_get_fname_cfg(char *buf, size_t bufsize, const char *gamestr, const char *uistr, const char *hwstr); extern const char *os_get_fname_log(char *buf, size_t bufsize); #endif 1oom-1.11.2/src/os/000077500000000000000000000000001476061725400136735ustar00rootroot000000000000001oom-1.11.2/src/os/Makefile.am000066400000000000000000000002261476061725400157270ustar00rootroot00000000000000if COMPILE_UNIX SUBDIRS = unix endif if COMPILE_WIN32 SUBDIRS = win32 endif if COMPILE_MSDOS SUBDIRS = msdos endif DIST_SUBDIRS = unix win32 msdos 1oom-1.11.2/src/os/msdos/000077500000000000000000000000001476061725400150205ustar00rootroot000000000000001oom-1.11.2/src/os/msdos/Makefile.am000066400000000000000000000002051476061725400170510ustar00rootroot00000000000000AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src noinst_LIBRARIES = libos.a libos_a_SOURCES = \ os.c \ osdefs.h 1oom-1.11.2/src/os/msdos/os.c000066400000000000000000000055451476061725400156160ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include "os.h" #include "options.h" #include "lib.h" #include "util.h" /* -------------------------------------------------------------------------- */ const struct cmdline_options_s os_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ static char *data_path = NULL; static char *user_path = NULL; static char *all_data_paths[] = { NULL, NULL, NULL, NULL }; /* -------------------------------------------------------------------------- */ const char *idstr_os = "msdos"; int os_early_init(void) { return 0; } int os_init(void) { return 0; } void os_shutdown(void) { lib_free(data_path); data_path = NULL; lib_free(user_path); user_path = NULL; } const char **os_get_paths_data(void) { int i = 0; if (data_path) { all_data_paths[i++] = data_path; } all_data_paths[i++] = "."; all_data_paths[i++] = ".\\data"; all_data_paths[i] = NULL; return (const char **)all_data_paths; } const char *os_get_path_data(void) { return data_path; } void os_set_path_data(const char *path) { data_path = lib_stralloc(path); } const char *os_get_path_user(void) { if (user_path == NULL) { user_path = lib_stralloc("."); } return user_path; } void os_set_path_user(const char *path) { if (user_path) { lib_free(user_path); user_path = NULL; } user_path = lib_stralloc(path); } int os_make_path(const char *path) { if ((path == NULL) || ((path[0] == '.') && (path[1] == '\0'))) { return 0; } return mkdir(path, 0700); } int os_make_path_user(void) { return os_make_path(os_get_path_user()); } int os_make_path_for(const char *filename) { int res = 0; char *path; util_fname_split(filename, &path, NULL); if (path != NULL) { res = os_make_path(path); lib_free(path); } return res; } const char *os_get_fname_save_slot(char *buf, size_t bufsize, int savei/*1..9*/) { lib_sprintf(buf, bufsize, "1oomsav%i.bin", savei); return buf; } const char *os_get_fname_save_year(char *buf, size_t bufsize, int year/*2300..*/) { lib_sprintf(buf, bufsize, "1oom%i.bin", year); return buf; } const char *os_get_fname_cfg(char *buf, size_t bufsize, const char *gamestr, const char *uistr, const char *hwstr) { const char *s; if (strcmp(gamestr, "game") == 0) { s = uistr; } else { s = gamestr; } lib_sprintf(buf, bufsize, "1%s", s); buf[8] = '\0'; lib_strcat(buf, ".cfg", bufsize); return buf; } const char *os_get_fname_log(char *buf, size_t bufsize) { if (buf) { lib_strcpy(buf, "1oom_log.txt", bufsize); return buf; } return "1oom_log.txt"; } 1oom-1.11.2/src/os/msdos/osdefs.h000066400000000000000000000003741476061725400164600ustar00rootroot00000000000000#ifndef INC_1OOM_OSDEFS_H #define INC_1OOM_OSDEFS_H #define FSDEV_PATH_MAX 1024 #define FSDEV_DIR_SEP_STR "\\" #define FSDEV_DIR_SEP_CHR '\\' #define FSDEV_EXT_SEP_STR "." #define FSDEV_EXT_SEP_CHR '.' #define OS_UI_SCALE_MAX 2 #endif 1oom-1.11.2/src/os/unix/000077500000000000000000000000001476061725400146565ustar00rootroot000000000000001oom-1.11.2/src/os/unix/Makefile.am000066400000000000000000000002051476061725400167070ustar00rootroot00000000000000AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src noinst_LIBRARIES = libos.a libos_a_SOURCES = \ os.c \ osdefs.h 1oom-1.11.2/src/os/unix/os.c000066400000000000000000000114761476061725400154540ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include #include "os.h" #include "options.h" #include "lib.h" #include "util.h" #include "types.h" /* -------------------------------------------------------------------------- */ const struct cmdline_options_s os_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ #define NUM_ALL_DATA_PATHS 64 static char *data_path = NULL; static char *user_path = NULL; static char *all_data_paths[NUM_ALL_DATA_PATHS] = {NULL}; static int num_data_paths = 0; /* -------------------------------------------------------------------------- */ const char *idstr_os = "unix"; int os_early_init(void) { return 0; } int os_init(void) { return 0; } void os_shutdown(void) { lib_free(user_path); user_path = NULL; lib_free(data_path); data_path = NULL; for (int i = 0; i < num_data_paths; ++i) { lib_free(all_data_paths[i]); all_data_paths[i] = NULL; } num_data_paths = 0; } const char **os_get_paths_data(void) { if (num_data_paths == 0) { const char *p; int i = 0; bool got_xdg = false; if (data_path) { all_data_paths[i++] = lib_stralloc(data_path); } p = getenv("XDG_DATA_HOME"); if (p) { all_data_paths[i++] = util_concat(p, "/1oom", NULL); got_xdg = true; } p = getenv("XDG_DATA_DIRS"); if (p) { char *data_dirs = lib_stralloc(p); char *q = data_dirs; bool flag_done = false; while (!flag_done && *q) { char *r = strchr(q, ':'); if (r == NULL) { flag_done = true; } else { *r = '\0'; } r = strchr(q, '\0'); if (!r || (r == q)) { flag_done = true; } else { if (*(r - 1) == '/') { *(r - 1) = '\0'; } all_data_paths[i++] = util_concat(q, "/1oom", NULL); } if (!flag_done) { q = r + 1; } } got_xdg = true; lib_free(data_dirs); } if (!got_xdg) { p = getenv("HOME"); if (p) { all_data_paths[i++] = util_concat(p, "/.local/share/1oom", NULL);; } } all_data_paths[i++] = lib_stralloc("/usr/share/1oom"); all_data_paths[i++] = lib_stralloc("/usr/local/share/1oom"); all_data_paths[i++] = lib_stralloc("."); all_data_paths[i++] = lib_stralloc("./data"); all_data_paths[i] = NULL; num_data_paths = i; } return (const char **)all_data_paths; } const char *os_get_path_data(void) { return data_path; } void os_set_path_data(const char *path) { if (data_path) { lib_free(data_path); data_path = NULL; } data_path = lib_stralloc(path); } const char *os_get_path_user(void) { if (user_path == NULL) { char *xdg_config_home = getenv("XDG_CONFIG_HOME"); if (xdg_config_home != NULL) { user_path = util_concat(xdg_config_home, "/1oom", NULL); } else { char *home = getenv("HOME"); if (home != NULL) { user_path = util_concat(home, "/.config/1oom", NULL); } else { user_path = lib_stralloc("."); } } } return user_path; } void os_set_path_user(const char *path) { if (user_path) { lib_free(user_path); user_path = NULL; } user_path = lib_stralloc(path); } int os_make_path(const char *path) { if ((path == NULL) || ((path[0] == '.') && (path[1] == '\0'))) { return 0; } if (access(path, F_OK)) { return mkdir(path, 0700); } return 0; } int os_make_path_user(void) { return os_make_path(os_get_path_user()); } int os_make_path_for(const char *filename) { int res = 0; char *path; util_fname_split(filename, &path, NULL); if (path != NULL) { res = os_make_path(path); lib_free(path); } return res; } const char *os_get_fname_save_slot(char *buf, size_t bufsize, int savei/*1..9*/) { return NULL; } const char *os_get_fname_save_year(char *buf, size_t bufsize, int year/*2300..*/) { return NULL; } const char *os_get_fname_cfg(char *buf, size_t bufsize, const char *gamestr, const char *uistr, const char *hwstr) { return NULL; } const char *os_get_fname_log(char *buf, size_t bufsize) { if (buf) { lib_strcpy(buf, "1oom_log.txt", bufsize); return buf; } return "1oom_log.txt"; } 1oom-1.11.2/src/os/unix/osdefs.h000066400000000000000000000003361476061725400163140ustar00rootroot00000000000000#ifndef INC_1OOM_OSDEFS_H #define INC_1OOM_OSDEFS_H #define FSDEV_PATH_MAX 2048 #define FSDEV_DIR_SEP_STR "/" #define FSDEV_DIR_SEP_CHR '/' #define FSDEV_EXT_SEP_STR "." #define FSDEV_EXT_SEP_CHR '.' #endif 1oom-1.11.2/src/os/win32/000077500000000000000000000000001476061725400146355ustar00rootroot000000000000001oom-1.11.2/src/os/win32/Makefile.am000066400000000000000000000002051476061725400166660ustar00rootroot00000000000000AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src noinst_LIBRARIES = libos.a libos_a_SOURCES = \ os.c \ osdefs.h 1oom-1.11.2/src/os/win32/os.c000066400000000000000000000047661476061725400154370ustar00rootroot00000000000000#include "config.h" #include #include #include #include "os.h" #include "options.h" #include "lib.h" #include "util.h" /* -------------------------------------------------------------------------- */ const struct cmdline_options_s os_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ static char *data_path = NULL; static char *user_path = NULL; static char *all_data_paths[] = { NULL, NULL, NULL, NULL }; /* -------------------------------------------------------------------------- */ const char *idstr_os = "win32"; int os_early_init(void) { return 0; } int os_init(void) { return 0; } void os_shutdown(void) { lib_free(data_path); data_path = NULL; lib_free(user_path); user_path = NULL; } const char **os_get_paths_data(void) { int i = 0; if (data_path) { all_data_paths[i++] = data_path; } all_data_paths[i++] = "."; all_data_paths[i++] = ".\\data"; all_data_paths[i] = NULL; return (const char **)all_data_paths; } const char *os_get_path_data(void) { return data_path; } void os_set_path_data(const char *path) { data_path = lib_stralloc(path); } const char *os_get_path_user(void) { if (user_path == NULL) { user_path = lib_stralloc("."); } return user_path; } void os_set_path_user(const char *path) { if (user_path) { lib_free(user_path); user_path = NULL; } user_path = lib_stralloc(path); } int os_make_path(const char *path) { if ((path == NULL) || ((path[0] == '.') && (path[1] == '\0'))) { return 0; } return mkdir(path); } int os_make_path_user(void) { return os_make_path(os_get_path_user()); } int os_make_path_for(const char *filename) { int res = 0; char *path; util_fname_split(filename, &path, NULL); if (path != NULL) { res = os_make_path(path); lib_free(path); } return res; } const char *os_get_fname_save_slot(char *buf, size_t bufsize, int savei/*1..9*/) { return NULL; } const char *os_get_fname_save_year(char *buf, size_t bufsize, int year/*2300..*/) { return NULL; } const char *os_get_fname_cfg(char *buf, size_t bufsize, const char *gamestr, const char *uistr, const char *hwstr) { return NULL; } const char *os_get_fname_log(char *buf, size_t bufsize) { if (buf) { lib_strcpy(buf, "1oom_log.txt", bufsize); return buf; } return "1oom_log.txt"; } 1oom-1.11.2/src/os/win32/osdefs.h000066400000000000000000000004011476061725400162640ustar00rootroot00000000000000#ifndef INC_1OOM_OSDEFS_H #define INC_1OOM_OSDEFS_H #define FSDEV_PATH_MAX 2048 #define FSDEV_DIR_SEP_STR "\\" #define FSDEV_DIR_SEP_CHR '\\' #define FSDEV_DIR_SEP_ALT '/' #define FSDEV_EXT_SEP_STR "." #define FSDEV_EXT_SEP_CHR '.' #endif 1oom-1.11.2/src/palette.c000066400000000000000000000000671476061725400150570ustar00rootroot00000000000000#include "palette.h" uint8_t ui_palette[256*3] = {0}; 1oom-1.11.2/src/palette.h000066400000000000000000000011451476061725400150620ustar00rootroot00000000000000#ifndef INC_1OOM_PALETTE_H #define INC_1OOM_PALETTE_H #include #include "types.h" extern uint8_t ui_palette[256*3]; /* 6bit palette from the game */ static inline void ui_palette_set_color(int i, uint8_t r, uint8_t g, uint8_t b) { int j = i * 3; ui_palette[j] = r & 0x3f; ui_palette[j+1] = g & 0x3f; ui_palette[j+2] = b & 0x3f; } static inline void ui_palette_set(const uint8_t *pal, int first, int num) { memcpy(&ui_palette[first * 3], pal, num * 3); } static inline uint8_t palette_6bit_to_8bit(uint8_t six_bit) { return (six_bit << 2) | ((six_bit >> 4) & 3); } #endif 1oom-1.11.2/src/pbx.c000066400000000000000000000212331476061725400142100ustar00rootroot00000000000000#include "config.h" #include #include #include #include "pbx.h" #include "bits.h" #include "gameapi.h" #include "lbx.h" #include "lib.h" #include "log.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define MAX_PATCHFILES 20 static size_t num_patchfiles = 0; static const char *patchfiles[MAX_PATCHFILES] = { NULL }; /* -------------------------------------------------------------------------- */ static char *str_from_buf(const void *buf, uint32_t buf_size) { size_t str_size = (size_t)buf_size + 1; char *str = lib_malloc(str_size); memcpy(str, buf, buf_size); /* lib_malloc zeros the buffer, so the string is '\0'-terminated. */ return str; } static int pbx_cb_name(void *ctx, const char *filename, int pbxi, uint8_t *data, uint32_t len) { char *str = str_from_buf(data, len); log_message("PBX: name '%s'\n", str); lib_free(str); return 0; } static int pbx_cb_desc(void *ctx, const char *filename, int pbxi, uint8_t *data, uint32_t len) { /* ignore */ return 0; } static int pbx_cb_lbxp(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len) { lbxfile_e lbxf = lbxfile_id(id); if (lbxf < LBXFILE_NUM) { lbxfile_add_patch(lbxf, itemi, data, len, filename); return 1; } else { log_error("patch file '%s' item %i base filename '%s' not recognized!\n", filename, pbxi, id); return -1; } } static int pbx_cb_lbxo(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len, uint32_t itemoffs) { lbxfile_e lbxf = lbxfile_id(id); if (lbxf < LBXFILE_NUM) { lbxfile_add_overwrite(lbxf, itemi, itemoffs, data, len, filename); return 1; } else { log_error("patch file '%s' item %i base filename '%s' not recognized!\n", filename, pbxi, id); return -1; } } static bool pbx_cb_strp(void *ctx, const char *filename, int pbxi, const char *id, const uint8_t *patchstr_data, int itemi, uint32_t len) { char *patchstr = str_from_buf(patchstr_data, len); if (!game_str_patch(id, patchstr, itemi)) { log_error("patch file '%s' item %i strid '%s' (%i) invalid!\n", filename, pbxi, id, itemi); lib_free(patchstr); return false; } lib_free(patchstr); return true; } static bool pbx_cb_nump(void *ctx, const char *filename, int pbxi, const char *id, const int32_t *patchnums, int first, int num) { if (!game_num_patch(id, patchnums, first, num)) { log_error("patch file '%s' item %i numid '%s' (%i) invalid!\n", filename, pbxi, id, first); return false; } return true; } /* -------------------------------------------------------------------------- */ int pbx_add_file(const char *filename, struct pbx_add_cbs *cbs_in, void *ctx) { FILE *fd; uint8_t buf[PBX_ITEM_HEADER_LEN + 4]; uint32_t version; uint32_t items; char *id = NULL; uint8_t *data = NULL; int res = -1; struct pbx_add_cbs cbs; cbs.name = (cbs_in && cbs_in->name) ? cbs_in->name : pbx_cb_name; cbs.desc = (cbs_in && cbs_in->desc) ? cbs_in->desc : pbx_cb_desc; cbs.lbxp = (cbs_in && cbs_in->lbxp) ? cbs_in->lbxp : pbx_cb_lbxp; cbs.strp = (cbs_in && cbs_in->strp) ? cbs_in->strp : pbx_cb_strp; cbs.nump = (cbs_in && cbs_in->nump) ? cbs_in->nump : pbx_cb_nump; cbs.lbxo = (cbs_in && cbs_in->lbxo) ? cbs_in->lbxo : pbx_cb_lbxo; log_message("PBX: applying patch file '%s'\n", filename); fd = fopen(filename, "rb"); if (!fd) { log_error("opening patch file '%s'!\n", filename); goto fail; } if (fread(buf, PBX_HEADER_LEN, 1, fd) < 1) { log_error("reading header of file '%s'!\n", filename); goto fail; } if (memcmp(buf, (const uint8_t *)PBX_MAGIC, 8) != 0) { log_error("invalid PBX header on file '%s'!\n", filename); goto fail; } version = GET_LE_32(&buf[PBX_OFFS_VERSION]); items = GET_LE_32(&buf[PBX_OFFS_ITEMS]); if (version != PBX_VERSION) { log_error("invalid PBX version %i on file '%s'! (expected %i)\n", version, filename, PBX_VERSION); goto fail; } for (int i = 0; i < items; ++i) { uint32_t offs, len, itemoffs; uint16_t type, itemi; int ri; if (fseek(fd, PBX_HEADER_LEN + i * 4, SEEK_SET)) { log_error("problem seeking to item %i offs %i\n", i, PBX_HEADER_LEN + i * 4); goto fail; } if (fread(buf, 4, 1, fd) < 1) { log_error("problem reading file\n"); goto fail; } offs = GET_LE_32(buf); if (fseek(fd, offs, SEEK_SET)) { log_error("problem seeking to item %i header at %i\n", i, offs); goto fail; } if (fread(buf, PBX_ITEM_HEADER_LEN, 1, fd) < 1) { log_error("reading item %i header of file '%s'!\n", i, filename); goto fail; } len = GET_LE_32(&(buf[PBX_OFFS_ITEM_LEN])); type = GET_LE_16(&(buf[PBX_OFFS_ITEM_TYPE])); itemi = GET_LE_16(&(buf[PBX_OFFS_ITEM_INDEX])); id = str_from_buf((const void *)&(buf[PBX_OFFS_ITEM_ID]), PBX_ITEM_ID_LEN); switch (type) { case PBX_ITEM_TYPE_LBXO: if (fread(&(buf[PBX_OFFS_ITEM_OFFS]), 4, 1, fd) < 1) { log_error("reading item %i offset (len %i) of file '%s'!\n", i, len, filename); goto fail; } itemoffs = GET_LE_32(&(buf[PBX_OFFS_ITEM_OFFS])); len -= 4; break; default: itemoffs = 0; break; } data = lib_malloc(len); if (fread(data, len, 1, fd) < 1) { log_error("reading item %i data (len %i) of file '%s'!\n", i, len, filename); goto fail; } switch (type) { case PBX_ITEM_TYPE_NAME: ri = cbs.name(ctx, filename, i, data, len); if (ri > 0) { data = NULL; } else if (ri < 0) { goto fail; } break; case PBX_ITEM_TYPE_DESC: ri = cbs.desc(ctx, filename, i, data, len); if (ri > 0) { data = NULL; } else if (ri < 0) { goto fail; } break; case PBX_ITEM_TYPE_LBXP: ri = cbs.lbxp(ctx, filename, i, id, itemi, data, len); if (ri > 0) { data = NULL; } else if (ri < 0) { goto fail; } break; case PBX_ITEM_TYPE_LBXO: ri = cbs.lbxo(ctx, filename, i, id, itemi, data, len, itemoffs); if (ri > 0) { data = NULL; } else if (ri < 0) { goto fail; } break; case PBX_ITEM_TYPE_STRP: if (!cbs.strp(ctx, filename, i, id, data, itemi, len)) { goto fail; } break; case PBX_ITEM_TYPE_NUMP: { uint8_t *p; int32_t *nums; int numnum; numnum = len / 4; nums = lib_malloc(numnum * sizeof(int32_t)); p = data; for (int j = 0; j < numnum; ++j) { nums[j] = (int32_t)GET_LE_32(p); p += 4; } if (!cbs.nump(ctx, filename, i, id, nums, itemi, numnum)) { lib_free(nums); goto fail; } lib_free(nums); } break; default: log_error("patch file '%s' item %i type %i not recognized!\n", filename, i, type); goto fail; } lib_free(id); id = NULL; lib_free(data); data = NULL; } res = 0; fail: if (id) { lib_free(id); id = NULL; } if (data) { lib_free(data); data = NULL; } if (fd) { fclose(fd); fd = NULL; } return res; } int pbx_queue_file(const char *filename) { if (num_patchfiles < MAX_PATCHFILES) { patchfiles[num_patchfiles++] = filename; return 0; } return -1; } int pbx_apply_queued_files(void) { for (int i = 0; i < num_patchfiles; ++i) { if (pbx_add_file(patchfiles[i], NULL, NULL) < 0) { return -1; } } return 0; } 1oom-1.11.2/src/pbx.h000066400000000000000000000031041476061725400142120ustar00rootroot00000000000000#ifndef INC_1OOM_PBX_H #define INC_1OOM_PBX_H #include "types.h" #define PBX_HEADER_LEN 16 #define PBX_MAGIC "1oomPBX " #define PBX_OFFS_VERSION 8 #define PBX_OFFS_ITEMS 12 #define PBX_VERSION 1 #define PBX_ITEM_HEADER_LEN 32 #define PBX_OFFS_ITEM_LEN 0 #define PBX_OFFS_ITEM_TYPE 4 #define PBX_OFFS_ITEM_INDEX 6 #define PBX_OFFS_ITEM_ID 8 #define PBX_OFFS_ITEM_OFFS PBX_ITEM_HEADER_LEN #define PBX_ITEM_ID_LEN (PBX_ITEM_HEADER_LEN - PBX_OFFS_ITEM_ID) typedef enum { PBX_ITEM_TYPE_NAME = 0, PBX_ITEM_TYPE_DESC, PBX_ITEM_TYPE_LBXP, PBX_ITEM_TYPE_STRP, PBX_ITEM_TYPE_NUMP, PBX_ITEM_TYPE_LBXO } pbx_item_type_t; struct pbx_add_cbs { /* int callbacks return 1 if data is not to be freed */ int (*name)(void *ctx, const char *filename, int pbxi, uint8_t *str, uint32_t len); int (*desc)(void *ctx, const char *filename, int pbxi, uint8_t *str, uint32_t len); int (*lbxp)(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len); bool (*strp)(void *ctx, const char *filename, int pbxi, const char *id, const uint8_t *patchstr, int itemi, uint32_t len); bool (*nump)(void *ctx, const char *filename, int pbxi, const char *id, const int32_t *patchnums, int first, int num); int (*lbxo)(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len, uint32_t itemoffs); }; extern int pbx_add_file(const char *filename, struct pbx_add_cbs *cbs, void *ctx); extern int pbx_queue_file(const char *filename); extern int pbx_apply_queued_files(void); #endif 1oom-1.11.2/src/pbxdump.c000066400000000000000000000213431476061725400151000ustar00rootroot00000000000000#include "config.h" #include #include #include #include "pbx.h" #include "lbx.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" /* -------------------------------------------------------------------------- */ #ifdef FEATURE_MODEBUG int opt_modebug = 0; #endif bool game_num_patch(const char *numid, const int32_t *patchnums, int first, int num) { return false; } bool game_str_patch(const char *strid, const char *patchstr, int i) { return false; } lbxfile_e lbxfile_id(const char *filename) { return LBXFILE_NUM; } void lbxfile_add_patch(lbxfile_e file_id, uint16_t i, uint8_t *data, uint32_t len, const char *patchfilename) { } void lbxfile_add_overwrite(lbxfile_e file_id, uint16_t i, uint32_t itemoffs, uint8_t *data, uint32_t len, const char *patchfilename) { } /* -------------------------------------------------------------------------- */ struct pbxdump_s { FILE *fd; const char *pbxin; const char *prefix; const char *prefix_file; bool flag_write; }; /* -------------------------------------------------------------------------- */ static int pbxdump_write(const char *prefix, const char *suffix, bool flag_write, const uint8_t *data, uint32_t len) { if (flag_write) { char *fname = util_concat(prefix, suffix, NULL); if (util_file_save(fname, data, len) < 0) { log_error("writing '%s'!\n", fname); lib_free(fname); return -1; } lib_free(fname); } return 0; } static int pbx_dump_textish(struct pbxdump_s *d, const char *filename, int pbxi, const uint8_t *str, uint32_t len, const char *pbxtext, const char *suffix) { bool can_print; if (len < 10) { can_print = true; } else if (len > 200) { can_print = false; } else { int n = 0; for (uint32_t i = 0; i < len; ++i) { char c; c = str[i]; n += ((c < 0x20) || (c > 0x7e)) ? -1 : 1; } can_print = (n > 2); } if (can_print) { if (fprintf(d->fd, "%s,\"", pbxtext) < 0) { goto fail; } for (uint32_t i = 0; i < len; ++i) { char c, c0; c = str[i]; switch (c) { case '\\': case '"': c0 = '\\'; break; case '\n': c0 = '\\'; c = 'n'; break; case '\r': c0 = '\\'; c = 'r'; break; default: c0 = 0; if ((c < 0x20) || (c > 0x7e)) { const char hexchars[0x10] = "0123456789abcdef"; char buf[4]; buf[0] = '\\'; buf[1] = 'x'; buf[2] = hexchars[(c >> 4) & 0xf]; buf[3] = hexchars[c & 0xf]; c = 0; if (fwrite(buf, 4, 1, d->fd) < 1) { goto fail; } } break; } if (0 || (c0 && (fputc(c0, d->fd) == EOF)) || (c && (fputc(c, d->fd) == EOF)) ) { goto fail; } } if (fprintf(d->fd, "\"\n") < 0) { goto fail; } return 0; } else { if (fprintf(d->fd, "%s,%s%s\n", pbxtext, d->prefix_file, suffix) < 0) { goto fail; } return pbxdump_write(d->prefix, suffix, d->flag_write, (const uint8_t *)str, len); } fail: log_error("writing PBXIN file %s\n", d->pbxin); return -1; } static int pbx_cb_name(void *ctx, const char *filename, int pbxi, uint8_t *str, uint32_t len) { return pbx_dump_textish(ctx, filename, pbxi, str, len, "0", "_name.txt"); } static int pbx_cb_desc(void *ctx, const char *filename, int pbxi, uint8_t *str, uint32_t len) { return pbx_dump_textish(ctx, filename, pbxi, str, len, "1", "_desc.txt"); } static int pbx_cb_lbxp(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len) { char pbxtext[32]; char suffix[40]; char *p = suffix; *p++ = '_'; for (const char *q = id; *q != '.';) { *p++ = *q++; } lib_sprintf(p, sizeof(suffix), "_%03u.bin", itemi); lib_sprintf(pbxtext, sizeof(pbxtext), "2,%s,%u", id, itemi); return pbx_dump_textish(ctx, filename, pbxi, data, len, pbxtext, suffix); } static int pbx_cb_lbxo(void *ctx, const char *filename, int pbxi, const char *id, uint16_t itemi, uint8_t *data, uint32_t len, uint32_t itemoffs) { char pbxtext[32]; char suffix[40]; char *p = suffix; *p++ = '_'; for (const char *q = id; *q != '.';) { *p++ = *q++; } lib_sprintf(p, sizeof(suffix), "_%03u.bin", itemi); lib_sprintf(pbxtext, sizeof(pbxtext), "5,%s,%u,0x%x", id, itemi, itemoffs); return pbx_dump_textish(ctx, filename, pbxi, data, len, pbxtext, suffix); } static bool pbx_cb_strp(void *ctx, const char *filename, int pbxi, const char *id, const uint8_t *patchstr, int itemi, uint32_t len) { char pbxtext[32]; char suffix[40]; lib_sprintf(pbxtext, sizeof(pbxtext), "3,%s,%i", id, itemi); lib_sprintf(suffix, sizeof(suffix), "_%s_%i.txt", id, itemi); return (pbx_dump_textish(ctx, filename, pbxi, patchstr, len, pbxtext, suffix) == 0); } static bool pbx_cb_nump(void *ctx, const char *filename, int pbxi, const char *id, const int32_t *patchnums, int first, int num) { struct pbxdump_s *d = ctx; if (fprintf(d->fd, "4,%s,%i", id, first) < 0) { return false; } for (int i = 0; i < num; ++i) { if (fprintf(d->fd, ",%i", patchnums[i]) < 0) { return false; } } if (fprintf(d->fd, "\n") < 0) { return -1; } return true; } static int dump_pbx(const char *filename, const char *prefix_in, bool flag_write) { struct pbx_add_cbs cbs; struct pbxdump_s ctx; char *fname_pbxin = NULL, *dir = NULL, *fnam = NULL, *prefix = NULL; int res; cbs.name = pbx_cb_name; cbs.desc = pbx_cb_desc; cbs.lbxp = pbx_cb_lbxp; cbs.lbxo = pbx_cb_lbxo; cbs.strp = pbx_cb_strp; cbs.nump = pbx_cb_nump; ctx.flag_write = flag_write; ctx.prefix = prefix = lib_stralloc(prefix_in ? prefix_in : filename); { char *p; p = strrchr(prefix, '.'); if (p && (strcasecmp(p + 1, "pbx") == 0) && ((*(p + 4)) == '\0')) { *p = '\0'; } } util_fname_split(ctx.prefix, &dir, &fnam); if (dir) { if (flag_write && os_make_path(dir)) { log_error("creating path '%s'\n", dir); return -1; } fname_pbxin = util_concat(dir, FSDEV_DIR_SEP_STR, fnam, ".pbxin", NULL); ctx.prefix_file = fnam; } else { ctx.prefix_file = ctx.prefix; fname_pbxin = util_concat(ctx.prefix, ".pbxin", NULL); } if (flag_write) { log_message("PBXDUMP: writing to '%s'\n", fname_pbxin); ctx.fd = fopen(fname_pbxin, "w+"); ctx.pbxin = fname_pbxin; } else { log_message("PBXDUMP: dry run, would use prefix '%s'\n", ctx.prefix); ctx.fd = stdout; ctx.pbxin = "(stdout)"; } res = pbx_add_file(filename, &cbs, &ctx); if (flag_write) { fclose(ctx.fd); ctx.fd = NULL; } lib_free(fname_pbxin); lib_free(dir); lib_free(fnam); lib_free(prefix); return res; } /* -------------------------------------------------------------------------- */ static void show_usage(void) { fprintf(stderr, "Usage:\n" " 1oom_pbxdump [OPTIONS] IN.PBX [OUTPREFIX]\n" "Options:\n" " -w Write files\n" ); } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { const char *filename_in; const char *prefix_out = NULL; bool flag_write = false; int i; i = 1; if (i >= argc) { show_usage(); return 1; } while (argv[i][0] == '-') { if (argv[i][2] != '\0') { show_usage(); return 1; } switch (argv[i][1]) { case 'w': flag_write = true; break; default: show_usage(); return 1; } ++i; } if (i >= argc) { show_usage(); return 1; } filename_in = argv[i++]; if (i < argc) { prefix_out = argv[i++]; if (i < argc) { show_usage(); return 1; } } return dump_pbx(filename_in, prefix_out, flag_write); } 1oom-1.11.2/src/pbxmake.c000066400000000000000000000326071476061725400150550ustar00rootroot00000000000000#include "config.h" #include #include #include #include "pbx.h" #include "bits.h" #include "lib.h" #include "log.h" #include "os.h" #include "types.h" #include "util.h" #include "util_cstr.h" /* -------------------------------------------------------------------------- */ #ifdef FEATURE_MODEBUG int opt_modebug = 0; #endif #define SEP_CHAR ',' struct patch_item_s { struct patch_item_s *next; uint16_t itemtype; uint16_t itemindex; uint32_t itemoffs; bool add_offset; const char *itemid; enum { PARAM_FILENAME, PARAM_DATA_STR, PARAM_DATA_NUM, } param_type; char *fname; /* or data (str) */ char *fullname; /* or data (num) */ uint32_t len; uint32_t pad; uint32_t offs; }; /* -------------------------------------------------------------------------- */ static bool get_file_len(const char *filename, uint32_t *len_out) { FILE *fd = NULL; uint32_t len = 0; if ((fd = fopen(filename, "rb")) == NULL) { perror(filename); goto fail; } if (fseek(fd, 0, SEEK_END) != 0) { perror(filename); goto fail; } len = ftell(fd); if (fd) { fclose(fd); fd = NULL; } *len_out = len; return true; fail: *len_out = 0; if (fd) { fclose(fd); fd = NULL; } return false; } static bool copy_file(const char *filename, uint32_t len_total, FILE *fd_out) { #define BUFSIZE 4096 FILE *fd_in = NULL; uint8_t *data = NULL; bool flag_ok = false; if ((fd_in = fopen(filename, "rb")) == NULL) { perror(filename); goto fail; } data = lib_malloc(BUFSIZE); while (len_total) { uint32_t len; len = (len_total > BUFSIZE) ? BUFSIZE : len_total; if (fread(data, len, 1, fd_in) < 1) { log_error("%s: read error\n", filename); goto fail; } if (fwrite(data, len, 1, fd_out) < 1) { log_error("write error\n"); goto fail; } len_total -= len; } flag_ok = true; fail: lib_free(data); data = NULL; if (fd_in) { fclose(fd_in); fd_in = NULL; } return flag_ok; #undef BUFSIZE } static bool isnl(char c) { return (c == '\r') || (c == '\n'); } static bool isws(char c) { return (c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'); } static bool iswsnotnl(char c) { return (c == ' ') || (c == '\t'); } static int skipws(const char *str, int i, int len) { while ((i < len) && isws(str[i])) { ++i; } return i; } static int skipwsnotnl(const char *str, int i, int len) { while ((i < len) && iswsnotnl(str[i])) { ++i; } return i; } static int findsep(char *str, int i, int len) { while ((i < len) && (str[i] != SEP_CHAR) && !isnl(str[i])) { ++i; } if ((i >= len) || isnl(str[i]) || (str[i] != SEP_CHAR)) { log_error("partial line near byte %i\n", i); return -1; } str[i++] = '\0'; return skipwsnotnl(str, i, len); } static int make_pbx(const char *filename_in, const char *filename_out) { struct patch_item_s *patches = NULL, *tail = NULL; int i, num_patches = 0; uint32_t len = 0; char *dir = NULL, *fullname = NULL; char *listfiledata = (char *)util_file_load(filename_in, &len); if (!listfiledata) { return 2; } util_fname_split(filename_in, &dir, NULL); i = 0; while ((i < len) && (listfiledata[i] != '\0')) { i = skipws(listfiledata, i, len); if (listfiledata[i] == '\0') { break; } else if (listfiledata[i] == '#') { while ((i < len) && !isnl(listfiledata[i])) { ++i; } } else { struct patch_item_s *n; int positemtype, positemid, positemindex, positemoffs, posparam; uint32_t v, flen; bool need_index, need_id, need_offs; pbx_item_type_t pbxitype; uint16_t item_index; uint32_t item_offs; const char *itemid; int32_t *numtbl; int numnum; positemtype = i; if ((i = findsep(listfiledata, i, len)) < 0) { return 3; } if (!util_parse_number(&listfiledata[positemtype], &v)) { log_error("error: invalid type number '%s' at %i\n", &listfiledata[positemtype], positemtype); return 3; } switch (v) { case 0: pbxitype = PBX_ITEM_TYPE_NAME; need_index = false; need_id = false; need_offs = false; itemid = "PBX NAME"; break; case 1: pbxitype = PBX_ITEM_TYPE_DESC; need_index = false; need_id = false; need_offs = false; itemid = "PBX DESC"; break; case 2: pbxitype = PBX_ITEM_TYPE_LBXP; need_index = true; need_id = true; need_offs = false; itemid = NULL; break; case 3: pbxitype = PBX_ITEM_TYPE_STRP; need_index = true; need_id = true; need_offs = false; itemid = NULL; break; case 4: pbxitype = PBX_ITEM_TYPE_NUMP; need_index = true; need_id = true; need_offs = false; itemid = NULL; break; case 5: pbxitype = PBX_ITEM_TYPE_LBXO; need_index = true; need_id = true; need_offs = true; itemid = NULL; break; default: log_error("error: invalid type number %u at %i\n", v, positemtype); return 3; } if (need_id) { int ilen; positemid = i; if ((i = findsep(listfiledata, i, len)) < 0) { return 3; } util_trim_whitespace(&listfiledata[positemid], len - positemid); itemid = &listfiledata[positemid]; ilen = strlen(itemid); if (ilen > PBX_ITEM_ID_LEN) { log_error("error: too long item id string '%s' (%i > %i) at %i\n", itemid, ilen, PBX_ITEM_ID_LEN, positemid); return 3; } } if (need_index) { positemindex = i; if ((i = findsep(listfiledata, i, len)) < 0) { return 3; } util_trim_whitespace(&listfiledata[positemindex], len - positemindex); if (!util_parse_number(&listfiledata[positemindex], &v)) { log_error("error: invalid number '%s' at %i\n", &listfiledata[positemindex], i); return 3; } item_index = v; } else { item_index = 0; } if (need_offs) { positemoffs = i; if ((i = findsep(listfiledata, i, len)) < 0) { return 3; } util_trim_whitespace(&listfiledata[positemoffs], len - positemoffs); if (!util_parse_number(&listfiledata[positemoffs], &v)) { log_error("error: invalid number '%s' at %i\n", &listfiledata[positemoffs], i); return 3; } item_offs = v; } else { item_offs = 0; } posparam = i; while ((i < len) && !isnl(listfiledata[i])) { ++i; } if ((i >= len) || !isnl(listfiledata[i])) { log_error("error: partial line near byte %i\n", i); return 3; } listfiledata[i] = '\0'; ++i; util_trim_whitespace(&listfiledata[posparam], len - posparam); if (fullname) { lib_free(fullname); fullname = NULL; } n = lib_malloc(sizeof(struct patch_item_s)); n->itemtype = pbxitype; n->itemid = itemid; n->itemindex = item_index; n->itemoffs = item_offs; n->add_offset = need_offs; n->next = NULL; n->fname = &listfiledata[posparam]; if (n->fname[0] == '"') { n->param_type = PARAM_DATA_STR; fullname = NULL; if (util_cstr_parse(n->fname, n->fname, &flen) < 0) { return 4; } } else if ((numtbl = util_parse_numbers(n->fname, SEP_CHAR, &numnum)) != NULL) { uint8_t *data; n->param_type = PARAM_DATA_NUM; flen = numnum * 4/*sizeof(int32_t)*/; data = lib_malloc(flen); fullname = (char *)data; for (int j = 0; j < numnum; ++j) { SET_LE_32(data, numtbl[j]); data += 4/*sizeof(int32_t)*/; } lib_free(numtbl); numtbl = NULL; } else { n->param_type = PARAM_FILENAME; if (dir && *dir) { fullname = util_concat(dir, FSDEV_DIR_SEP_STR, n->fname, NULL); } else { fullname = lib_stralloc(n->fname); } if (!get_file_len(fullname, &flen)) { return 4; } } n->fullname = fullname; fullname = NULL; n->len = flen; n->pad = "\0\03\02\01"[flen & 0x3]; if (tail == NULL) { patches = n; } else { tail->next = n; } tail = n; ++num_patches; } } if (num_patches) { const uint8_t pad[3] = { 0, 0, 0 }; uint8_t buf[PBX_ITEM_HEADER_LEN + 4]; FILE *fd; struct patch_item_s *p, *q; uint32_t offs = PBX_HEADER_LEN + (num_patches + 1) * 4; p = patches; while (p) { p->offs = offs; offs += PBX_ITEM_HEADER_LEN + p->len + p->pad; if (p->add_offset) { offs += 4; } p = p->next; } len = offs; fd = fopen(filename_out, "wb"); if (!fd) { perror(filename_out); return 4; } memset(buf, 0, sizeof(buf)); memcpy(buf, PBX_MAGIC, 8); SET_LE_32(&buf[PBX_OFFS_VERSION], PBX_VERSION); SET_LE_32(&buf[PBX_OFFS_ITEMS], num_patches); if (fwrite(buf, PBX_HEADER_LEN, 1, fd) != 1) { perror(filename_out); fclose(fd); return 3; } p = patches; while (p) { SET_LE_32(buf, p->offs); if (fwrite(buf, 4, 1, fd) != 1) { perror(filename_out); fclose(fd); return 3; } p = p->next; } SET_LE_32(buf, len); if (fwrite(buf, 4, 1, fd) != 1) { perror(filename_out); fclose(fd); return 3; } p = patches; i = 0; while (p) { uint32_t hlen, tlen; memset(buf, 0, sizeof(buf)); hlen = PBX_ITEM_HEADER_LEN; tlen = p->len; if (p->add_offset) { hlen += 4; tlen += 4; SET_LE_32(&buf[PBX_OFFS_ITEM_OFFS], p->itemoffs); } SET_LE_32(&buf[PBX_OFFS_ITEM_LEN], tlen); SET_LE_16(&buf[PBX_OFFS_ITEM_TYPE], p->itemtype); SET_LE_16(&buf[PBX_OFFS_ITEM_INDEX], p->itemindex); lib_strcpy((char *)&buf[PBX_OFFS_ITEM_ID], p->itemid, sizeof(buf) - PBX_OFFS_ITEM_ID); if (0 || (fwrite(buf, hlen, 1, fd) != 1) || ((p->param_type == PARAM_FILENAME) && (!copy_file(p->fullname, p->len, fd))) || ((p->param_type == PARAM_DATA_STR) && (fwrite(p->fname, p->len, 1, fd) != 1)) || ((p->param_type == PARAM_DATA_NUM) && (fwrite(p->fullname, p->len, 1, fd) != 1)) || ((p->pad != 0) && (fwrite(pad, p->pad, 1, fd) != 1)) ) { log_error("writing file '%s'", filename_out); fclose(fd); return 3; } LOG_DEBUG((0, "%i offs 0x%x: type %i '%s' index %i offset 0x%x %s '%s' len %i+%i+%i+%i\n", i, p->offs, p->itemtype, p->itemid, p->itemindex, p->itemoffs, (p->param_type == PARAM_FILENAME) ? "file" : "data", p->fname, PBX_ITEM_HEADER_LEN, p->add_offset ? 4 : 0, p->len, p->pad)); p = p->next; ++i; } fclose(fd); p = patches; q = NULL; while (p) { q = p->next; lib_free(p->fullname); lib_free(p); p = q; } } lib_free(listfiledata); lib_free(dir); return 0; } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { const char *filename_in; const char *filename_out; int i; if (argc != 3) { fprintf(stderr, "Usage: 1oom_pbxmake PBXIN.TXT OUT.PBX\nPBXIN.TXT format:\n" "# comment\n" "0,\"pbx name\"\n" "1,\"pbx description\"\n" "2,filename.lbx,itemnumber,replacementfile.bin\n" "5,filename.lbx,itemnumber,offset,partialdata.bin\n" "3,string_id,itemnumber,\"new text\"\n" "4,number_id,itemnumber,value[,value]*\n" ); return 1; } i = 1; filename_in = argv[i++]; filename_out = argv[i++]; return make_pbx(filename_in, filename_out); } 1oom-1.11.2/src/rnd.c000066400000000000000000000036401476061725400142040ustar00rootroot00000000000000#include "config.h" #include "rnd.h" #include "hw.h" #include "types.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ uint16_t rnd_0_nm1(uint16_t n, uint32_t *seed) { /* NOTE: This code is simplified and contains hacks. Assembler code in this function would be more appropriate. */ uint16_t r = 0; uint32_t di_si = *seed; for (int i = 9; i > 0; --i) { uint16_t ax = di_si; uint16_t dx; { uint32_t dx_bx = di_si; dx_bx >>= 1; ax ^= dx_bx; dx_bx >>= 1; ax ^= dx_bx; dx_bx >>= 2; ax ^= dx_bx; dx_bx >>= 2; ax ^= dx_bx; dx = dx_bx >> 25; } { uint8_t al = ax & 0xff; uint8_t ah = ax >> 8; al ^= dx; ax = ((uint16_t)ah << 8) + al; dx = ax; } r <<= 1; if (dx & 1) { ++r; } di_si >>= 1; if (ax & 1) { di_si += 0x80000000; } } if (di_si == 0) { di_si = 0x30be; } *seed = di_si; return r % n; } uint16_t rnd_1_n(uint16_t n, uint32_t *seed) { return 1 + rnd_0_nm1(n, seed); } uint32_t rnd_get_new_seed(void) { uint32_t seed; seed = hw_get_time_us(); if (seed == 0) { seed = 123; } return seed; } uint16_t rnd_bitfiddle(uint16_t ax) { if (ax == 0) { return 0x35c8; } int loops = 8; uint16_t bx, dx; do { dx = ax; bx = ax; bx >>= 1; ax ^= bx; bx >>= 1; ax ^= bx; bx >>= 2; ax ^= bx; bx >>= 2; ax ^= bx; bx >>= 1; ax ^= bx; dx >>= 1; if (ax & 1) { dx |= 0x8000; } ax = dx; } while (--loops); return ax; } 1oom-1.11.2/src/rnd.h000066400000000000000000000004131476061725400142040ustar00rootroot00000000000000#ifndef INC_1OOM_RND_H #define INC_1OOM_RND_H #include "types.h" extern uint16_t rnd_0_nm1(uint16_t n, uint32_t *seed); extern uint16_t rnd_1_n(uint16_t n, uint32_t *seed); extern uint32_t rnd_get_new_seed(void); extern uint16_t rnd_bitfiddle(uint16_t ax); #endif 1oom-1.11.2/src/saveconv.c000066400000000000000000002743201476061725400152520ustar00rootroot00000000000000#include "config.h" #include #include #include #include "main.h" #include "bits.h" #include "comp.h" #include "hw.h" #include "game/game.h" #include "game/game_aux.h" #include "game/game_save.h" #include "game/game_str.h" #include "lib.h" #include "log.h" #include "os.h" #include "ui.h" #include "util.h" /* -------------------------------------------------------------------------- */ const char *idstr_main = "saveconv"; bool main_use_lbx = false; bool main_use_cfg = false; bool ui_use_audio = false; char *cfg_cfgname(void) { return 0; } int cfg_load(const char *filename) { return -1; /* should never be called */ } int cfg_save(const char *filename) { return -1; /* should never be called */ } /* -------------------------------------------------------------------------- */ static struct game_s *gameptr = 0; static uint8_t *save2buf = 0; static int save2len = 0; static FILE *save2fd = 0; static const char *save2fname = 0; #define SAVE2BUF_SIZE 0x10000 typedef enum { SAVETYPE_SMART = 0, SAVETYPE_MOO13, SAVETYPE_1OOM0, SAVETYPE_TEXT, SAVETYPE_DUMMY, SAVETYPE_NUM } savetype_t; #define SAVETYPE_NATIVE SAVETYPE_1OOM0 #define SAVETYPE_F_OPTOUT (1 << 1) static int savetype_de_smart(struct game_s *g, const char *fname); static bool savetype_is_moo13(struct game_s *g, const char *fname); static int savetype_de_moo13(struct game_s *g, const char *fname); static int savetype_en_moo13(struct game_s *g, const char *fname); static int savetype_de_1oom0(struct game_s *g, const char *fname); static int savetype_en_1oom0(struct game_s *g, const char *fname); static bool savetype_is_text(struct game_s *g, const char *fname); static int savetype_de_text(struct game_s *g, const char *fname); static int savetype_en_text(struct game_s *g, const char *fname); static const struct { const char *name; bool (*detect)(struct game_s *g, const char *fname); int (*decode)(struct game_s *g, const char *fname); /* to native */ int (*encode)(struct game_s *g, const char *fname); uint8_t flags; savetype_t othertype; } savetype[SAVETYPE_NUM] = { { /* SAVETYPE_SMART */ "smart", 0, savetype_de_smart, 0, 0, SAVETYPE_NUM }, { /* SAVETYPE_MOO13 */ "MOO v1.3", savetype_is_moo13, savetype_de_moo13, savetype_en_moo13, 0, SAVETYPE_NATIVE }, { /* SAVETYPE_1OOM0 */ "1oom save version 0", 0, savetype_de_1oom0, savetype_en_1oom0, 0, SAVETYPE_MOO13 }, { /* SAVETYPE_TEXT */ "text", savetype_is_text, savetype_de_text, savetype_en_text, SAVETYPE_F_OPTOUT, SAVETYPE_NATIVE }, { /* SAVETYPE_DUMMY */ "dummy", 0, 0, 0, 0, SAVETYPE_NUM } }; static const struct { char const * const str; const savetype_t type; } savetype_match[] = { { "m", SAVETYPE_MOO13 }, { "1", SAVETYPE_1OOM0 }, { "s", SAVETYPE_SMART }, { "t", SAVETYPE_TEXT }, { "d", SAVETYPE_DUMMY }, { 0, 0 } }; static savetype_t savetypei = SAVETYPE_SMART; static savetype_t savetypeo = SAVETYPE_SMART; static int main_fname_num = 0; static const char *fnames[2] = { 0/*in*/, 0/*out*/ }; static char savename[SAVE_NAME_LEN] = ""; static bool opt_use_configmoo = false; /* -------------------------------------------------------------------------- */ static int save_out_open(const char *fname) { if (fname && (strcmp(fname, "-") != 0)) { save2fd = fopen(fname, "wb+"); if (!save2fd) { log_error("opening file '%s' for output!\n", fname); return -1; } save2fname = fname; } else { save2fd = stdout; save2fname = 0; } return 0; } static int save_out_flush(void) { if (save2len && fwrite(save2buf, save2len, 1, save2fd) != 1) { log_error("writing to file '%s'!\n", save2fname ? save2fname : "(stdout)"); return -1; } save2len = 0; return 0; } static int save_out_close(void) { if (save2fd && save2fname) { fclose(save2fd); save2fd = 0; save2fname = 0; } return 0; } static int save_out_write(const char *fname) { return save_out_open(fname) || save_out_flush() || save_out_close(); } /* -------------------------------------------------------------------------- */ static int savetype_de_smart(struct game_s *g, const char *fname) { FILE *fd; int res; LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); if ((fd = fopen(fname, "rb")) == 0) { log_error("opening file '%s'\n", fname); return -1; } fclose(fd); fd = NULL; if ((fd = game_save_open_check_header(fname, -1, false, 0, 0)) != 0) { fclose(fd); fd = NULL; savetypei = SAVETYPE_NATIVE; res = savetype[SAVETYPE_NATIVE].decode(g, fname); } else if (savetype_is_moo13(g, fname)) { savetypei = SAVETYPE_MOO13; res = savetype_de_moo13(g, fname); } else if (savetype_is_text(g, fname)) { savetypei = SAVETYPE_TEXT; res = savetype_de_text(g, fname); } else { log_error("file '%s' type autodetection failed\n", fname); return -1; } LOG_DEBUG((1, "%s: i '%s' o '%s'\n", __func__, savetype[savetypei].name, savetype[savetypeo].name)); if (savetypeo == SAVETYPE_SMART) { savetype_t typeo = savetype[savetypei].othertype; if (typeo == SAVETYPE_NUM) { log_error("BUG: no other type for type '%s'\n", savetype[savetypei].name); return -1; } savetypeo = typeo; LOG_DEBUG((1, "%s: diverted to '%s'\n", __func__, savetype[typeo].name)); } return res; } /* -------------------------------------------------------------------------- */ static int try_load_len(const char *fname, uint8_t *buf, int wantlen) { FILE *fd = 0; int len = -1; if (0 || ((fd = fopen(fname, "rb")) == 0) || ((len = fread(buf, 1, wantlen + 1, fd)) != wantlen) ) { LOG_DEBUG((1, "%s: loading '%s' (got %i != %i bytes)\n", __func__, fname, len, wantlen)); len = -1; } if (fd) { fclose(fd); fd = NULL; } return len; } /* -------------------------------------------------------------------------- */ #define SAVE_MOO13_LEN 59036 #define SAVE_CMOO_LEN 154 static bool savetype_is_moo13(struct game_s *g, const char *fname) { uint16_t w; int len; if ((len = try_load_len(fname, save2buf, SAVE_MOO13_LEN)) <= 0) { return false; } if (0 || ((w = GET_LE_16(&save2buf[0xe2d2])) < 2) || (w > 6) || ((w = GET_LE_16(&save2buf[0xe2d4])) < 0) || (w > 4) || ((w = GET_LE_16(&save2buf[0xe2d6])) < 24) || (w > 108) || ((w = GET_LE_16(&save2buf[0xe2d8])) < 0) || (w > 3) || ((w = GET_LE_16(&save2buf[0xe238])) < 0) || (w > 4) ) { return false; } return true; } #define M13_GET_8(item_, addr_) item_ = save2buf[addr_] #define M13_GET_16(item_, addr_) item_ = GET_LE_16(&save2buf[addr_]) #define M13_GET_32(item_, addr_) item_ = GET_LE_32(&save2buf[addr_]) #define M13_GET_16_OWNER(item_, addr_) \ do { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[addr_]); \ if (t_ == 0xffff) { t_ = PLAYER_NONE; }; \ item_ = t_; \ } while (0) #define M13_GET_16_KILLER(item_, addr_) \ do { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[addr_]); \ if (t_ == 0) { t_ = PLAYER_NONE; } else { --t_; } \ item_ = t_; \ } while (0) #define M13_GET_16_CHECK(item_, addr_, l_, h_) \ do { \ int t_; \ t_ = GET_LE_16(&save2buf[addr_]); \ if ((t_ < l_) || (t_ > h_)) { \ log_error( #item_ " at 0x%04x is %i and not in range %i..%i\n", addr_, t_, l_, h_); \ return -1; \ } \ item_ = t_; \ } while (0) #define M13_GET_TBL_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ item_[i_] = GET_LE_16(&save2buf[(addr_) + i_ * 2]); \ } \ } while (0) #define M13_GET_TBL_16_OWNER(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[(addr_) + i_ * 2]); \ if (t_ == 0xffff) { t_ = PLAYER_NONE; }; \ item_[i_] = t_; \ } \ } while (0) #define M13_GET_TBL_16_HATED(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[(addr_) + i_ * 2]); \ if (t_ == 0) { t_ = PLAYER_NONE; } \ item_[i_] = t_; \ } \ } while (0) #define M13_GET_TBL_BVN_8(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ if (save2buf[(addr_) + i_]) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_BV_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < PLAYER_NUM; ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[(addr_) + i_ * 2]); \ if (t_) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_BVN_16(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ uint16_t t_; \ t_ = GET_LE_16(&save2buf[(addr_) + i_ * 2]); \ if (t_) { \ BOOLVEC_SET1(item_, i_); \ } \ } \ } while (0) #define M13_GET_TBL_32(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ item_[i_] = GET_LE_32(&save2buf[(addr_) + i_ * 4]); \ } \ } while (0) static int savetype_de_moo13_sd(shipdesign_t *sd, int sb) { memcpy(sd->name, &save2buf[sb + 0x00], 11); M13_GET_16(sd->cost, sb + 0x14); M13_GET_16(sd->space, sb + 0x16); M13_GET_16(sd->hull, sb + 0x18); M13_GET_16(sd->look, sb + 0x1a); M13_GET_TBL_16(sd->wpnt, sb + 0x1c); M13_GET_TBL_16(sd->wpnn, sb + 0x24); M13_GET_16(sd->engine, sb + 0x2c); M13_GET_32(sd->engines, sb + 0x2e); M13_GET_TBL_16(sd->special, sb + 0x32); M13_GET_16(sd->shield, sb + 0x38); M13_GET_16(sd->jammer, sb + 0x3a); M13_GET_16(sd->comp, sb + 0x3c); M13_GET_16(sd->armor, sb + 0x3e); M13_GET_16(sd->man, sb + 0x40); M13_GET_16(sd->hp, sb + 0x42); return 0; } static int savetype_de_moo13(struct game_s *g, const char *fname) { LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); { int len; if ((len = try_load_len(fname, save2buf, SAVE_MOO13_LEN)) <= 0) { log_error("loading MOO1 v1.3 save '%s' (got %i != %i bytes)\n", fname, len, SAVE_MOO13_LEN); return -1; } save2len = len; } { void *t = g->gaux; memset(g, 0, sizeof(*g)); g->gaux = t; } M13_GET_16_CHECK(g->players, 0xe2d2, 2, 6); g->is_ai[0] = ((1 << g->players) - 1) & ~1; g->active_player = PLAYER_0; M13_GET_16_CHECK(g->difficulty, 0xe2d4, 0, 4); M13_GET_16_CHECK(g->galaxy_size, 0xe2d8, 0, 3); M13_GET_16_CHECK(g->nebula_num, 0xe238, 0, 4); M13_GET_16_CHECK(g->galaxy_stars, 0xe2d6, 24, 108); M13_GET_16(g->galaxy_w, 0xe2da); M13_GET_16(g->galaxy_h, 0xe2dc); M13_GET_16(g->galaxy_maxx, 0xe2de); M13_GET_16(g->galaxy_maxy, 0xe2e0); M13_GET_16(g->year, 0xe232); M13_GET_16_CHECK(g->enroute_num, 0xe1b6, 0, 259); M13_GET_16_CHECK(g->transport_num, 0xe1b8, 0, 99); M13_GET_16(g->end, 0xe686); g->refuse[0] = (!g->end) ? 0 : 1; M13_GET_16_OWNER(g->winner, 0xe688); M13_GET_16(g->election_held, 0xe68c); for (int i = 0; i < g->nebula_num; ++i) { M13_GET_16(g->nebula_type[i], 0xe23a + i * 2); M13_GET_16(g->nebula_x[i], 0xe242 + i * 2); M13_GET_16(g->nebula_y[i], 0xe24a + i * 2); for (int j = 0; j < 4; ++j) { M13_GET_16(g->nebula_x0[i][j], 0xe252 + (i * 4 + j) * 2); M13_GET_16(g->nebula_x1[i][j], 0xe272 + (i * 4 + j) * 2); M13_GET_16(g->nebula_y0[i][j], 0xe292 + (i * 4 + j) * 2); M13_GET_16(g->nebula_y1[i][j], 0xe2b2 + (i * 4 + j) * 2); } } for (int i = 0; i < g->players; ++i) { memcpy(g->emperor_names[i], &save2buf[0xe1ba + i * 15], EMPEROR_NAME_LEN - 1); } M13_GET_16(g->planet_focus_i[0], 0xe236); for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); int pb; pb = i * 0xb8; memcpy(p->name, &save2buf[pb], PLANET_NAME_LEN - 1); M13_GET_16(p->x, pb + 0xc); M13_GET_16(p->y, pb + 0xe); M13_GET_16(p->star_type, pb + 0x10); M13_GET_16(p->look, pb + 0x12); M13_GET_16(p->frame, pb + 0x14); M13_GET_16(p->rocks, pb + 0x18); M13_GET_16(p->max_pop1, pb + 0x1a); M13_GET_16(p->max_pop2, pb + 0x1c); M13_GET_16(p->max_pop3, pb + 0x1e); M13_GET_16(p->type, pb + 0x20); M13_GET_16(p->battlebg, pb + 0x22); M13_GET_16(p->infogfx, pb + 0x24); M13_GET_16(p->growth, pb + 0x26); M13_GET_16(p->special, pb + 0x28); M13_GET_16(p->bc_to_ecoproj, pb + 0x2a); M13_GET_16(p->bc_to_ship, pb + 0x2c); M13_GET_16(p->bc_to_factory, pb + 0x2e); M13_GET_32(p->reserve, pb + 0x30); M13_GET_16(p->waste, pb + 0x34); M13_GET_16_OWNER(p->owner, pb + 0x36); M13_GET_16_OWNER(p->prev_owner, pb + 0x38); M13_GET_16_OWNER(p->claim, pb + 0xa0); M13_GET_16(p->pop, pb + 0x3a); M13_GET_16(p->pop_prev, pb + 0x3c); M13_GET_16(p->factories, pb + 0x3e); M13_GET_TBL_16(p->slider, pb + 0x50); M13_GET_TBL_16(p->slider_lock, pb + 0x72); M13_GET_16(p->buildship, pb + 0x5a); M13_GET_16(p->reloc, pb + 0x5c); M13_GET_16(p->missile_bases, pb + 0x5e); M13_GET_16(p->bc_to_base, pb + 0x60); M13_GET_16(p->bc_upgrade_base, pb + 0x62); M13_GET_16(p->have_stargate, pb + 0x64); M13_GET_16(p->shield, pb + 0x68); M13_GET_16(p->bc_to_shield, pb + 0x6a); M13_GET_16(p->trans_num, pb + 0x6c); M13_GET_16(p->trans_dest, pb + 0x6e); M13_GET_8(p->pop_tenths, pb + 0x70); M13_GET_TBL_BV_16(p->explored, pb + 0x7c); M13_GET_16(p->pop_oper_fact, pb + 0xae); M13_GET_16(p->bc_to_refit, pb + 0xb0); M13_GET_16(p->rebels, pb + 0xb2); M13_GET_16(p->unrest, pb + 0xb4); M13_GET_16(p->unrest_reported, pb + 0xb6); } for (int i = 0; i < g->galaxy_stars; ++i) { seen_t *s = &(g->seen[PLAYER_0][i]); M13_GET_16_OWNER(s->owner, 0xe2e2 + i * 2); M13_GET_16(s->pop, 0xe3ba + i * 2); M13_GET_16(s->bases, 0xe492 + i * 2); M13_GET_16(s->factories, 0xe56a + i * 2); } for (int j = PLAYER_1; j < g->players; ++j) { for (int i = 0; i < g->galaxy_stars; ++i) { seen_t *s = &(g->seen[j][i]); s->owner = PLAYER_NONE; } } for (int i = 0; i < g->enroute_num; ++i) { fleet_enroute_t *r = &(g->enroute[i]); int rb; rb = 0x4da0 + i * 0x1c; M13_GET_16_OWNER(r->owner, rb + 0x00); M13_GET_16(r->x, rb + 0x02); M13_GET_16(r->y, rb + 0x04); M13_GET_16(r->dest, rb + 0x06); M13_GET_8(r->speed, rb + 0x08); M13_GET_TBL_16(r->ships, rb + 0x0a); } for (int i = 0; i < g->transport_num; ++i) { transport_t *r = &(g->transport[i]); int rb; rb = 0x6a10 + i * 0x12; M13_GET_16_OWNER(r->owner, rb + 0x00); M13_GET_16(r->x, rb + 0x02); M13_GET_16(r->y, rb + 0x04); M13_GET_16(r->dest, rb + 0x06); M13_GET_8(r->speed, rb + 0x10); M13_GET_16(r->pop, rb + 0x08); } for (int i = 0; i < g->players; ++i) { empiretechorbit_t *e = &(g->eto[i]); int eb; eb = 0x7118 + i * 0xdd4; M13_GET_8(e->race, eb + 0x000); M13_GET_8(e->banner, eb + 0x002); M13_GET_8(e->trait1, eb + 0x004); M13_GET_8(e->trait2, eb + 0x006); M13_GET_16(e->ai_p3_countdown, eb + 0x008); M13_GET_16(e->ai_p2_countdown, eb + 0x00a); M13_GET_TBL_BV_16(e->contact, eb + 0x00c); M13_GET_TBL_16(e->relation1, eb + 0x018); M13_GET_TBL_16(e->relation2, eb + 0x024); M13_GET_TBL_16(e->diplo_type, eb + 0x030); M13_GET_TBL_16(e->diplo_val, eb + 0x03c); M13_GET_TBL_16(e->diplo_p1, eb + 0x048); M13_GET_TBL_16(e->diplo_p2, eb + 0x054); M13_GET_TBL_16(e->trust, eb + 0x06c); M13_GET_TBL_16(e->broken_treaty, eb + 0x078); M13_GET_TBL_16(e->blunder, eb + 0x084); M13_GET_TBL_16(e->tribute_field, eb + 0x090); M13_GET_TBL_16(e->tribute_tech, eb + 0x09c); M13_GET_TBL_16(e->mood_treaty, eb + 0x0a8); M13_GET_TBL_16(e->mood_trade, eb + 0x0b4); M13_GET_TBL_16(e->mood_tech, eb + 0x0c0); M13_GET_TBL_16(e->mood_peace, eb + 0x0cc); M13_GET_TBL_16(e->treaty, eb + 0x0d8); M13_GET_TBL_16(e->trade_bc, eb + 0x0e4); M13_GET_TBL_16(e->trade_percent, eb + 0x0f0); M13_GET_TBL_16(e->spymode_next, eb + 0x0fc); M13_GET_TBL_16(e->offer_field, eb + 0x1d4); M13_GET_TBL_16(e->offer_tech, eb + 0x1e0); M13_GET_TBL_16(e->offer_bc, eb + 0x1ec); M13_GET_TBL_16_HATED(e->attack_bounty, eb + 0x21c); M13_GET_TBL_16_HATED(e->bounty_collect, eb + 0x228); M13_GET_TBL_16(e->attack_gift_field, eb + 0x234); M13_GET_TBL_16(e->attack_gift_tech, eb + 0x240); M13_GET_TBL_16(e->attack_gift_bc, eb + 0x24c); M13_GET_TBL_16(e->hatred, eb + 0x270); M13_GET_TBL_16(e->have_met, eb + 0x27c); M13_GET_TBL_16(e->trade_established_bc, eb + 0x288); M13_GET_TBL_16(e->spying, eb + 0x2a4); M13_GET_TBL_16(e->spyfund, eb + 0x2b0); M13_GET_TBL_16(e->spymode, eb + 0x2c8); M13_GET_16(e->security, eb + 0x2d4); M13_GET_TBL_16(e->spies, eb + 0x2d6); M13_GET_32(e->reserve_bc, eb + 0x2fc); M13_GET_16(e->tax, eb + 0x300); M13_GET_16(e->base_shield, eb + 0x302); M13_GET_16(e->base_comp, eb + 0x304); M13_GET_16(e->base_weapon, eb + 0x306); M13_GET_16(e->colonist_oper_factories, eb + 0x326); M13_GET_TBL_16(e->tech.percent, eb + 0x332 + 0x00); M13_GET_TBL_16(e->tech.slider, eb + 0x332 + 0x0c); M13_GET_TBL_16(e->tech.slider_lock, eb + 0x332 + 0x60); M13_GET_TBL_32(e->tech.investment, eb + 0x332 + 0x18); M13_GET_TBL_16(e->tech.project, eb + 0x332 + 0x30); M13_GET_TBL_32(e->tech.cost, eb + 0x332 + 0x3c); M13_GET_TBL_16(e->tech.completed, eb + 0x332 + 0x54); M13_GET_16_CHECK(e->shipdesigns_num, eb + 0x3a0, 0, 6); for (int j = 0; j < g->galaxy_stars; ++j) { fleet_orbit_t *r = &(e->orbit[j]); int ob; ob = eb + 0x3a2 + j * 0x18; M13_GET_TBL_16(r->ships, ob + 0x0c); } M13_GET_TBL_16(g->eto[PLAYER_0].spyreportfield[i], eb + 0xdc2); M13_GET_16(g->eto[PLAYER_0].spyreportyear[i], eb + 0xdce); M13_GET_16(e->shipi_colony, eb + 0xdd0); M13_GET_16(e->shipi_bomber, eb + 0xdd2); } for (int i = 0; i < g->players; ++i) { shipresearch_t *srd = &(g->srd[i]); int srdb, pos; srdb = 0xc410 + i * 0x468; for (int j = 0; j < g->eto[i].shipdesigns_num; ++j) { if (savetype_de_moo13_sd(&(srd->design[j]), srdb + j * 0x44) != 0) { return -1; } } pos = srdb + 0x228; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int t = 0; t < TECH_TIER_NUM; ++t) { for (int j = 0; j < 3; ++j) { M13_GET_8(srd->researchlist[f][t][j], pos); ++pos; } } } pos = srdb + 0x2dc; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int j = 0; j < TECH_PER_FIELD; ++j) { M13_GET_8(srd->researchcompleted[f][j], pos); ++pos; } } M13_GET_TBL_16(srd->year, srdb + 0x450); } if (savetype_de_moo13_sd(&(g->current_design[PLAYER_0]), 0xe642) != 0) { return -1; } { gameevents_t *ev = &(g->evn); const int evb = 0xde80; M13_GET_16(ev->year, evb + 0x000); M13_GET_TBL_BVN_16(ev->done, evb + 0x004, 20); M13_GET_16(ev->have_plague, evb + 0x02c); M13_GET_16(ev->plague_player, evb + 0x02e); M13_GET_16(ev->plague_planet_i, evb + 0x030); M13_GET_16(ev->plague_val, evb + 0x032); M13_GET_16(ev->have_nova, evb + 0x03a); M13_GET_16(ev->nova_player, evb + 0x03c); M13_GET_16(ev->nova_planet_i, evb + 0x03e); M13_GET_16(ev->nova_years, evb + 0x040); M13_GET_16(ev->nova_val, evb + 0x042); M13_GET_16(ev->have_accident, evb + 0x044); M13_GET_16(ev->accident_planet_i, evb + 0x048); M13_GET_16(ev->have_comet, evb + 0x056); M13_GET_16(ev->comet_player, evb + 0x058); M13_GET_16(ev->comet_planet_i, evb + 0x05a); M13_GET_16(ev->comet_years, evb + 0x05c); M13_GET_16(ev->comet_hp, evb + 0x05e); M13_GET_16(ev->comet_dmg, evb + 0x060); M13_GET_16(ev->have_pirates, evb + 0x062); M13_GET_16(ev->pirates_planet_i, evb + 0x066); M13_GET_16(ev->pirates_hp, evb + 0x068); M13_GET_16(ev->crystal.exists, evb + 0x06e); M13_GET_16(ev->crystal.x, evb + 0x070); M13_GET_16(ev->crystal.y, evb + 0x072); M13_GET_16_KILLER(ev->crystal.killer, evb + 0x076); M13_GET_16(ev->crystal.dest, evb + 0x078); M13_GET_16(ev->crystal.counter, evb + 0x074); M13_GET_16(ev->crystal.nuked, evb + 0x07a); M13_GET_16(ev->amoeba.exists, evb + 0x07c); M13_GET_16(ev->amoeba.x, evb + 0x07e); M13_GET_16(ev->amoeba.y, evb + 0x080); M13_GET_16_KILLER(ev->amoeba.killer, evb + 0x084); M13_GET_16(ev->amoeba.dest, evb + 0x086); M13_GET_16(ev->amoeba.counter, evb + 0x082); M13_GET_16(ev->amoeba.nuked, evb + 0x088); M13_GET_8(ev->planet_orion_i, evb + 0x09c); M13_GET_8(ev->have_guardian, evb + 0x09e); M13_GET_TBL_16(ev->home, evb + 0x0a0); M13_GET_8(ev->report_stars, evb + 0x0ac); for (int i = 1; i < g->players; ++i) { M13_GET_16(ev->spies_caught[i][PLAYER_0], evb + 0x1f2 + i * 2); } M13_GET_TBL_16(ev->spies_caught[PLAYER_0], evb + 0x1fe); M13_GET_TBL_16(ev->ceasefire[PLAYER_0], evb + 0x28e); M13_GET_TBL_BVN_8(ev->help_shown[PLAYER_0], evb + 0x2e2, 16); /* TODO build_finished ; is it even possible to save before clicking them away? */ M13_GET_TBL_16_OWNER(ev->voted, evb + 0x320); M13_GET_16(ev->best_ecorestore[PLAYER_0], evb + 0x32c); M13_GET_16(ev->best_wastereduce[PLAYER_0], evb + 0x32e); M13_GET_16(ev->best_roboctrl[PLAYER_0], evb + 0x332); M13_GET_16(ev->best_terraform[PLAYER_0], evb + 0x334); } { uint8_t v = 0; int a = 0xe68e; for (int i = 0; i < g->galaxy_stars; ++i) { if ((i & 7) == 0) { M13_GET_8(v, a); ++a; } if (v & (1 << (i & 7))) { BOOLVEC_SET1(g->planet[i].finished, FINISHED_SHIP); } } } if (savename[0] == 0) { char *dir; char *fnam; char savei; util_fname_split(fname, &dir, &fnam); savei = fnam[4] - '0'; fnam[4] = 'x'; if (strcasecmp(fnam, "savex.gam") != 0) { savei = 0; } if (opt_use_configmoo && (savei >= 1) && (savei <= 6)) { bool found = true; uint8_t *cmoobuf = &save2buf[SAVE_MOO13_LEN]; char *fullname = 0; const char *tryname; tryname = "config.moo"; if (dir) { tryname = fullname = util_concat(dir, FSDEV_DIR_SEP_STR, tryname, NULL); } if (try_load_len(tryname, cmoobuf, SAVE_CMOO_LEN) <= 0) { tryname = "CONFIG.MOO"; if (dir) { lib_free(fullname); tryname = fullname = util_concat(dir, FSDEV_DIR_SEP_STR, tryname, NULL); } if (try_load_len(tryname, cmoobuf, SAVE_CMOO_LEN) <= 0) { found = false; } } if (found) { lib_strcpy(savename, (const char *)&cmoobuf[0x22 + 20 * (savei - 1)], SAVE_NAME_LEN); LOG_DEBUG((1, "found '%s' slot %i '%s'\n", tryname, savei, savename)); } if (fullname) { lib_free(fullname); fullname = 0; } } lib_free(fnam); lib_free(dir); if ((savename[0] == 0) && (savei >= 1) && (savei <= 7)) { lib_sprintf(savename, SAVE_NAME_LEN, "v1.3 SAVE%i.GAM", savei); LOG_DEBUG((1, "generated '%s' -> '%s'\n", fname, savename)); } } return 0; } #define M13_SET_8(item_, addr_) save2buf[addr_] = item_ #define M13_SET_16(item_, addr_) SET_LE_16(&save2buf[addr_], item_) #define M13_SET_32(item_, addr_) SET_LE_32(&save2buf[addr_], item_) #define M13_SET_16_OWNER(item_, addr_) \ do { \ uint16_t t_; \ t_ = item_; \ if (t_ == PLAYER_NONE) { t_ = 0xffff; }; \ SET_LE_16(&save2buf[addr_], t_); \ } while (0) #define M13_SET_16_HATED(item_, addr_) \ do { \ uint16_t t_; \ t_ = item_; \ if (t_ == PLAYER_NONE) { t_ = 0; } \ SET_LE_16(&save2buf[addr_], t_); \ } while (0) #define M13_SET_16_KILLER(item_, addr_) \ do { \ uint16_t t_; \ t_ = item_; \ if (t_ == PLAYER_NONE) { t_ = 0; } else { ++t_; } \ SET_LE_16(&save2buf[addr_], t_); \ } while (0) #define M13_SET_16_CHECK(item_, addr_, l_, h_) \ do { \ uint16_t t_; \ t_ = item_; \ if ((t_ < l_) || (t_ > h_)) { \ log_error( #item_ " is %i and not in range %i..%i\n", addr_, t_, l_, h_); \ return -1; \ } \ SET_LE_16(&save2buf[addr_], t_); \ } while (0) #define M13_SET_TBL_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = item_[i_]; \ SET_LE_16(&save2buf[(addr_) + i_ * 2], t_); \ } \ } while (0) #define M13_SET_TBL_16_OWNER(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = item_[i_]; \ if (t_ == PLAYER_NONE) { t_ = 0xffff; }; \ SET_LE_16(&save2buf[(addr_) + i_ * 2], t_); \ } \ } while (0) #define M13_SET_TBL_16_HATED(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint16_t t_; \ t_ = item_[i_]; \ if (t_ == PLAYER_NONE) { t_ = 0; } \ SET_LE_16(&save2buf[(addr_) + i_ * 2], t_); \ } \ } while (0) #define M13_SET_TBL_BVN_8(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ uint8_t t_; \ t_ = BOOLVEC_IS1(item_, i_); \ save2buf[(addr_) + i_] = t_; \ } \ } while (0) #define M13_SET_TBL_BV_16(item_, addr_) \ do { \ for (int i_ = 0; i_ < PLAYER_NUM; ++i_) { \ uint16_t t_; \ t_ = BOOLVEC_IS1(item_, i_); \ SET_LE_16(&save2buf[(addr_) + i_ * 2], t_); \ } \ } while (0) #define M13_SET_TBL_BVN_16(item_, addr_, n_) \ do { \ for (int i_ = 0; i_ < n_; ++i_) { \ uint16_t t_; \ t_ = BOOLVEC_IS1(item_, i_); \ SET_LE_16(&save2buf[(addr_) + i_ * 2], t_); \ } \ } while (0) #define M13_SET_TBL_32(item_, addr_) \ do { \ for (int i_ = 0; i_ < TBLLEN(item_); ++i_) { \ uint32_t t_; \ t_ = item_[i_]; \ SET_LE_32(&save2buf[(addr_) + i_ * 4], t_); \ } \ } while (0) static int savetype_en_moo13_sd(const shipdesign_t *sd, int sb) { memcpy(&save2buf[sb + 0x00], sd->name, 11); M13_SET_16(sd->cost, sb + 0x14); M13_SET_16(sd->space, sb + 0x16); M13_SET_16(sd->hull, sb + 0x18); M13_SET_16(sd->look, sb + 0x1a); M13_SET_TBL_16(sd->wpnt, sb + 0x1c); M13_SET_TBL_16(sd->wpnn, sb + 0x24); M13_SET_16(sd->engine, sb + 0x2c); M13_SET_32(sd->engines, sb + 0x2e); M13_SET_TBL_16(sd->special, sb + 0x32); M13_SET_16(sd->shield, sb + 0x38); M13_SET_16(sd->jammer, sb + 0x3a); M13_SET_16(sd->comp, sb + 0x3c); M13_SET_16(sd->armor, sb + 0x3e); M13_SET_16(sd->man, sb + 0x40); M13_SET_16(sd->hp, sb + 0x42); return 0; } static int savetype_en_moo13(struct game_s *g, const char *fname) { LOG_DEBUG((2, "%s: '%s'\n", __func__, fname ? fname : "(null)")); memset(save2buf, 0, SAVE_MOO13_LEN); M13_SET_16(g->players, 0xe2d2); M13_SET_16(g->difficulty, 0xe2d4); M13_SET_16(g->galaxy_size, 0xe2d8); M13_SET_16(g->nebula_num, 0xe238); M13_SET_16(g->galaxy_stars, 0xe2d6); M13_SET_16(g->galaxy_w, 0xe2da); M13_SET_16(g->galaxy_h, 0xe2dc); M13_SET_16(g->galaxy_maxx, 0xe2de); M13_SET_16(g->galaxy_maxy, 0xe2e0); M13_SET_16(g->year, 0xe232); M13_SET_16_CHECK(g->enroute_num, 0xe1b6, 0, 259); M13_SET_16_CHECK(g->transport_num, 0xe1b8, 0, 99); M13_SET_16(g->end, 0xe686); M13_SET_16_OWNER(g->winner, 0xe688); M13_SET_16(g->election_held, 0xe68c); for (int i = 0; i < g->nebula_num; ++i) { M13_SET_16(g->nebula_type[i], 0xe23a + i * 2); M13_SET_16(g->nebula_x[i], 0xe242 + i * 2); M13_SET_16(g->nebula_y[i], 0xe24a + i * 2); for (int j = 0; j < 4; ++j) { M13_SET_16(g->nebula_x0[i][j], 0xe252 + (i * 4 + j) * 2); M13_SET_16(g->nebula_x1[i][j], 0xe272 + (i * 4 + j) * 2); M13_SET_16(g->nebula_y0[i][j], 0xe292 + (i * 4 + j) * 2); M13_SET_16(g->nebula_y1[i][j], 0xe2b2 + (i * 4 + j) * 2); } } for (int i = 0; i < g->players; ++i) { memcpy(&save2buf[0xe1ba + i * 15], g->emperor_names[i], EMPEROR_NAME_LEN - 1); } M13_SET_16(g->planet_focus_i[0], 0xe236); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); int pb; pb = i * 0xb8; memcpy(&save2buf[pb], p->name, PLANET_NAME_LEN - 1); M13_SET_16(p->x, pb + 0xc); M13_SET_16(p->y, pb + 0xe); M13_SET_16(p->star_type, pb + 0x10); M13_SET_16(p->look, pb + 0x12); M13_SET_16(p->frame, pb + 0x14); M13_SET_16(p->rocks, pb + 0x18); M13_SET_16(p->max_pop1, pb + 0x1a); M13_SET_16(p->max_pop2, pb + 0x1c); M13_SET_16(p->max_pop3, pb + 0x1e); M13_SET_16(p->type, pb + 0x20); M13_SET_16(p->battlebg, pb + 0x22); M13_SET_16(p->infogfx, pb + 0x24); M13_SET_16(p->growth, pb + 0x26); M13_SET_16(p->special, pb + 0x28); M13_SET_16(p->bc_to_ecoproj, pb + 0x2a); M13_SET_16(p->bc_to_ship, pb + 0x2c); M13_SET_16(p->bc_to_factory, pb + 0x2e); M13_SET_32(p->reserve, pb + 0x30); M13_SET_16(p->waste, pb + 0x34); M13_SET_16_OWNER(p->owner, pb + 0x36); M13_SET_16_OWNER(p->prev_owner, pb + 0x38); M13_SET_16_OWNER(p->claim, pb + 0xa0); M13_SET_16(p->pop, pb + 0x3a); M13_SET_16(p->pop_prev, pb + 0x3c); M13_SET_16(p->factories, pb + 0x3e); M13_SET_TBL_16(p->slider, pb + 0x50); M13_SET_TBL_16(p->slider_lock, pb + 0x72); M13_SET_16(p->buildship, pb + 0x5a); M13_SET_16(p->reloc, pb + 0x5c); M13_SET_16(p->missile_bases, pb + 0x5e); M13_SET_16(p->bc_to_base, pb + 0x60); M13_SET_16(p->bc_upgrade_base, pb + 0x62); M13_SET_16(p->have_stargate, pb + 0x64); M13_SET_16(p->shield, pb + 0x68); M13_SET_16(p->bc_to_shield, pb + 0x6a); M13_SET_16(p->trans_num, pb + 0x6c); M13_SET_16(p->trans_dest, pb + 0x6e); M13_SET_8(p->pop_tenths, pb + 0x70); M13_SET_TBL_BV_16(p->explored, pb + 0x7c); M13_SET_16(p->pop_oper_fact, pb + 0xae); M13_SET_16(p->bc_to_refit, pb + 0xb0); M13_SET_16(p->rebels, pb + 0xb2); M13_SET_16(p->unrest, pb + 0xb4); M13_SET_16(p->unrest_reported, pb + 0xb6); } for (int i = 0; i < g->galaxy_stars; ++i) { const seen_t *s = &(g->seen[PLAYER_0][i]); M13_SET_16_OWNER(s->owner, 0xe2e2 + i * 2); M13_SET_16(s->pop, 0xe3ba + i * 2); M13_SET_16(s->bases, 0xe492 + i * 2); M13_SET_16(s->factories, 0xe56a + i * 2); } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); int rb; rb = 0x4da0 + i * 0x1c; M13_SET_16_OWNER(r->owner, rb + 0x00); M13_SET_16(r->x, rb + 0x02); M13_SET_16(r->y, rb + 0x04); M13_SET_16(r->dest, rb + 0x06); M13_SET_8(r->speed, rb + 0x08); M13_SET_TBL_16(r->ships, rb + 0x0a); } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); int rb; rb = 0x6a10 + i * 0x12; M13_SET_16_OWNER(r->owner, rb + 0x00); M13_SET_16(r->x, rb + 0x02); M13_SET_16(r->y, rb + 0x04); M13_SET_16(r->dest, rb + 0x06); M13_SET_8(r->speed, rb + 0x10); M13_SET_16(r->pop, rb + 0x08); } for (int i = 0; i < g->players; ++i) { const empiretechorbit_t *e = &(g->eto[i]); int eb; eb = 0x7118 + i * 0xdd4; M13_SET_8(e->race, eb + 0x000); M13_SET_8(e->banner, eb + 0x002); M13_SET_8(e->trait1, eb + 0x004); M13_SET_8(e->trait2, eb + 0x006); M13_SET_16(e->ai_p3_countdown, eb + 0x008); M13_SET_16(e->ai_p2_countdown, eb + 0x00a); M13_SET_TBL_BV_16(e->contact, eb + 0x00c); M13_SET_TBL_16(e->relation1, eb + 0x018); M13_SET_TBL_16(e->relation2, eb + 0x024); M13_SET_TBL_16(e->diplo_type, eb + 0x030); M13_SET_TBL_16(e->diplo_val, eb + 0x03c); M13_SET_TBL_16(e->diplo_p1, eb + 0x048); M13_SET_TBL_16(e->diplo_p2, eb + 0x054); M13_SET_TBL_16(e->trust, eb + 0x06c); M13_SET_TBL_16(e->broken_treaty, eb + 0x078); M13_SET_TBL_16(e->blunder, eb + 0x084); M13_SET_TBL_16(e->tribute_field, eb + 0x090); M13_SET_TBL_16(e->tribute_tech, eb + 0x09c); M13_SET_TBL_16(e->mood_treaty, eb + 0x0a8); M13_SET_TBL_16(e->mood_trade, eb + 0x0b4); M13_SET_TBL_16(e->mood_tech, eb + 0x0c0); M13_SET_TBL_16(e->mood_peace, eb + 0x0cc); M13_SET_TBL_16(e->treaty, eb + 0x0d8); M13_SET_TBL_16(e->trade_bc, eb + 0x0e4); M13_SET_TBL_16(e->trade_percent, eb + 0x0f0); M13_SET_TBL_16(e->spymode_next, eb + 0x0fc); M13_SET_TBL_16(e->offer_field, eb + 0x1d4); M13_SET_TBL_16(e->offer_tech, eb + 0x1e0); M13_SET_TBL_16(e->offer_bc, eb + 0x1ec); M13_SET_TBL_16_HATED(e->attack_bounty, eb + 0x21c); M13_SET_TBL_16_HATED(e->bounty_collect, eb + 0x228); M13_SET_TBL_16(e->attack_gift_field, eb + 0x234); M13_SET_TBL_16(e->attack_gift_tech, eb + 0x240); M13_SET_TBL_16(e->attack_gift_bc, eb + 0x24c); M13_SET_TBL_16(e->hatred, eb + 0x270); M13_SET_TBL_16(e->have_met, eb + 0x27c); M13_SET_TBL_16(e->trade_established_bc, eb + 0x288); M13_SET_TBL_16(e->spying, eb + 0x2a4); M13_SET_TBL_16(e->spyfund, eb + 0x2b0); M13_SET_TBL_16(e->spymode, eb + 0x2c8); M13_SET_16(e->security, eb + 0x2d4); M13_SET_TBL_16(e->spies, eb + 0x2d6); M13_SET_32(e->reserve_bc, eb + 0x2fc); M13_SET_16(e->tax, eb + 0x300); M13_SET_16(e->base_shield, eb + 0x302); M13_SET_16(e->base_comp, eb + 0x304); M13_SET_16(e->base_weapon, eb + 0x306); M13_SET_16(e->colonist_oper_factories, eb + 0x326); M13_SET_TBL_16(e->tech.percent, eb + 0x332 + 0x00); M13_SET_TBL_16(e->tech.slider, eb + 0x332 + 0x0c); M13_SET_TBL_16(e->tech.slider_lock, eb + 0x332 + 0x60); M13_SET_TBL_32(e->tech.investment, eb + 0x332 + 0x18); M13_SET_TBL_16(e->tech.project, eb + 0x332 + 0x30); M13_SET_TBL_32(e->tech.cost, eb + 0x332 + 0x3c); M13_SET_TBL_16(e->tech.completed, eb + 0x332 + 0x54); M13_SET_16_CHECK(e->shipdesigns_num, eb + 0x3a0, 0, 6); for (int j = 0; j < g->galaxy_stars; ++j) { const fleet_orbit_t *r = &(e->orbit[j]); int ob; ob = eb + 0x3a2 + j * 0x18; M13_SET_TBL_16(r->ships, ob + 0x0c); } M13_SET_TBL_16(g->eto[PLAYER_0].spyreportfield[i], eb + 0xdc2); M13_SET_16(g->eto[PLAYER_0].spyreportyear[i], eb + 0xdce); M13_SET_16(e->shipi_colony, eb + 0xdd0); M13_SET_16(e->shipi_bomber, eb + 0xdd2); } for (int i = 0; i < g->players; ++i) { const shipresearch_t *srd = &(g->srd[i]); int srdb, pos; srdb = 0xc410 + i * 0x468; for (int j = 0; j < g->eto[i].shipdesigns_num; ++j) { if (savetype_en_moo13_sd(&(srd->design[j]), srdb + j * 0x44) != 0) { return -1; } } pos = srdb + 0x228; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int t = 0; t < TECH_TIER_NUM; ++t) { for (int j = 0; j < 3; ++j) { M13_SET_8(srd->researchlist[f][t][j], pos); ++pos; } } } pos = srdb + 0x2dc; for (int f = 0; f < TECH_FIELD_NUM; ++f) { for (int j = 0; j < TECH_PER_FIELD; ++j) { M13_SET_8(srd->researchcompleted[f][j], pos); ++pos; } } M13_SET_TBL_16(srd->year, srdb + 0x450); } save2len = SAVE_MOO13_LEN; if (savetype_en_moo13_sd(&(g->current_design[PLAYER_0]), 0xe642) != 0) { return -1; } { gameevents_t *ev = &(g->evn); const int evb = 0xde80; M13_SET_16(ev->year, evb + 0x000); M13_SET_TBL_BVN_16(ev->done, evb + 0x004, 20); M13_SET_16(ev->have_plague, evb + 0x02c); M13_SET_16(ev->plague_player, evb + 0x02e); M13_SET_16(ev->plague_planet_i, evb + 0x030); M13_SET_16(ev->plague_val, evb + 0x032); M13_SET_16(ev->have_nova, evb + 0x03a); M13_SET_16(ev->nova_player, evb + 0x03c); M13_SET_16(ev->nova_planet_i, evb + 0x03e); M13_SET_16(ev->nova_years, evb + 0x040); M13_SET_16(ev->nova_val, evb + 0x042); M13_SET_16(ev->have_accident, evb + 0x044); M13_SET_16(ev->accident_planet_i, evb + 0x048); M13_SET_16(ev->have_comet, evb + 0x056); M13_SET_16(ev->comet_player, evb + 0x058); M13_SET_16(ev->comet_planet_i, evb + 0x05a); M13_SET_16(ev->comet_years, evb + 0x05c); M13_SET_16(ev->comet_hp, evb + 0x05e); M13_SET_16(ev->comet_dmg, evb + 0x060); M13_SET_16(ev->have_pirates, evb + 0x062); M13_SET_16(ev->pirates_planet_i, evb + 0x066); M13_SET_16(ev->pirates_hp, evb + 0x068); M13_SET_16(ev->crystal.exists, evb + 0x06e); M13_SET_16(ev->crystal.x, evb + 0x070); M13_SET_16(ev->crystal.y, evb + 0x072); M13_SET_16_KILLER(ev->crystal.killer, evb + 0x076); M13_SET_16(ev->crystal.dest, evb + 0x078); M13_SET_16(ev->crystal.counter, evb + 0x074); M13_SET_16(ev->crystal.nuked, evb + 0x07a); M13_SET_16(ev->amoeba.exists, evb + 0x07c); M13_SET_16(ev->amoeba.x, evb + 0x07e); M13_SET_16(ev->amoeba.y, evb + 0x080); M13_SET_16_KILLER(ev->amoeba.killer, evb + 0x084); M13_SET_16(ev->amoeba.dest, evb + 0x086); M13_SET_16(ev->amoeba.counter, evb + 0x082); M13_SET_16(ev->amoeba.nuked, evb + 0x088); M13_SET_8(ev->planet_orion_i, evb + 0x09c); M13_SET_8(ev->have_guardian, evb + 0x09e); M13_SET_TBL_16(ev->home, evb + 0x0a0); M13_SET_8(ev->report_stars, evb + 0x0ac); for (int i = 1; i < g->players; ++i) { M13_SET_16(ev->spies_caught[i][PLAYER_0], evb + 0x1f2 + i * 2); } M13_SET_TBL_16(ev->spies_caught[PLAYER_0], evb + 0x1fe); M13_SET_TBL_16(ev->ceasefire[PLAYER_0], evb + 0x28e); M13_SET_TBL_BVN_8(ev->help_shown[PLAYER_0], evb + 0x2e2, 16); /* TODO build_finished ; is it even possible to save before clicking them away? */ M13_SET_TBL_16_OWNER(ev->voted, evb + 0x320); M13_SET_16(ev->best_ecorestore[PLAYER_0], evb + 0x32c); M13_SET_16(ev->best_wastereduce[PLAYER_0], evb + 0x32e); M13_SET_16(ev->best_roboctrl[PLAYER_0], evb + 0x332); M13_SET_16(ev->best_terraform[PLAYER_0], evb + 0x334); } { uint8_t v = 0; int i, a = 0xe68e; for (i = 0; i < g->galaxy_stars; ++i) { if (BOOLVEC_IS1(g->planet[i].finished, FINISHED_SHIP)) { v |= (1 << (i & 7)); } if ((i & 7) == 7) { M13_SET_8(v, a); ++a; v = 0; } } if ((i & 7) != 0) { M13_SET_8(v, a); ++a; } } M13_SET_16(1000, 0xe68a); for (int i = 0; i < g->players; ++i) { const empiretechorbit_t *e = &(g->eto[i]); int srdb; srdb = 0xc410 + 0x468 * i; for (int j = 0; j < SHIP_NAME_NUM; ++j) { strncpy((char *)&(save2buf[srdb + 0x198 + j * 12]), game_str_tbl_ship_names[e->race * SHIP_NAME_NUM + j], 11); } } if (save_out_write(fname) != 0) { return -1; } if (opt_use_configmoo) { char *dir; char *fnam; char savei; util_fname_split(fname, &dir, &fnam); savei = fnam[4] - '0'; fnam[4] = 'x'; if (strcasecmp(fnam, "savex.gam") != 0) { savei = 0; } if (opt_use_configmoo && (savei >= 1) && (savei <= 6)) { bool found = true; uint8_t *cmoobuf = &save2buf[SAVE_MOO13_LEN]; char *fullname = 0; const char *tryname; tryname = "config.moo"; if (dir) { tryname = fullname = util_concat(dir, FSDEV_DIR_SEP_STR, tryname, NULL); } if (try_load_len(tryname, cmoobuf, SAVE_CMOO_LEN) <= 0) { tryname = "CONFIG.MOO"; if (dir) { lib_free(fullname); tryname = fullname = util_concat(dir, FSDEV_DIR_SEP_STR, tryname, NULL); } if (try_load_len(tryname, cmoobuf, SAVE_CMOO_LEN) <= 0) { found = false; } } if (found) { strncpy((char *)&cmoobuf[0x22 + 20 * (savei - 1)], savename, 20); cmoobuf[0x22 + 20 * (savei - 1) + 20 - 1] = '\0'; cmoobuf[0x16 + 2 * (savei - 1)] = 1; /* set have save flag */ LOG_DEBUG((1, "set '%s' slot %i '%s'\n", tryname, savei, savename)); if (util_file_save(tryname, cmoobuf, SAVE_CMOO_LEN)) { log_warning("failed to save '%s'\n", tryname); } } if (fullname) { lib_free(fullname); fullname = 0; } } lib_free(fnam); lib_free(dir); } return 0; } /* -------------------------------------------------------------------------- */ typedef enum { GAME_INTROS_T_VALUE, GAME_INTROS_T_STR, GAME_INTROS_T_BV, GAME_INTROS_T_SUB } game_intros_value_t; struct game_intros_s { const char *str; game_intros_value_t type; int offs; int size; int len; const struct game_intros_s *sub; }; #define GAME_INTROS_OFF(_r_, _s_) (((const uint8_t *)&(((const struct _r_ *)1024)->_s_)) - ((const uint8_t *)1024)) #define GAME_INTROS_VSIZE(_r_, _s_) sizeof((&((struct _r_ *)1024)->_s_)[0]) #define GAME_INTROS_VLEN(_r_, _s_) (sizeof(((struct _r_ *)1024)->_s_) / GAME_INTROS_VSIZE(_r_, _s_)) #define GAME_INTROS_TSIZE(_r_, _s_) sizeof((((struct _r_ *)1024)->_s_)[0]) #define GAME_INTROS_TLEN(_r_, _s_) (sizeof(((struct _r_ *)1024)->_s_) / GAME_INTROS_TSIZE(_r_, _s_)) #define GAME_INTROS_VAL(_r_, _s_) { #_s_, GAME_INTROS_T_VALUE, GAME_INTROS_OFF(_r_, _s_), GAME_INTROS_VSIZE(_r_, _s_), GAME_INTROS_VLEN(_r_, _s_), 0 } #define GAME_INTROS_TBL(_r_, _s_) { #_s_, GAME_INTROS_T_VALUE, GAME_INTROS_OFF(_r_, _s_), GAME_INTROS_TSIZE(_r_, _s_), GAME_INTROS_TLEN(_r_, _s_), 0 } #define GAME_INTROS_LTBL(_r_, _s_) { "", GAME_INTROS_T_VALUE, 0, GAME_INTROS_TSIZE(_r_, _s_), GAME_INTROS_TLEN(_r_, _s_), 0 } #define GAME_INTROS_BV(_r_, _s_, _l_) { #_s_, GAME_INTROS_T_BV, GAME_INTROS_OFF(_r_, _s_), _l_, 1, 0 } #define GAME_INTROS_BVT(_r_, _s_, _l_, _n_) { #_s_, GAME_INTROS_T_BV, GAME_INTROS_OFF(_r_, _s_), _l_, _n_, 0 } #define GAME_INTROS_STR(_r_, _s_, _z_, _l_) { #_s_, GAME_INTROS_T_STR, GAME_INTROS_OFF(_r_, _s_), _z_, _l_, 0 } #define GAME_INTROS_SUB(_r_, _s_, _p_) { #_s_, GAME_INTROS_T_SUB, GAME_INTROS_OFF(_r_, _s_), GAME_INTROS_TSIZE(_r_, _s_), GAME_INTROS_TLEN(_r_, _s_), _p_ } #define GAME_INTROS_SUBV(_r_, _s_, _p_) { #_s_, GAME_INTROS_T_SUB, GAME_INTROS_OFF(_r_, _s_), GAME_INTROS_VSIZE(_r_, _s_), GAME_INTROS_VLEN(_r_, _s_), _p_ } #define GAME_INTROS_END { 0, 0, 0, 0, 0, 0 } static const struct game_intros_s game_intros_planet[] = { GAME_INTROS_STR(planet_s, name, PLANET_NAME_LEN, 1), GAME_INTROS_VAL(planet_s, x), GAME_INTROS_VAL(planet_s, y), GAME_INTROS_VAL(planet_s, star_type), GAME_INTROS_VAL(planet_s, look), GAME_INTROS_VAL(planet_s, frame), GAME_INTROS_VAL(planet_s, rocks), GAME_INTROS_VAL(planet_s, max_pop1), GAME_INTROS_VAL(planet_s, max_pop2), GAME_INTROS_VAL(planet_s, max_pop3), GAME_INTROS_VAL(planet_s, type), GAME_INTROS_VAL(planet_s, battlebg), GAME_INTROS_VAL(planet_s, infogfx), GAME_INTROS_VAL(planet_s, growth), GAME_INTROS_VAL(planet_s, special), GAME_INTROS_VAL(planet_s, owner), GAME_INTROS_VAL(planet_s, prev_owner), GAME_INTROS_VAL(planet_s, claim), GAME_INTROS_VAL(planet_s, waste), GAME_INTROS_BV(planet_s, explored, PLAYER_NUM), GAME_INTROS_BV(planet_s, unrefuel, PLAYER_NUM), GAME_INTROS_VAL(planet_s, bc_to_ecoproj), GAME_INTROS_VAL(planet_s, bc_to_ship), GAME_INTROS_VAL(planet_s, bc_to_factory), GAME_INTROS_VAL(planet_s, reserve), GAME_INTROS_VAL(planet_s, pop), GAME_INTROS_VAL(planet_s, pop_prev), GAME_INTROS_VAL(planet_s, factories), GAME_INTROS_TBL(planet_s, slider), GAME_INTROS_TBL(planet_s, slider_lock), GAME_INTROS_VAL(planet_s, buildship), GAME_INTROS_VAL(planet_s, reloc), GAME_INTROS_VAL(planet_s, missile_bases), GAME_INTROS_VAL(planet_s, bc_to_base), GAME_INTROS_VAL(planet_s, bc_upgrade_base), GAME_INTROS_VAL(planet_s, have_stargate), GAME_INTROS_VAL(planet_s, shield), GAME_INTROS_VAL(planet_s, bc_to_shield), GAME_INTROS_VAL(planet_s, trans_num), GAME_INTROS_VAL(planet_s, trans_dest), GAME_INTROS_VAL(planet_s, pop_tenths), GAME_INTROS_VAL(planet_s, pop_oper_fact), GAME_INTROS_VAL(planet_s, bc_to_refit), GAME_INTROS_VAL(planet_s, rebels), GAME_INTROS_VAL(planet_s, unrest), GAME_INTROS_VAL(planet_s, unrest_reported), GAME_INTROS_BV(planet_s, finished, FINISHED_NUM), GAME_INTROS_END }; static const struct game_intros_s game_intros_seen[] = { GAME_INTROS_VAL(seen_s, owner), GAME_INTROS_VAL(seen_s, pop), GAME_INTROS_VAL(seen_s, bases), GAME_INTROS_VAL(seen_s, factories), GAME_INTROS_END }; static const struct game_intros_s game_intros_seen0[] = { { "", GAME_INTROS_T_SUB, 0, sizeof(struct seen_s), PLANETS_MAX, game_intros_seen }, GAME_INTROS_END }; static const struct game_intros_s game_intros_enroute[] = { GAME_INTROS_VAL(fleet_enroute_s, owner), GAME_INTROS_VAL(fleet_enroute_s, x), GAME_INTROS_VAL(fleet_enroute_s, y), GAME_INTROS_VAL(fleet_enroute_s, dest), GAME_INTROS_VAL(fleet_enroute_s, speed), GAME_INTROS_TBL(fleet_enroute_s, ships), GAME_INTROS_END }; static const struct game_intros_s game_intros_transport[] = { GAME_INTROS_VAL(transport_s, owner), GAME_INTROS_VAL(transport_s, x), GAME_INTROS_VAL(transport_s, y), GAME_INTROS_VAL(transport_s, dest), GAME_INTROS_VAL(transport_s, speed), GAME_INTROS_VAL(transport_s, pop), GAME_INTROS_END }; static const struct game_intros_s game_intros_tech[] = { GAME_INTROS_TBL(techdata_s, percent), GAME_INTROS_TBL(techdata_s, slider), GAME_INTROS_TBL(techdata_s, slider_lock), GAME_INTROS_TBL(techdata_s, investment), GAME_INTROS_TBL(techdata_s, project), GAME_INTROS_TBL(techdata_s, cost), GAME_INTROS_TBL(techdata_s, completed), GAME_INTROS_END }; static const struct game_intros_s game_intros_orbit[] = { GAME_INTROS_TBL(fleet_orbit_s, ships), GAME_INTROS_END }; static const struct game_intros_s game_intros_spyreportfield[] = { GAME_INTROS_LTBL(empiretechorbit_s, spyreportfield[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_eto[] = { GAME_INTROS_VAL(empiretechorbit_s, race), GAME_INTROS_VAL(empiretechorbit_s, banner), GAME_INTROS_VAL(empiretechorbit_s, trait1), GAME_INTROS_VAL(empiretechorbit_s, trait2), GAME_INTROS_VAL(empiretechorbit_s, ai_p3_countdown), GAME_INTROS_VAL(empiretechorbit_s, ai_p2_countdown), GAME_INTROS_BV(empiretechorbit_s, contact, PLAYER_NUM), GAME_INTROS_BV(empiretechorbit_s, contact_broken, PLAYER_NUM), GAME_INTROS_TBL(empiretechorbit_s, relation1), GAME_INTROS_TBL(empiretechorbit_s, relation2), GAME_INTROS_TBL(empiretechorbit_s, diplo_type), GAME_INTROS_TBL(empiretechorbit_s, diplo_val), GAME_INTROS_TBL(empiretechorbit_s, diplo_p1), GAME_INTROS_TBL(empiretechorbit_s, diplo_p2), GAME_INTROS_TBL(empiretechorbit_s, trust), GAME_INTROS_TBL(empiretechorbit_s, broken_treaty), GAME_INTROS_TBL(empiretechorbit_s, blunder), GAME_INTROS_TBL(empiretechorbit_s, tribute_field), GAME_INTROS_TBL(empiretechorbit_s, tribute_tech), GAME_INTROS_TBL(empiretechorbit_s, mood_treaty), GAME_INTROS_TBL(empiretechorbit_s, mood_trade), GAME_INTROS_TBL(empiretechorbit_s, mood_tech), GAME_INTROS_TBL(empiretechorbit_s, mood_peace), GAME_INTROS_TBL(empiretechorbit_s, treaty), GAME_INTROS_TBL(empiretechorbit_s, trade_bc), GAME_INTROS_TBL(empiretechorbit_s, trade_percent), GAME_INTROS_TBL(empiretechorbit_s, spymode_next), GAME_INTROS_TBL(empiretechorbit_s, offer_field), GAME_INTROS_TBL(empiretechorbit_s, offer_tech), GAME_INTROS_TBL(empiretechorbit_s, offer_bc), GAME_INTROS_TBL(empiretechorbit_s, attack_bounty), GAME_INTROS_TBL(empiretechorbit_s, bounty_collect), GAME_INTROS_TBL(empiretechorbit_s, attack_gift_field), GAME_INTROS_TBL(empiretechorbit_s, attack_gift_tech), GAME_INTROS_TBL(empiretechorbit_s, attack_gift_bc), GAME_INTROS_TBL(empiretechorbit_s, hatred), GAME_INTROS_TBL(empiretechorbit_s, have_met), GAME_INTROS_TBL(empiretechorbit_s, trade_established_bc), GAME_INTROS_TBL(empiretechorbit_s, spying), GAME_INTROS_TBL(empiretechorbit_s, spyfund), GAME_INTROS_TBL(empiretechorbit_s, spymode), GAME_INTROS_VAL(empiretechorbit_s, security), GAME_INTROS_TBL(empiretechorbit_s, spies), GAME_INTROS_VAL(empiretechorbit_s, reserve_bc), GAME_INTROS_VAL(empiretechorbit_s, tax), GAME_INTROS_VAL(empiretechorbit_s, base_shield), GAME_INTROS_VAL(empiretechorbit_s, base_comp), GAME_INTROS_VAL(empiretechorbit_s, base_weapon), GAME_INTROS_VAL(empiretechorbit_s, colonist_oper_factories), GAME_INTROS_SUBV(empiretechorbit_s, tech, game_intros_tech), GAME_INTROS_VAL(empiretechorbit_s, shipdesigns_num), GAME_INTROS_SUB(empiretechorbit_s, orbit, game_intros_orbit), GAME_INTROS_SUB(empiretechorbit_s, spyreportfield, game_intros_spyreportfield), GAME_INTROS_TBL(empiretechorbit_s, spyreportyear), GAME_INTROS_VAL(empiretechorbit_s, shipi_colony), GAME_INTROS_VAL(empiretechorbit_s, shipi_bomber), GAME_INTROS_END }; static const struct game_intros_s game_intros_design[] = { GAME_INTROS_STR(shipdesign_s, name, SHIP_NAME_LEN, 1), GAME_INTROS_VAL(shipdesign_s, cost), GAME_INTROS_VAL(shipdesign_s, space), GAME_INTROS_VAL(shipdesign_s, hull), GAME_INTROS_VAL(shipdesign_s, look), GAME_INTROS_TBL(shipdesign_s, wpnt), GAME_INTROS_TBL(shipdesign_s, wpnn), GAME_INTROS_VAL(shipdesign_s, engine), GAME_INTROS_VAL(shipdesign_s, engines), GAME_INTROS_TBL(shipdesign_s, special), GAME_INTROS_VAL(shipdesign_s, shield), GAME_INTROS_VAL(shipdesign_s, jammer), GAME_INTROS_VAL(shipdesign_s, comp), GAME_INTROS_VAL(shipdesign_s, armor), GAME_INTROS_VAL(shipdesign_s, man), GAME_INTROS_VAL(shipdesign_s, hp), GAME_INTROS_END }; static const struct game_intros_s game_intros_researchlist[] = { GAME_INTROS_LTBL(shipresearch_s, researchlist[0][0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_researchlist0[] = { { "", GAME_INTROS_T_SUB, 0, GAME_INTROS_TSIZE(shipresearch_s, researchlist[0]), TECH_TIER_NUM, game_intros_researchlist }, GAME_INTROS_END }; static const struct game_intros_s game_intros_researchcompleted[] = { GAME_INTROS_LTBL(shipresearch_s, researchcompleted[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_srd[] = { GAME_INTROS_SUB(shipresearch_s, design, game_intros_design), GAME_INTROS_SUB(shipresearch_s, researchlist, game_intros_researchlist0), GAME_INTROS_SUB(shipresearch_s, researchcompleted, game_intros_researchcompleted), GAME_INTROS_TBL(shipresearch_s, year), GAME_INTROS_END }; static const struct game_intros_s game_intros_monster[] = { GAME_INTROS_VAL(monster_s, exists), GAME_INTROS_VAL(monster_s, x), GAME_INTROS_VAL(monster_s, y), GAME_INTROS_VAL(monster_s, killer), GAME_INTROS_VAL(monster_s, dest), GAME_INTROS_VAL(monster_s, counter), GAME_INTROS_VAL(monster_s, nuked), GAME_INTROS_END }; static const struct game_intros_s game_intros_new_ships[] = { GAME_INTROS_LTBL(gameevents_s, new_ships[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_spies_caught[] = { GAME_INTROS_LTBL(gameevents_s, spies_caught[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_ceasefire[] = { GAME_INTROS_LTBL(gameevents_s, ceasefire[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_help_shown[] = { { "", GAME_INTROS_T_BV, 0, HELP_SHOWN_NUM, 1, 0 }, GAME_INTROS_END }; static const struct game_intros_s game_intros_evn[] = { GAME_INTROS_VAL(gameevents_s, year), GAME_INTROS_BV(gameevents_s, done, GAME_EVENT_TBL_NUM), GAME_INTROS_VAL(gameevents_s, diplo_msg_subtype), GAME_INTROS_VAL(gameevents_s, have_plague), GAME_INTROS_VAL(gameevents_s, plague_player), GAME_INTROS_VAL(gameevents_s, plague_planet_i), GAME_INTROS_VAL(gameevents_s, plague_val), GAME_INTROS_VAL(gameevents_s, have_nova), GAME_INTROS_VAL(gameevents_s, nova_player), GAME_INTROS_VAL(gameevents_s, nova_planet_i), GAME_INTROS_VAL(gameevents_s, nova_years), GAME_INTROS_VAL(gameevents_s, nova_val), GAME_INTROS_VAL(gameevents_s, have_accident), GAME_INTROS_VAL(gameevents_s, accident_planet_i), GAME_INTROS_VAL(gameevents_s, have_comet), GAME_INTROS_VAL(gameevents_s, comet_player), GAME_INTROS_VAL(gameevents_s, comet_planet_i), GAME_INTROS_VAL(gameevents_s, comet_years), GAME_INTROS_VAL(gameevents_s, comet_hp), GAME_INTROS_VAL(gameevents_s, comet_dmg), GAME_INTROS_VAL(gameevents_s, have_pirates), GAME_INTROS_VAL(gameevents_s, pirates_planet_i), GAME_INTROS_VAL(gameevents_s, pirates_hp), GAME_INTROS_SUBV(gameevents_s, crystal, game_intros_monster), GAME_INTROS_SUBV(gameevents_s, amoeba, game_intros_monster), GAME_INTROS_VAL(gameevents_s, planet_orion_i), GAME_INTROS_VAL(gameevents_s, have_guardian), GAME_INTROS_TBL(gameevents_s, home), GAME_INTROS_VAL(gameevents_s, report_stars), GAME_INTROS_SUB(gameevents_s, new_ships, game_intros_new_ships), GAME_INTROS_SUB(gameevents_s, spies_caught, game_intros_spies_caught), GAME_INTROS_SUB(gameevents_s, ceasefire, game_intros_ceasefire), GAME_INTROS_SUB(gameevents_s, help_shown, game_intros_help_shown), GAME_INTROS_TBL(gameevents_s, build_finished_num), GAME_INTROS_TBL(gameevents_s, voted), GAME_INTROS_TBL(gameevents_s, best_ecorestore), GAME_INTROS_TBL(gameevents_s, best_wastereduce), GAME_INTROS_TBL(gameevents_s, best_roboctrl), GAME_INTROS_TBL(gameevents_s, best_terraform), GAME_INTROS_END }; static const struct game_intros_s game_intros_nebula_coord[] = { GAME_INTROS_LTBL(game_s, nebula_x0[0]), GAME_INTROS_END }; static const struct game_intros_s game_intros_root[] = { GAME_INTROS_VAL(game_s, players), GAME_INTROS_BV(game_s, is_ai, PLAYER_NUM), GAME_INTROS_BV(game_s, refuse, PLAYER_NUM), GAME_INTROS_VAL(game_s, ai_id), GAME_INTROS_VAL(game_s, active_player), GAME_INTROS_VAL(game_s, difficulty), GAME_INTROS_VAL(game_s, galaxy_size), GAME_INTROS_VAL(game_s, galaxy_w), GAME_INTROS_VAL(game_s, galaxy_h), GAME_INTROS_VAL(game_s, galaxy_stars), GAME_INTROS_VAL(game_s, galaxy_maxx), GAME_INTROS_VAL(game_s, galaxy_maxy), GAME_INTROS_VAL(game_s, galaxy_seed), GAME_INTROS_VAL(game_s, seed), GAME_INTROS_VAL(game_s, year), GAME_INTROS_VAL(game_s, enroute_num), GAME_INTROS_VAL(game_s, transport_num), GAME_INTROS_VAL(game_s, end), GAME_INTROS_VAL(game_s, winner), GAME_INTROS_VAL(game_s, election_held), GAME_INTROS_VAL(game_s, nebula_num), GAME_INTROS_TBL(game_s, nebula_type), GAME_INTROS_TBL(game_s, nebula_x), GAME_INTROS_TBL(game_s, nebula_y), GAME_INTROS_SUB(game_s, nebula_x0, game_intros_nebula_coord), GAME_INTROS_SUB(game_s, nebula_x1, game_intros_nebula_coord), GAME_INTROS_SUB(game_s, nebula_y0, game_intros_nebula_coord), GAME_INTROS_SUB(game_s, nebula_y1, game_intros_nebula_coord), GAME_INTROS_STR(game_s, emperor_names, EMPEROR_NAME_LEN, PLAYER_NUM), GAME_INTROS_TBL(game_s, planet_focus_i), GAME_INTROS_SUB(game_s, planet, game_intros_planet), GAME_INTROS_SUB(game_s, seen, game_intros_seen0), GAME_INTROS_SUB(game_s, enroute, game_intros_enroute), GAME_INTROS_SUB(game_s, transport, game_intros_transport), GAME_INTROS_SUB(game_s, eto, game_intros_eto), GAME_INTROS_SUB(game_s, srd, game_intros_srd), GAME_INTROS_SUB(game_s, current_design, game_intros_design), GAME_INTROS_SUBV(game_s, evn, game_intros_evn), GAME_INTROS_END }; static char *savetype_de_text_tok(char *p) { char c; while (((c = *p) != '\0') && (c != ',') && (c != ' ')) { ++p; } *p = 0; if (c == '\0') { return p; } while (p[1] == ' ') { ++p; } return p + 1; } static char *savetype_de_text_parse_right(struct game_s *g, const char *fname, char *buf, int lnum, int offs, const struct game_intros_s *gitbl, int braces) { const struct game_intros_s *gi = gitbl; char *p = buf; char c; int offs_base = offs; again: while ((c = *p) == ' ') { ++p; } buf = p; if (c == '\0') { return p; } else if ((c == '/') && (p[1] == '/')) { handle_comment: *p = '\0'; return p; } else if (c == '"') { char *q; if (gi->type != GAME_INTROS_T_STR) { log_error("'%s' type %i does not accept strings (line %i)\n", fname, gi->type, lnum); return 0; } q = ((char *)(((uint8_t *)g) + offs)); ++p; for (int i = 0; (i < (gi->size - 1)) && (*p != '"'); ++i) { *q++ = *p++; } *q++ = '\0'; if (*p != '"') { log_error("'%s' too long string on line %i\n", fname, lnum); return 0; } return ++p; } else if (c == '{') { return savetype_de_text_parse_right(g, fname, p + 1, lnum, offs, gi, braces + 1); } else if (c == '}') { handle_brace_close: if (braces) { return p + 1; } else { log_error("'%s' unexpected } on line %i\n", fname, lnum); return 0; } } else if (c == '.') { handle_dot: /* if (gi->type != GAME_INTROS_T_SUB) { log_error("'%s' type %i does not accept .vars (line %i)\n", fname, gi->type, lnum); return 0; } */ buf = ++p; while ((((c = *p) >= 'a') && (c <= 'z')) || (c == '_') || ((c >= '0') && (c <= '9'))) { ++p; } c = *p; *p++ = 0; for (gi = gitbl; gi->str != NULL; ++gi) { if (strcmp(gi->str, buf) == 0) { break; } } if (gi->str == NULL) { log_error("'%s' could not find token '%s' on line %i\n", fname, buf, lnum); return 0; } offs = offs_base + gi->offs; if (c == '[') { if (((c = *p++) != ']') || (*p++ != ' ')) { log_error("'%s' invalid '[] ' on line %i\n", fname, lnum); return 0; } } if (((c = *p++) != '=') || ((c = *p++) != ' ')) { log_error("'%s' invalid = on line %i\n", fname, lnum); return 0; } buf = p; goto again; } else if (((c >= '0') && (c <= '9')) || (c == '-')) { if ((c == '0') && (p[1] == 'b')) { int n = 0; if (gi->type != GAME_INTROS_T_BV) { log_error("'%s' type %i does not accept bool vectors (line %i)\n", fname, gi->type, lnum); return 0; } p += 2; buf = p; while ((p[0] == '0') || (p[0] == '1')) { ++n; ++p; } if ((p[0] == '\0') || (p[0] == ' ')) { p[0] = '\0'; } else { log_error("'%s' unexpected char 0x%02x on line %i\n", fname, p[0], lnum); return 0; } if (n > gi->size) { log_error("'%s' bool vector size %i > max %i\n", fname, n, gi->size); return 0; } else { uint8_t *bv = ((uint8_t *)(((uint8_t *)g) + offs)); buf = p; --p; for (int i = 0; i < n; ++i) { if (*p-- == '1') { BOOLVEC_SET1(bv, i); } } return buf; } } else { int n; n = 0; if (gi->type != GAME_INTROS_T_VALUE) { log_error("'%s' type %i does not accept numbers (line %i)\n", fname, gi->type, lnum); return 0; } do { uint32_t v; if ((*p == '/') && (p[1] == '/')) { goto handle_comment; } if (*p == '}') { goto handle_brace_close; } if (*p == '.') { goto handle_dot; } p = savetype_de_text_tok(p); if (!util_parse_number(buf, &v)) { log_error("'%s' invalid number on line %i\n", fname, lnum); return 0; } if (n >= gi->len) { log_error("'%s' too many values (%i) on line %i for '%s'\n", fname, n, lnum, gi->str); return 0; } switch (gi->size) { case 1: *((uint8_t *)(((uint8_t *)g) + offs)) = v; break; case 2: *((uint16_t *)(((uint8_t *)g) + offs)) = v; break; case 4: *((uint32_t *)(((uint8_t *)g) + offs)) = v; break; case 8: *((uint64_t *)(((uint8_t *)g) + offs)) = v; break; default: log_error("'%s' invalid var size %i on line %i\n", fname, gi->size, lnum); return 0; } offs += gi->size; ++n; buf = p; } while (*p != 0); } } else { log_error("'%s' unexpected char 0x%02x on line %i\n", fname, c, lnum); return 0; } return p; } static int savetype_de_text_parse_line(struct game_s *g, const char *fname, char *buf, int lnum) { int offs = -1; char *p = buf; const struct game_intros_s *gitbl = game_intros_root; while (1) { const struct game_intros_s *gi; char c, cend; bool have_sub; have_sub = false; p = buf; while ((((c = *p) >= 'a') && (c <= 'z')) || (c == '_') || ((c >= '0') && (c <= '9'))) { ++p; } cend = c; *p++ = 0; if (c == '\0') { log_error("'%s' unexpected 0 on line %i\n", fname, lnum); return -1; } gi = NULL; if ((buf[0] >= 'a') && (buf[0] <= 'z')) { for (gi = gitbl; gi->str != NULL; ++gi) { if (strcmp(gi->str, buf) == 0) { break; } } if (gi->str == NULL) { log_error("'%s' could not find token '%s' on line %i\n", fname, buf, lnum); return -1; } if (offs < 0) { offs = gi->offs; } else { offs += gi->offs; } } while (c == '[') { uint32_t v; char *numstr; numstr = p; while (((c = *p) >= '0') && (c <= '9')) { ++p; } if (c != ']') { log_error("'%s' missing ']' on line %i\n", fname, lnum); return -1; } *p++ = 0; c = *p++; if (*numstr == 0) { break; } else { if (!util_parse_number(numstr, &v)) { log_error("'%s' parsing index on line %i\n", fname, lnum); return -1; } if ((offs < 0) || (gi == NULL)) { log_error("'%s' indexing without variable on line %i\n", fname, lnum); return -1; } if (v >= gi->len) { log_error("'%s' index %i >= len %i on line %i\n", fname, v, gi->len, lnum); return -1; } offs += gi->size * v; if (gi->sub) { gitbl = gi = gi->sub; have_sub = true; } } } if (c == '.') { if (gi == NULL) { log_error("'%s' . without name on line %i\n", fname, lnum); return -1; } if ((!have_sub) && gi->sub) { gitbl = gi->sub; have_sub = true; } if (!have_sub) { log_error("'%s' . without name on line %i\n", fname, lnum); return -1; } buf = p; continue; } if (c == ' ') { if (offs < 0) { log_error("'%s' variable name missing on line %i\n", fname, lnum); return -1; } if (((c = *p++) != '=') || ((c = *p++) != ' ')) { log_error("'%s' invalid = on line %i\n", fname, lnum); return -1; } p = savetype_de_text_parse_right(g, fname, p, lnum, offs, gi, 0); return (p != NULL) ? 0 : -1; } else { log_error("'%s' unexpected char 0x%02x on line %i\n", fname, cend, lnum); return -1; } } return 0; } static bool savetype_is_text(struct game_s *g, const char *fname) { FILE *fd = NULL; int len; bool is_text = true; LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); fd = fopen(fname, "r"); if (!fd) { log_error("failed to open file '%s'\n", fname); return false; } while ((len = util_get_line((char *)save2buf, 1024, fd)) >= 0) { if ((len == 0) || ((save2buf[0] == '/') && (save2buf[1] == '/'))) { continue; } if (memcmp(save2buf, "savename = \"", 12) == 0) { continue; } else if ((memcmp(save2buf, "g->", 3) != 0) || (len > 1020)) { is_text = false; break; } } if (fd) { fclose(fd); } return is_text; } static int savetype_de_text(struct game_s *g, const char *fname) { FILE *fd = NULL; int len, lnum = 0; LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); fd = fopen(fname, "r"); if (!fd) { log_error("failed to open file '%s'\n", fname); return -1; } { void *t = g->gaux; memset(g, 0, sizeof(*g)); g->gaux = t; } while ((len = util_get_line((char *)save2buf, 1024, fd)) >= 0) { ++lnum; if ((len == 0) || ((save2buf[0] == '/') && (save2buf[1] == '/'))) { continue; } if (memcmp(save2buf, "savename = \"", 12) == 0) { if (savename[0] == 0) { char *p = savename; const char *q = (const char *)&save2buf[12]; for (int i = 0; (i < (SAVE_NAME_LEN)) && (*q != '"'); ++i) { *p++ = *q++; } *p++ = 0; } continue; } else if ((memcmp(save2buf, "g->", 3) != 0) || (len > 1020)) { log_error("invalid line %i in '%s'\n", lnum, fname); goto fail; } if (savetype_de_text_parse_line(g, fname, (char *)&save2buf[3], lnum) < 0) { goto fail; } } if (fd) { fclose(fd); } return 0; fail: if (fd) { fclose(fd); } return -1; } #define OUTADD save2len += lib_sprintf((char *)&save2buf[save2len], SAVE2BUF_SIZE - save2len, #define OUTPRE() OUTADD "%s", tp->buf) #define OUTLINE OUTPRE(); OUTADD #define OUTLINEI(_name_, _var_) OUTPRE(); OUTADD "%s = %i\n", _name_, _var_) #define OUTLINEX(_name_, _var_) OUTPRE(); OUTADD "%s = 0x%x\n", _name_, _var_) #define OUTLINES(_name_, _var_) OUTPRE(); OUTADD "%s = \"%s\"\n", _name_, _var_) #define OUTLINEBV(_name_, _var_, _num_) OUTPRE(); OUTADD "%s = %s\n", _name_, savetype_en_bv(_var_, _num_)) #define OUTTBL(_name_, _num_, _var_) \ do { \ OUTADD "%s[] = { ", _name_); \ for (int i_ = 0; i_ < _num_; ++i_) { \ OUTADD "%i", _var_[i_]); \ if (i_ != (_num_ - 1)) { OUTADD ", "); } \ } \ OUTADD " }"); \ } while (0) #define OUTLINETBL(_name_, _num_, _var_) OUTPRE(); OUTTBL(_name_, _num_, _var_); OUTADD "\n") #define OUTLINETBLNON0(_name_, _num_, _var_) \ do { \ for (int j_ = 0; j_ < _num_; ++j_) { \ if (_var_[j_]) { OUTLINETBL(_name_, _num_, _var_); break; } \ } \ } while (0) #define OUTFLUSH() do { if (save_out_flush()) { return -1; } } while (0) struct text_dump_prefix_s { char buf[128]; int pos[10]; int num; }; static void text_dump_prefix_init(struct text_dump_prefix_s *tp) { tp->num = 0; tp->pos[0] = 0; tp->buf[0] = 0; } static void text_dump_prefix_add(struct text_dump_prefix_s *tp, const char *str, const char *sep) { int num, pos; num = tp->num++; if (num >= 10) { log_fatal_and_die("test_dump_prefix_add: too many entries."); } pos = tp->pos[num]; pos += lib_sprintf(&(tp->buf[pos]), 128 - pos, "%s%s", str, sep); if (num <= 8) { tp->pos[num + 1] = pos; } } static void text_dump_prefix_add_tbl(struct text_dump_prefix_s *tp, const char *str, const char *sep, int index) { char buf[128]; lib_sprintf(buf, sizeof(buf), "%s[%i]", str, index); text_dump_prefix_add(tp, buf, sep); } static void text_dump_prefix_del(struct text_dump_prefix_s *tp) { int pos; pos = tp->pos[--tp->num]; tp->buf[pos] = 0; } static const char *savetype_en_bv(const BOOLVEC_PTRPARAMI(bv), int len) { static char buf[128]; /* HACK */ char *p = &(buf[127]); *p-- = 0; for (int i = 0; i < len; ++i) { char c; c = BOOLVEC_IS1(bv, i) ? '1' : '0'; *p-- = c; } *p-- = 'b'; *p = '0'; return p; } static void savetype_en_text_sd(const shipdesign_t *sd, struct text_dump_prefix_s *tp) { OUTLINES("name", sd->name); OUTLINEI("cost", sd->cost); OUTLINEI("space", sd->space); OUTLINEI("hull", sd->hull); OUTLINEI("look", sd->look); OUTLINETBL("wpnt", WEAPON_SLOT_NUM, sd->wpnt); OUTLINETBL("wpnn", WEAPON_SLOT_NUM, sd->wpnn); OUTLINEI("engine", sd->engine); OUTLINEI("engines", sd->engines); OUTLINETBL("special", SPECIAL_SLOT_NUM, sd->special); OUTLINEI("shield", sd->shield); OUTLINEI("jammer", sd->jammer); OUTLINEI("comp", sd->comp); OUTLINEI("armor", sd->armor); OUTLINEI("man", sd->man); OUTLINEI("hp", sd->hp); } static void savetype_en_text_monster(const monster_t *m, struct text_dump_prefix_s *tp) { OUTLINEI("exists", m->exists); OUTLINEI("x", m->x); OUTLINEI("y", m->y); OUTLINEI("killer", m->killer); OUTLINEI("dest", m->dest); OUTLINEI("counter", m->counter); OUTLINEI("nuked", m->nuked); } static int savetype_en_text(struct game_s *g, const char *fname) { struct text_dump_prefix_s tp[1]; LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); save2len = 0; if (save_out_open(fname)) { return -1; } text_dump_prefix_init(tp); OUTLINES("savename", savename); text_dump_prefix_add(tp, "g", "->"); OUTLINEI("players", g->players); OUTLINEBV("is_ai", g->is_ai, g->players); OUTLINEBV("refuse", g->refuse, g->players); OUTLINEI("ai_id", g->ai_id); OUTLINEI("active_player", g->active_player); OUTLINEI("difficulty", g->difficulty); OUTLINEI( "galaxy_size", g->galaxy_size); OUTLINEI("galaxy_w", g->galaxy_w); OUTLINEI("galaxy_h", g->galaxy_h); OUTLINEI("galaxy_stars", g->galaxy_stars); OUTLINEI("galaxy_maxx", g->galaxy_maxx); OUTLINEI("galaxy_maxy", g->galaxy_maxy); OUTLINEX("galaxy_seed", g->galaxy_seed); OUTLINEX("seed", g->seed); OUTLINEI("year", g->year); OUTLINEI("enroute_num", g->enroute_num); OUTLINEI("transport_num", g->transport_num); OUTLINEI("end", g->end); OUTLINEI("winner", g->winner); OUTLINEI("election_held", g->election_held); OUTFLUSH(); OUTLINEI("nebula_num", g->nebula_num); if (g->nebula_num) { OUTLINETBL("nebula_type", g->nebula_num, g->nebula_type); OUTLINETBL("nebula_x", g->nebula_num, g->nebula_x); OUTLINETBL("nebula_y", g->nebula_num, g->nebula_y); for (int i = 0; i < g->nebula_num; ++i) { text_dump_prefix_add_tbl(tp, "nebula_x0", "", i); OUTLINETBL("", 4, g->nebula_x0[i]); text_dump_prefix_del(tp); text_dump_prefix_add_tbl(tp, "nebula_x1", "", i); OUTLINETBL("", 4, g->nebula_x1[i]); text_dump_prefix_del(tp); text_dump_prefix_add_tbl(tp, "nebula_y0", "", i); OUTLINETBL("", 4, g->nebula_y0[i]); text_dump_prefix_del(tp); text_dump_prefix_add_tbl(tp, "nebula_y1", "", i); OUTLINETBL("", 4, g->nebula_y1[i]); text_dump_prefix_del(tp); } } for (int i = 0; i < g->players; ++i) { OUTLINE "emperor_names[%i] = \"%s\"\n", i, g->emperor_names[i]); } OUTLINETBL("planet_focus_i", g->players, g->planet_focus_i); OUTFLUSH(); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); text_dump_prefix_add_tbl(tp, "planet", ".", i); OUTLINES("name", p->name); OUTLINEI("x", p->x); OUTLINEI("y", p->y); OUTLINEI("star_type", p->star_type); OUTLINEI("look", p->look); OUTLINEI("frame", p->frame); OUTLINEI("rocks", p->rocks); OUTLINEI("max_pop1", p->max_pop1); OUTLINEI("max_pop2", p->max_pop2); OUTLINEI("max_pop3", p->max_pop3); OUTLINEI("type", p->type); OUTLINEI("battlebg", p->battlebg); OUTLINEI("infogfx", p->infogfx); OUTLINEI("growth", p->growth); OUTLINEI("special", p->special); OUTLINEI("owner", p->owner); OUTLINEI("prev_owner", p->prev_owner); OUTLINEI("claim", p->claim); OUTLINEI("waste", p->waste); OUTLINEBV("explored", p->explored, g->players); OUTLINEBV("unrefuel", p->unrefuel, g->players); OUTLINEI("bc_to_ecoproj", p->bc_to_ecoproj); OUTLINEI("bc_to_ship", p->bc_to_ship); OUTLINEI("bc_to_factory", p->bc_to_factory); OUTLINEI("reserve", p->reserve); OUTLINEI("pop", p->pop); OUTLINEI("pop_prev", p->pop_prev); OUTLINEI("factories", p->factories); OUTLINETBL("slider", PLANET_SLIDER_NUM, p->slider); OUTLINETBL("slider_lock", PLANET_SLIDER_NUM, p->slider_lock); OUTLINEI("buildship", p->buildship); OUTLINEI("reloc", p->reloc); OUTLINEI("missile_bases", p->missile_bases); OUTLINEI("bc_to_base", p->bc_to_base); OUTLINEI("bc_upgrade_base", p->bc_upgrade_base); OUTLINEI("have_stargate", p->have_stargate); OUTLINEI("shield", p->shield); OUTLINEI("bc_to_shield", p->bc_to_shield); OUTLINEI("trans_num", p->trans_num); OUTLINEI("trans_dest", p->trans_dest); OUTLINEI("pop_tenths", p->pop_tenths); OUTLINEI("pop_oper_fact", p->pop_oper_fact); OUTLINEI("bc_to_refit", p->bc_to_refit); OUTLINEI("rebels", p->rebels); OUTLINEI("unrest", p->unrest); OUTLINEI("unrest_reported", p->unrest_reported); OUTLINEBV("finished", p->finished, FINISHED_NUM); text_dump_prefix_del(tp); OUTFLUSH(); } for (int j = 0; j < g->players; ++j) { for (int i = 0; i < g->galaxy_stars; ++i) { const seen_t *s = &(g->seen[j][i]); OUTLINE "seen[%i][%i] = { .owner = %i, .pop = %i, .bases = %i, .factories = %i }\n", j, i, s->owner, s->pop, s->bases, s->factories); } OUTFLUSH(); } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); OUTLINE "enroute"); OUTADD "[%i] = { .owner = %i, .x = %i, .y = %i, .dest = %i, .speed = %i, ", i, r->owner, r->x, r->y, r->dest, r->speed); OUTADD ".ships[] = { %i, %i, %i, %i, %i, %i } }\n", r->ships[0], r->ships[1], r->ships[2], r->ships[3], r->ships[4], r->ships[5]); } OUTFLUSH(); for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); OUTLINE "transport"); OUTADD "[%i] = { .owner = %i, .x = %i, .y = %i, .dest = %i, .speed = %i, ", i, r->owner, r->x, r->y, r->dest, r->speed); OUTADD ".pop = %i }\n", r->pop); } OUTFLUSH(); for (int pl = 0; pl < g->players; ++pl) { const empiretechorbit_t *e = &(g->eto[pl]); text_dump_prefix_add_tbl(tp, "eto", ".", pl); OUTLINEI("race", e->race); OUTLINEI("banner", e->banner); OUTLINEI("trait1", e->trait1); OUTLINEI("trait2", e->trait2); OUTLINEI("ai_p3_countdown", e->ai_p3_countdown); OUTLINEI("ai_p2_countdown", e->ai_p2_countdown); OUTLINEBV("contact", e->contact, g->players); OUTLINEBV("contact_broken", e->contact_broken, g->players); OUTLINETBL("relation1", g->players, e->relation1); OUTLINETBL("relation2", g->players, e->relation2); OUTLINETBL("diplo_type", g->players, e->diplo_type); OUTLINETBL("diplo_val", g->players, e->diplo_val); OUTLINETBL("diplo_p1", g->players, e->diplo_p1); OUTLINETBL("diplo_p2", g->players, e->diplo_p2); OUTLINETBL("trust", g->players, e->trust); OUTLINETBL("broken_treaty", g->players, e->broken_treaty); OUTLINETBL("blunder", g->players, e->blunder); OUTLINETBL("tribute_field", g->players, e->tribute_field); OUTLINETBL("tribute_tech", g->players, e->tribute_tech); OUTLINETBL("mood_treaty", g->players, e->mood_treaty); OUTLINETBL("mood_trade", g->players, e->mood_trade); OUTLINETBL("mood_tech", g->players, e->mood_tech); OUTLINETBL("mood_peace", g->players, e->mood_peace); OUTLINETBL("treaty", g->players, e->treaty); OUTLINETBL("trade_bc", g->players, e->trade_bc); OUTLINETBL("trade_percent", g->players, e->trade_percent); OUTLINETBL("spymode_next", g->players, e->spymode_next); OUTLINETBL("offer_field", g->players, e->offer_field); OUTLINETBL("offer_tech", g->players, e->offer_tech); OUTLINETBL("offer_bc", g->players, e->offer_bc); OUTLINETBL("attack_bounty", g->players, e->attack_bounty); OUTLINETBL("bounty_collect", g->players, e->bounty_collect); OUTLINETBL("attack_gift_field", g->players, e->attack_gift_field); OUTLINETBL("attack_gift_tech", g->players, e->attack_gift_tech); OUTLINETBL("attack_gift_bc", g->players, e->attack_gift_bc); OUTLINETBL("hatred", g->players, e->hatred); OUTLINETBL("have_met", g->players, e->have_met); OUTLINETBL("trade_established_bc", g->players, e->trade_established_bc); OUTLINETBL("spying", g->players, e->spying); OUTLINETBL("spyfund", g->players, e->spyfund); OUTLINETBL("spymode", g->players, e->spymode); OUTLINEI("security", e->security); OUTLINETBL("spies", g->players, e->spies); OUTLINEI("reserve_bc", e->reserve_bc); OUTLINEI("tax", e->tax); OUTLINEI("base_shield", e->base_shield); OUTLINEI("base_comp", e->base_comp); OUTLINEI("base_weapon", e->base_weapon); OUTLINEI("colonist_oper_factories", e->colonist_oper_factories); OUTLINETBL("tech.percent", TECH_FIELD_NUM, e->tech.percent); OUTLINETBL("tech.slider", TECH_FIELD_NUM, e->tech.slider); OUTLINETBL("tech.slider_lock", TECH_FIELD_NUM, e->tech.slider_lock); OUTLINETBL("tech.investment", TECH_FIELD_NUM, e->tech.investment); OUTLINETBL("tech.project", TECH_FIELD_NUM, e->tech.project); OUTLINETBL("tech.cost", TECH_FIELD_NUM, e->tech.cost); OUTLINETBL("tech.completed", TECH_FIELD_NUM, e->tech.completed); OUTLINEI("shipdesigns_num", e->shipdesigns_num); OUTFLUSH(); for (int i = 0; i < g->galaxy_stars; ++i) { text_dump_prefix_add_tbl(tp, "orbit", ".", i); OUTLINETBLNON0("ships", e->shipdesigns_num, e->orbit[i].ships); text_dump_prefix_del(tp); } OUTFLUSH(); for (int i = 0; i < g->players; ++i) { if (i != pl) { text_dump_prefix_add_tbl(tp, "spyreportfield", "", i); OUTLINETBL("", TECH_FIELD_NUM, e->spyreportfield[i]); text_dump_prefix_del(tp); } } OUTLINETBL("spyreportyear", g->players, e->spyreportyear); OUTLINEI("shipi_colony", e->shipi_colony); OUTLINEI("shipi_bomber", e->shipi_bomber); text_dump_prefix_del(tp); OUTFLUSH(); } for (int pl = 0; pl < g->players; ++pl) { const shipresearch_t *srd = &(g->srd[pl]); const empiretechorbit_t *e = &(g->eto[pl]); text_dump_prefix_add_tbl(tp, "srd", ".", pl); for (int i = 0; i < g->eto[pl].shipdesigns_num; ++i) { text_dump_prefix_add_tbl(tp, "design", ".", i); savetype_en_text_sd(&(srd->design[i]), tp); text_dump_prefix_del(tp); } OUTFLUSH(); for (int f = 0; f < TECH_FIELD_NUM; ++f) { text_dump_prefix_add_tbl(tp, "researchlist", "", f); for (int t = 0; t < TECH_TIER_NUM; ++t) { text_dump_prefix_add_tbl(tp, "", "", t); OUTLINETBL("", 3, srd->researchlist[f][t]); text_dump_prefix_del(tp); } text_dump_prefix_del(tp); OUTFLUSH(); } for (int f = 0; f < TECH_FIELD_NUM; ++f) { text_dump_prefix_add_tbl(tp, "researchcompleted", "", f); OUTLINETBL("", e->tech.completed[f], srd->researchcompleted[f]); text_dump_prefix_del(tp); } OUTFLUSH(); OUTLINETBL("year", e->shipdesigns_num, srd->year); text_dump_prefix_del(tp); } OUTFLUSH(); for (int pl = 0; pl < g->players; ++pl) { if (IS_HUMAN(g, pl)) { text_dump_prefix_add_tbl(tp, "current_design", ".", pl); savetype_en_text_sd(&(g->current_design[pl]), tp); text_dump_prefix_del(tp); } } OUTFLUSH(); { const gameevents_t *ev = &(g->evn); text_dump_prefix_add(tp, "evn", "."); OUTLINEI("year", ev->year); OUTLINEBV("done", ev->done, GAME_EVENT_TBL_NUM); OUTLINEI("diplo_msg_subtype", ev->diplo_msg_subtype); OUTLINEI("have_plague", ev->have_plague); OUTLINEI("plague_player", ev->plague_player); OUTLINEI("plague_planet_i", ev->plague_planet_i); OUTLINEI("plague_val", ev->plague_val); OUTLINEI("have_nova", ev->have_nova); OUTLINEI("nova_player", ev->nova_player); OUTLINEI("nova_planet_i", ev->nova_planet_i); OUTLINEI("nova_years", ev->nova_years); OUTLINEI("nova_val", ev->nova_val); OUTLINEI("have_accident", ev->have_accident); OUTLINEI("accident_planet_i", ev->accident_planet_i); OUTLINEI("have_comet", ev->have_comet); OUTLINEI("comet_player", ev->comet_player); OUTLINEI("comet_planet_i", ev->comet_planet_i); OUTLINEI("comet_years", ev->comet_years); OUTLINEI("comet_hp", ev->comet_hp); OUTLINEI("comet_dmg", ev->comet_dmg); OUTLINEI("have_pirates", ev->have_pirates); OUTLINEI("pirates_planet_i", ev->pirates_planet_i); OUTLINEI("pirates_hp", ev->pirates_hp); text_dump_prefix_add(tp, "crystal", "."); savetype_en_text_monster(&(ev->crystal), tp); text_dump_prefix_del(tp); text_dump_prefix_add(tp, "amoeba", "."); savetype_en_text_monster(&(ev->amoeba), tp); text_dump_prefix_del(tp); OUTLINEI("planet_orion_i", ev->planet_orion_i); OUTLINEI("have_guardian", ev->have_guardian); OUTLINETBL("home", g->players, ev->home); OUTLINEI("report_stars", ev->report_stars); OUTFLUSH(); for (int pl = 0; pl < g->players; ++pl) { text_dump_prefix_add_tbl(tp, "new_ships", "", pl); OUTLINETBL("", NUM_SHIPDESIGNS, ev->new_ships[pl]); text_dump_prefix_del(tp); } for (int pl = 0; pl < g->players; ++pl) { text_dump_prefix_add_tbl(tp, "spies_caught", "", pl); OUTLINETBL("", g->players, ev->spies_caught[pl]); text_dump_prefix_del(tp); } for (int pl = 0; pl < g->players; ++pl) { text_dump_prefix_add_tbl(tp, "ceasefire", "", pl); OUTLINETBL("", g->players, ev->ceasefire[pl]); text_dump_prefix_del(tp); } for (int pl = 0; pl < g->players; ++pl) { if (IS_HUMAN(g, pl)) { text_dump_prefix_add_tbl(tp, "help_shown", "", pl); OUTLINEBV("", ev->help_shown[pl], HELP_SHOWN_NUM); text_dump_prefix_del(tp); } } OUTLINETBL("build_finished_num", g->players, ev->build_finished_num); OUTLINETBL("voted", g->players, ev->voted); OUTLINETBL("best_ecorestore", g->players, ev->best_ecorestore); OUTLINETBL("best_wastereduce", g->players, ev->best_wastereduce); OUTLINETBL("best_roboctrl", g->players, ev->best_roboctrl); OUTLINETBL("best_terraform", g->players, ev->best_terraform); text_dump_prefix_del(tp); } OUTFLUSH(); text_dump_prefix_del(tp); return save_out_close(); } #undef OUTTBL #undef OUTLINETBL #undef OUTLINETBLNON0 #undef OUTPRE #undef OUTADD #undef OUTLINE /* -------------------------------------------------------------------------- */ static int savetype_de_1oom0(struct game_s *g, const char *fname) { char *sname = (*savename == '\0') ? savename : NULL; LOG_DEBUG((2, "%s: '%s'\n", __func__, fname)); return game_save_do_load_fname(fname, sname, g); } static int savetype_en_1oom0(struct game_s *g, const char *fname) { LOG_DEBUG((2, "%s: '%s'\n", __func__, fname ? fname : "(null)")); return game_save_do_save_fname(fname, savename, g, 0); } /* -------------------------------------------------------------------------- */ static void savegame_usage(void) { log_message_direct("Usage:\n 1oom_saveconv [OPTIONS] INPUT [OUTPUT]\n"); } void (*main_usage)(void) = savegame_usage; int main_handle_option(const char *argv) { if (main_fname_num < 2) { fnames[main_fname_num++] = argv; return 0; } else { log_error("too many parameters!\n"); return -1; } } static int saveconv_opt_typeo(char **argv, void *var) { int i = 0; while (savetype_match[i].str) { if (strcmp(savetype_match[i].str, argv[1]) == 0) { savetypeo = savetype_match[i].type; LOG_DEBUG((1, "%s: set output type to '%s' -> '%s'\n", __func__, argv[1], savetype[savetypeo].name)); return 0; } ++i; } log_error("unknown type '%s'\n", argv[1]); return -1; } static int saveconv_opt_typei(char **argv, void *var) { int i = 0; while (savetype_match[i].str) { if (strcmp(savetype_match[i].str, argv[1]) == 0) { if (savetype[savetypei].decode) { savetypei = savetype_match[i].type; LOG_DEBUG((1, "%s: set input type to '%s' -> '%s'\n", __func__, argv[1], savetype[savetypei].name)); return 0; } else { log_error("unknown type '%s' is not a valid input type\n", savetype[savetypei].name); return -1; } } ++i; } log_error("unknown type '%s'\n", argv[1]); return -1; } static int saveconv_opt_cmoo_en(char **argv, void *var) { opt_use_configmoo = true; LOG_DEBUG((1, "%s\n", __func__)); return 0; } static int saveconv_opt_sname(char **argv, void *var) { strncpy(savename, argv[1], SAVE_NAME_LEN); savename[SAVE_NAME_LEN - 1] = '\0'; LOG_DEBUG((1, "%s: set save name '%s'\n", __func__, savename)); return 0; } const struct cmdline_options_s main_cmdline_options_early[] = { { "-i", 1, saveconv_opt_typei, 0, "INTYPE", "Input type:\n" " s - smart: autodetect (default)\n" " m - MOO1 v1.3\n" " 1 - 1oom save version 0\n" " t - text" }, { "-o", 1, saveconv_opt_typeo, 0, "OUTTYPE", "Output type:\n" " s - smart: in old/new -> out new/old (default)\n" " m - MOO1 v1.3\n" " 1 - 1oom save version 0\n" " t - text\n" " d - dummy (no output)" }, { "-cmoo", 0, saveconv_opt_cmoo_en, 0, NULL, "Enable CONFIG.MOO use" }, { "-n", 1, saveconv_opt_sname, 0, "NAME", "Set save name" }, { 0, 0, 0, 0, 0, 0 } }; const struct cmdline_options_s main_cmdline_options[] = { { 0, 0, 0, 0, 0, 0 } }; struct pbx_add_cbs; /* Dummy functions that are needed because some of the headers slip in pbx.h. */ int pbx_add_file(const char *filename, struct pbx_add_cbs *cbs) { return -1; } int pbx_queue_file(const char *filename) { return -1; } int pbx_apply_queued_files(void) { return -1; } /* -------------------------------------------------------------------------- */ static int main_early_init(void) { struct game_s *g; struct game_aux_s *gaux; if (os_early_init()) { return 1; } gameptr = g = lib_malloc(sizeof(struct game_s)); g->gaux = gaux = lib_malloc(sizeof(struct game_aux_s)); gaux->savenamebuflen = FSDEV_PATH_MAX; gaux->savenamebuf = lib_malloc(gaux->savenamebuflen); gaux->savebuflen = sizeof(struct game_s) + 64; gaux->savebuf = lib_malloc(gaux->savebuflen); save2buf = lib_malloc(SAVE2BUF_SIZE); return 0; } static int main_init(void) { if (os_init()) { return 1; } return 0; } static void main_shutdown(void) { lib_free(gameptr->gaux->savenamebuf); lib_free(gameptr->gaux->savebuf); lib_free(gameptr->gaux); lib_free(gameptr); lib_free(save2buf); os_shutdown(); } int main_do(void) { int res; uint32_t v; const char *fname; if (main_fname_num == 0) { options_show_usage(); return 0; } fname = fnames[0]; if (util_parse_number(fname, &v)) { if ((v >= 1) && (v <= NUM_ALL_SAVES)) { game_save_get_slot_fname(gameptr->gaux->savenamebuf, gameptr->gaux->savenamebuflen, v - 1); fname = gameptr->gaux->savenamebuf; } else if ((v >= 2300) && (v <= 9999)) { game_save_get_year_fname(gameptr->gaux->savenamebuf, gameptr->gaux->savenamebuflen, v); fname = gameptr->gaux->savenamebuf; } } res = savetype[savetypei].decode(gameptr, fname); if (res < 0) { log_error("decoding file '%s' failed\n", fname); return 1; } log_message("saveconv: decode type '%s' file '%s'\n", savetype[savetypei].name, fname); if (!savetype[savetypeo].encode) { LOG_DEBUG((1, "%s: encode type '%s' no callback\n", __func__, savetype[savetypeo].name)); if (main_fname_num == 2) { log_error("output filename given for type '%s' which has no output\n", savetype[savetypeo].name); return 1; } return 0; } fname = fnames[1]; if (fname == 0) { if (!(savetype[savetypeo].flags & SAVETYPE_F_OPTOUT)) { log_error("output filename missing\n"); return 1; } } else if (util_parse_number(fname, &v)) { if ((v >= 1) && (v <= NUM_ALL_SAVES)) { game_save_get_slot_fname(gameptr->gaux->savenamebuf, gameptr->gaux->savenamebuflen, v - 1); fname = gameptr->gaux->savenamebuf; } else if ((v >= 2300) && (v <= 9999)) { game_save_get_year_fname(gameptr->gaux->savenamebuf, gameptr->gaux->savenamebuflen, v); fname = gameptr->gaux->savenamebuf; } } log_message("saveconv: encode type '%s' file '%s'\n", savetype[savetypeo].name, fname ? fname : "(null)"); if (savename[0] == '\0') { lib_strcpy(savename, "saveconv", SAVE_NAME_LEN); } res = savetype[savetypeo].encode(gameptr, fname); if (res < 0) { log_error("encoding file '%s' failed\n", fname ? fname : "(null)"); return 1; } return 0; } /* -------------------------------------------------------------------------- */ int main_1oom(int argc, char **argv) { if (main_early_init()) { return 1; } if (options_parse_early(argc, argv)) { return 1; } atexit(main_shutdown); if (main_init()) { return 2; } if (options_parse(argc, argv)) { return 3; } return main_do(); } 1oom-1.11.2/src/types.h000066400000000000000000000001721476061725400145670ustar00rootroot00000000000000#ifndef INC_1OOM_TYPES_H #define INC_1OOM_TYPES_H #include #include #include #endif 1oom-1.11.2/src/ui.h000066400000000000000000000176641476061725400140560ustar00rootroot00000000000000#ifndef INC_1OOM_UI_H #define INC_1OOM_UI_H /* API to ui/ */ #include "cfg.h" #include "options.h" #include "types.h" extern const char *idstr_ui; extern void ui_early_show_message_box(const char *msg); extern int ui_early_init(void); extern int ui_init(void); extern int ui_late_init(void); extern void ui_shutdown(void); extern bool ui_use_audio; extern const struct cmdline_options_s ui_cmdline_options[]; extern const struct cfg_items_s ui_cfg_items[]; #define UI_STRBUF_SIZE 1024 extern char *ui_get_strbuf(void); extern void ui_play_intro(void); extern void ui_play_ending_good(int race, const char *name); extern void ui_play_ending_tyrant(int race, const char *name); extern void ui_play_ending_funeral(int banner_live, int banner_dead); extern void ui_play_ending_exile(const char *name); typedef enum { MAIN_MENU_ACT_NEW_GAME, MAIN_MENU_ACT_CUSTOM_GAME, MAIN_MENU_ACT_CHALLENGE_GAME, MAIN_MENU_ACT_LOAD_GAME, MAIN_MENU_ACT_LOAD_GAME_MOO13, MAIN_MENU_ACT_CONTINUE_GAME, MAIN_MENU_ACT_QUIT_GAME, MAIN_MENU_ACT_TUTOR } main_menu_action_t; struct game_new_options_s; extern main_menu_action_t ui_main_menu(struct game_new_options_s *newopts, struct game_new_options_s *customopts, struct game_new_options_s *challengeopts, int *load_game_i_ptr); struct game_s; struct game_end_s; extern void ui_game_start(struct game_s *g); extern void ui_game_end(struct game_s *g); extern void ui_sound_play_sfx(int sfxi); typedef enum { UI_TURN_ACT_NEXT_TURN, UI_TURN_ACT_LOAD_GAME, UI_TURN_ACT_QUIT_GAME } ui_turn_action_t; extern ui_turn_action_t ui_game_turn(struct game_s *g, int *load_game_i_ptr, int pi); extern void *ui_gmap_basic_init(struct game_s *g, bool show_player_switch); extern void ui_gmap_basic_start_player(void *ctx, int pi); extern void ui_gmap_basic_start_frame(void *ctx, int pi); extern void ui_gmap_basic_draw_frame(void *ctx, int pi); extern void ui_gmap_basic_finish_frame(void *ctx, int pi); extern void ui_gmap_basic_shutdown(void *ctx); extern uint8_t *ui_gfx_get_ship(int look); extern uint8_t *ui_gfx_get_planet(int look); extern uint8_t *ui_gfx_get_rock(int look); struct battle_s; #define UI_BATTLE_ACT_CLICK(_x_, _y_) BATTLE_XY_SET((_x_), (_y_)) #define UI_BATTLE_ACT_GET_X(_v_) BATTLE_XY_GET_X(_v_) #define UI_BATTLE_ACT_GET_Y(_v_) BATTLE_XY_GET_Y(_v_) #define UI_BATTLE_ACT_NONE 0x80 #define UI_BATTLE_ACT_WAIT 0x81 #define UI_BATTLE_ACT_DONE 0x82 #define UI_BATTLE_ACT_RETREAT 0x83 #define UI_BATTLE_ACT_AUTO 0x84 #define UI_BATTLE_ACT_MISSILE 0x85 #define UI_BATTLE_ACT_PLANET 0x86 #define UI_BATTLE_ACT_SCAN 0x87 #define UI_BATTLE_ACT_SPECIAL 0x88 typedef uint8_t ui_battle_action_t; typedef enum { UI_BATTLE_AUTORESOLVE_OFF, UI_BATTLE_AUTORESOLVE_AUTO, UI_BATTLE_AUTORESOLVE_RETREAT } ui_battle_autoresolve_t; typedef enum { UI_BATTLE_BOMB_BOMB, UI_BATTLE_BOMB_BIO, UI_BATTLE_BOMB_WARPDIS } ui_battle_bomb_t; extern ui_battle_autoresolve_t ui_battle_init(struct battle_s *bt); extern void ui_battle_shutdown(struct battle_s *bt, bool colony_destroyed, int winner); extern void ui_battle_draw_misshield(const struct battle_s *bt, int target_i, int target_x, int target_y, int missile_i); extern void ui_battle_draw_damage(const struct battle_s *bt, int target_i, int target_x, int target_y, uint32_t damage); extern void ui_battle_draw_explos_small(const struct battle_s *bt, int x, int y); extern void ui_battle_draw_basic(const struct battle_s *bt); extern void ui_battle_draw_basic_copy(const struct battle_s *bt); extern void ui_battle_draw_missile(const struct battle_s *bt, int missilei, int x, int y, int tx, int ty); extern void ui_battle_draw_cloaking(const struct battle_s *bt, int from, int to, int sx, int sy); extern void ui_battle_draw_arena(const struct battle_s *bt, int itemi, int dmode); extern void ui_battle_draw_item(const struct battle_s *bt, int itemi, int x, int y); extern void ui_battle_draw_bomb_attack(const struct battle_s *bt, int attacker_i, int target_i, ui_battle_bomb_t bombtype); extern void ui_battle_draw_beam_attack(const struct battle_s *bt, int attacker_i, int target_i, int wpni); extern void ui_battle_draw_stasis(const struct battle_s *bt, int attacker_i, int target_i); extern void ui_battle_draw_pulsar(const struct battle_s *bt, int attacker_i, int ptype, const uint32_t *dmgtbl); extern void ui_battle_draw_stream1(const struct battle_s *bt, int attacker_i, int target_i); extern void ui_battle_draw_stream2(const struct battle_s *bt, int attacker_i, int target_i); extern void ui_battle_draw_blackhole(const struct battle_s *bt, int attacker_i, int target_i); extern void ui_battle_draw_technull(const struct battle_s *bt, int attacker_i, int target_i); extern void ui_battle_draw_repulse(const struct battle_s *bt, int attacker_i, int target_i, int sx, int sy); extern void ui_battle_draw_retreat(const struct battle_s *bt); extern void ui_battle_draw_bottom(const struct battle_s *bt); extern void ui_battle_draw_planetinfo(const struct battle_s *bt, bool side_r); extern void ui_battle_draw_scan(const struct battle_s *bt, bool side_r); extern void ui_battle_draw_finish(const struct battle_s *bt); extern void ui_battle_area_setup(const struct battle_s *bt); extern void ui_battle_turn_pre(const struct battle_s *bt); extern void ui_battle_turn_post(const struct battle_s *bt); extern ui_battle_action_t ui_battle_turn(const struct battle_s *bt); extern void ui_battle_ai_pre(const struct battle_s *bt); extern bool ui_battle_ai_post(const struct battle_s *bt); extern int ui_spy_steal(struct game_s *g, int spy, int target, uint8_t flags_field); extern void ui_spy_stolen(struct game_s *g, int pi, int spy, int field, uint8_t tech); typedef enum { UI_SABOTAGE_FACT, /*0*/ UI_SABOTAGE_BASES, /*1*/ UI_SABOTAGE_REVOLT, /*2*/ UI_SABOTAGE_NONE /*-1*/ } ui_sabotage_t; extern ui_sabotage_t ui_spy_sabotage_ask(struct game_s *g, int spy, int target, uint8_t *planetptr); extern int ui_spy_sabotage_done(struct game_s *g, int pi, int spy, int target, ui_sabotage_t act, int other1, int other2, uint8_t planet, int snum); extern void ui_newtech(struct game_s *g, int pi); extern bool ui_explore(struct game_s *g, int pi, uint8_t planet_i, bool by_scanner, bool flag_colony_ship); extern void ui_landing(struct game_s *g, int pi, uint8_t planet_i); extern bool ui_bomb_ask(struct game_s *g, int pi, uint8_t planet_i, int pop_inbound); extern void ui_bomb_show(struct game_s *g, int pi, int attacker_i, int owner_i, uint8_t planet_i, int popdmg, int factdmg, bool play_music, bool hide_other); extern void ui_turn_pre(const struct game_s *g); extern void ui_turn_msg(struct game_s *g, int pi, const char *str); struct ground_s; extern void ui_ground(struct game_s *g, struct ground_s *gr); struct news_s; extern void ui_news_start(void); extern void ui_news(struct game_s *g, struct news_s *ns); extern void ui_news_end(void); struct election_s; extern void ui_election_start(struct election_s *el); extern void ui_election_show(struct election_s *el); extern void ui_election_delay(struct election_s *el, int delay); extern int ui_election_vote(struct election_s *el, int player_i); extern bool ui_election_accept(struct election_s *el, int player_i); extern void ui_election_end(struct election_s *el); struct audience_s; extern void ui_audience_start(struct audience_s *au); extern void ui_audience_show1(struct audience_s *au); extern void ui_audience_show2(struct audience_s *au); extern void ui_audience_show3(struct audience_s *au); extern int16_t ui_audience_ask2a(struct audience_s *au); extern int16_t ui_audience_ask2b(struct audience_s *au); extern int16_t ui_audience_ask3(struct audience_s *au); extern int16_t ui_audience_ask4(struct audience_s *au); extern void ui_audience_newtech(struct audience_s *au, int pi); extern void ui_audience_end(struct audience_s *au); extern void ui_newships(struct game_s *g, int pi); extern void ui_copyprotection_check(struct game_s *g); extern void ui_copyprotection_lose(struct game_s *g, struct game_end_s *ge); #endif 1oom-1.11.2/src/ui/000077500000000000000000000000001476061725400136675ustar00rootroot000000000000001oom-1.11.2/src/ui/Makefile.am000066400000000000000000000002161476061725400157220ustar00rootroot00000000000000SUBDIRS = nop if COMPILE_UICMDLINE SUBDIRS += cmdline endif if COMPILE_UICLASSIC SUBDIRS += classic endif DIST_SUBDIRS = nop cmdline classic 1oom-1.11.2/src/ui/classic/000077500000000000000000000000001476061725400153105ustar00rootroot000000000000001oom-1.11.2/src/ui/classic/Makefile.am000066400000000000000000000032731476061725400173510ustar00rootroot00000000000000AM_CPPFLAGS = \ @OS_INCLUDES@ \ -I$(top_srcdir)/src/game \ -I$(top_srcdir)/src noinst_LIBRARIES = libuiclassic.a libuiclassic_a_SOURCES = \ uiaudience.c \ uibasescrap.c \ uibasescrap.h \ uibattle.c \ uibattlepre.c \ uibattlepre.h \ uibomb.c \ uicaught.c \ uicaught.h \ uiclassic.c \ uicopyprotection.c \ uicursor.c \ uicursor.h \ uidefs.h \ uidelay.c \ uidelay.h \ uidesign.c \ uidesign.h \ uidialog.c \ uidialog.h \ uidraw.c \ uidraw.h \ uielection.c \ uiempirereport.c \ uiempirereport.h \ uiempirestatus.c \ uiempirestatus.h \ uiending.c \ uiexplore.c \ uifleet.c \ uifleet.h \ uigame.c \ uigameopts.c \ uigameopts.h \ uigmap.c \ uigmap.h \ uiground.c \ uihelp.c \ uihelp.h \ uiintro.c \ uilanding.c \ uilanding.h \ uiload.c \ uiload.h \ uimainmenu.c \ uinewgame.c \ uinewgame.h \ uinews.c \ uinews.h \ uinewships.c \ uinewtech.c \ uiobj.c \ uiobj.h \ uipal.c \ uipal.h \ uiplanets.c \ uiplanets.h \ uiraces.c \ uiraces.h \ uisave.c \ uisave.h \ uisearch.c \ uisearch.h \ uisound.c \ uisound.h \ uispecs.c \ uispecs.h \ uispy_esp.c \ uispy_sab.c \ uistarmap.c \ uistarmap.h \ uistarmap_common.c \ uistarmap_common.h \ uistarmap_enroute.c \ uistarmap_orbit_en.c \ uistarmap_orbit_own.c \ uistarmap_reloc.c \ uistarmap_ships.c \ uistarmap_trans.c \ uistarmap_transport.c \ uistarview.c \ uistarview.h \ uiswitch.c \ uiswitch.h \ uitech.c \ uitech.h \ uiturn.c 1oom-1.11.2/src/ui/classic/uiaudience.c000066400000000000000000000304141476061725400175710ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "comp.h" #include "game_audience.h" #include "game_aux.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct audience_data_s { struct audience_s *au; uint8_t *gfx_border; uint8_t *gfx_race; uint8_t *gfx_emperor; int8_t music_0; int8_t music_1; int8_t music_i; uint8_t gfxi; int delay; }; static const int8_t tbl_audience_music[RACE_NUM] = { 0x16, 0x14, 0x22, 0x20, 0x1c, 0x12, 0x18, 0x24, 0x1a, 0x1e }; /* -------------------------------------------------------------------------- */ static void audience_load_data(struct audience_data_s *d) { struct game_s *g = d->au->g; race_t ra = g->eto[d->au->pa].race; d->gfx_border = lbxfile_item_get(LBXFILE_EMBASSY, 0); { uint8_t *gfx; gfx = lbxfile_item_get(LBXFILE_EMBASSY, 1); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, gfx, UI_SCREEN_W, ui_scale); uiobj_table_clear(); uiobj_finish_frame(); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, gfx, UI_SCREEN_W, ui_scale); lbxfile_item_release(LBXFILE_EMBASSY, gfx); } d->gfx_race = lbxfile_item_get(LBXFILE_EMBASSY, 0x2 + ra); d->gfx_emperor = lbxfile_item_get(LBXFILE_EMBASSY, 0xc + g->eto[d->au->ph].banner); d->music_0 = tbl_audience_music[ra]; d->music_1 = tbl_audience_music[ra] + 1; } static void audience_free_data(struct audience_data_s *d) { lbxfile_item_release(LBXFILE_EMBASSY, d->gfx_border); lbxfile_item_release(LBXFILE_EMBASSY, d->gfx_race); lbxfile_item_release(LBXFILE_EMBASSY, d->gfx_emperor); } static void ui_audience_draw_race(struct audience_data_s *d) { struct audience_s *au = d->au; uint8_t *gfx = d->gfx_race; int frame = -1, x = 96; if (au->gfxi != d->gfxi) { switch (au->gfxi) { case 0: case 1: case 2: frame = 2; break; case 3: frame = 0; break; case 4: case 5: frame = 1; break; default: break; } if (frame >= 0) { lbxgfx_set_new_frame(gfx, frame); } } frame = lbxgfx_get_frame(gfx); switch (au->gfxi) { case 0: draw_anim: SETMAX(frame, 2); lbxgfx_set_new_frame(gfx, 2); for (int f = 0; f <= (frame - 2); ++f) { lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); } d->delay = (d->delay + 1) % 4; if (d->delay != 0) { lbxgfx_set_new_frame(gfx, frame); } break; case 1: if (frame < 2) { lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); d->delay = (d->delay + 1) % 4; } else { goto draw_anim; } break; case 2: if (frame < 2) { lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); d->delay = (d->delay + 1) % 4; } else { goto draw_anim; } break; case 3: lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); break; case 4: lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(x, 0, gfx, UI_SCREEN_W, ui_scale); break; case 5: default: break; } d->gfxi = au->gfxi; } static void ui_audience_play_music(struct audience_data_s *d, uint8_t musi) { int mi = -1; if ((musi == 0) || (musi == 1)) { mi = d->music_0; } else if (musi == 2) { mi = d->music_1; } if ((mi >= 0) && (d->music_i != mi)) { d->music_i = mi; ui_sound_play_music(mi); } } static void ui_audience_draw_cb1(void *vptr) { struct audience_data_s *d = vptr; struct audience_s *au = d->au; if (au->mode != 1) { ui_audience_draw_race(d); } lbxgfx_draw_frame(0, -2, d->gfx_emperor, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_border, UI_SCREEN_W, ui_scale); if ((au->mode >= 0) && (au->mode <= 2)) { lbxfont_select(3, 2, 0, 0); lbxfont_set_gap_h(1); lbxfont_print_str_split(38, 140, 245, au->buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } /*d->delay2 = (d->delay2 + 1) % 6;*/ } static void ui_audience_draw_cb2(void *vptr) { struct audience_data_s *d = vptr; struct audience_s *au = d->au; int strh; ui_audience_draw_race(d); lbxgfx_draw_frame(0, -2, d->gfx_emperor, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_border, UI_SCREEN_W, ui_scale); lbxfont_select(3, 1, 0, 0); lbxfont_set_gap_h(1); strh = lbxfont_calc_split_str_h(245, au->buf); if (strh > 39) { lbxfont_set_gap_h(0); } lbxfont_print_str_split(38, 140, 245, au->buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); /*d->delay2 = (d->delay2 + 1) % 6;*/ } static void ui_audience_draw_cb3(void *vptr) { struct audience_data_s *d = vptr; struct audience_s *au = d->au; ui_audience_draw_race(d); lbxgfx_draw_frame(0, -2, d->gfx_emperor, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_border, UI_SCREEN_W, ui_scale); lbxfont_select(3, 2, 1, 0); lbxfont_set_gap_h(1); lbxfont_print_str_split(38, 140, 245, au->buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); /*d->delay2 = (d->delay2 + 1) % 6;*/ } static void ui_audience_draw_cb4(void *vptr) /* FIXME combine with cb3 and/or cb2 */ { struct audience_data_s *d = vptr; struct audience_s *au = d->au; int strh; ui_audience_draw_race(d); lbxgfx_draw_frame(0, -2, d->gfx_emperor, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_border, UI_SCREEN_W, ui_scale); lbxfont_select(3, 1, 0, 0); lbxfont_set_gap_h(1); strh = lbxfont_calc_split_str_h(245, au->buf); if (strh > 39) { lbxfont_set_gap_h(0); } lbxfont_print_str_split(38, 136, 245, au->buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); /*d->delay2 = (d->delay2 + 1) % 6;*/ } static int16_t ui_audience_ask_do(struct audience_s *au, int y, void (*draw_cb)(void *vptr)) { int16_t selected = 0; ui_audience_play_music(au->uictx, au->musi); /* side effect of game_audience_get_diplo_msg() */ uiobj_set_callback_and_delay(draw_cb, au->uictx, 1); uiobj_set_downcount(1); lbxfont_select(0, 2, 3, 0); selected = uiobj_select_from_list1(38, y, 245, "", au->strtbl, &selected, au->condtbl, 0xf, 0xb, true); return selected; } /* -------------------------------------------------------------------------- */ void ui_audience_start(struct audience_s *au) { static struct audience_data_s d; /* HACK */ ui_switch_2(au->g, au->ph, au->pa); d.au = au; au->uictx = &d; d.delay = 0; d.music_i = -1; d.gfxi = 0xff; if (ui_draw_finish_mode == 0) { ui_palette_fadeout_a_f_1(); } ui_draw_finish_mode = 2; ui_sound_stop_music(); ui_delay_1(); audience_load_data(&d); lbxpal_select(7, -1, 0); lbxpal_set_update_range(0, 255); lbxpal_build_colortables(); uiobj_table_clear(); uiobj_set_callback_and_delay(ui_audience_draw_cb1, &d, 3); uiobj_set_downcount(1); } void ui_audience_show1(struct audience_s *au) { struct audience_data_s *d = au->uictx; bool flag_done = false; int16_t oi_ma = UIOBJI_INVALID; ui_audience_play_music(au->uictx, au->musi); /* side effect of game_audience_get_diplo_msg() */ uiobj_set_callback_and_delay(ui_audience_draw_cb1, d, 1); uiobj_set_downcount(1); uiobj_table_clear(); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_ma) || (oi == UIOBJI_ESC)) { flag_done = true; } uiobj_table_clear(); oi_ma = UIOBJI_INVALID; if ((au->mode >= 0) && (au->mode <= 2)) { oi_ma = uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); } if (!flag_done) { ui_audience_draw_cb1(d); ui_delay_ticks_or_click(1); ui_draw_finish(); } } uiobj_table_clear(); } void ui_audience_show2(struct audience_s *au) { struct audience_data_s *d = au->uictx; int16_t oi = 0; ui_audience_play_music(d, au->musi); /* side effect of game_audience_get_diplo_msg() */ uiobj_set_callback_and_delay(ui_audience_draw_cb2, d, 1); uiobj_set_downcount(1); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); while (oi == 0) { ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi == 0) { ui_audience_draw_cb2(d); ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_table_clear(); } void ui_audience_show3(struct audience_s *au) { struct audience_data_s *d = au->uictx; bool flag_done = false; ui_audience_play_music(au->uictx, au->musi); /* side effect of game_audience_get_diplo_msg() */ uiobj_set_callback_and_delay(ui_audience_draw_cb3, d, 1); uiobj_set_downcount(1); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } if (!flag_done) { ui_audience_draw_cb3(d); ui_delay_ticks_or_click(1); ui_draw_finish(); } } uiobj_table_clear(); } int16_t ui_audience_ask2a(struct audience_s *au) { return ui_audience_ask_do(au, 145, ui_audience_draw_cb2); } int16_t ui_audience_ask2b(struct audience_s *au) { int strh; lbxfont_select(3, 1, 0, 0); lbxfont_set_gap_h(1); strh = lbxfont_calc_split_str_h(245, au->buf); if (strh > 39) { lbxfont_set_gap_h(0); strh = lbxfont_calc_split_str_h(245, au->buf); } return ui_audience_ask_do(au, 133 + strh, ui_audience_draw_cb2); } int16_t ui_audience_ask3(struct audience_s *au) { int strh; lbxfont_select(3, 2, 1, 0); lbxfont_set_gap_h(1); strh = lbxfont_calc_split_str_h(245, au->buf); return ui_audience_ask_do(au, 139 + strh, ui_audience_draw_cb3); } int16_t ui_audience_ask4(struct audience_s *au) { return ui_audience_ask_do(au, 139, ui_audience_draw_cb4); } void ui_audience_newtech(struct audience_s *au, int pi) { bool flag_switched; ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; lbxpal_select(0, -1, 0); lbxpal_set_update_range(0, 255); lbxpal_build_colortables(); if (pi == PLAYER_NONE) { ui_newtech(au->g, au->ph); ui_newtech(au->g, au->pa); } else { ui_newtech(au->g, pi); } flag_switched = ui_switch_2(au->g, au->ph, au->pa); if (flag_switched) { ui_palette_fadeout_a_f_1(); } lbxpal_select(7, -1, 0); lbxpal_set_update_range(0, 255); if ((!flag_switched) && (ui_draw_finish_mode == 0)) { ui_palette_fadeout_a_f_1(); } ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); audience_free_data(au->uictx); audience_load_data(au->uictx); if (flag_switched) { ui_draw_finish_mode = 2; } else { ui_draw_finish_mode = 0; } lbxpal_build_colortables(); ui_sound_play_music(((struct audience_data_s *)(au->uictx))->music_0); } void ui_audience_end(struct audience_s *au) { struct audience_data_s *d = au->uictx; uiobj_unset_callback(); uiobj_table_clear(); ui_sound_stop_music(); ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; lbxpal_select(0, -1, 0); lbxpal_set_update_range(0, 255); lbxpal_build_colortables(); ui_switch_1(au->g, au->ph); audience_free_data(d); } 1oom-1.11.2/src/ui/classic/uibasescrap.c000066400000000000000000000074661476061725400177720ustar00rootroot00000000000000#include "config.h" #include #include "uibasescrap.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "game_tech.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct basescrap_data_s { struct game_s *g; uint8_t *gfx; player_id_t api; int16_t slider_var; }; static void basescrap_load_data(struct basescrap_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 0x1e); } static void basescrap_free_data(struct basescrap_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void basescrap_draw_cb1(void *vptr) { struct basescrap_data_s *d = vptr; struct game_s *g = d->g; const int x = 56, y = 50; const planet_t *p = &(g->planet[g->planet_focus_i[d->api]]); lbxgfx_draw_frame(x, y, d->gfx, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(x + 14, y + 35, x + 64, y + 38, 0x2f, ui_scale); if (d->slider_var > 0) { ui_draw_slider(x + 14, y + 36, d->slider_var, 2, -1, 0x74, ui_scale); } lbxfont_select(0, 0xd, 0, 0); lbxfont_print_str_center(x + 57, y + 11, game_str_bs_line1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(x + 57, y + 20, game_str_bs_line2, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_right(x + 104, y + 35, game_str_bs_bases, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 83, y + 35, (p->missile_bases * d->slider_var) / 100, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_basescrap(struct game_s *g, player_id_t active_player) { struct basescrap_data_s d; bool flag_done = false; int16_t oi_cancel, oi_accept, oi_plus, oi_minus; const int x = 56, y = 50; planet_t *p = &(g->planet[g->planet_focus_i[active_player]]); d.g = g; d.api = active_player; basescrap_load_data(&d); ui_draw_copy_buf(); uiobj_finish_frame(); d.slider_var = 0; ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); uiobj_table_clear(); oi_cancel = uiobj_add_t0(x + 10, y + 47, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); oi_accept = uiobj_add_t0(x + 66, y + 47, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); uiobj_add_slider_int(x + 14, y + 35, 0, 100, 50, 9, &d.slider_var); oi_minus = uiobj_add_mousearea(x + 10, y + 33, x + 12, y + 41, MOO_KEY_UNKNOWN); oi_plus = uiobj_add_mousearea(x + 66, y + 33, x + 70, y + 41, MOO_KEY_UNKNOWN); uiobj_set_callback_and_delay(basescrap_draw_cb1, &d, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_cancel) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; } else if (oi == oi_accept) { int n; ui_sound_play_sfx_24(); n = (p->missile_bases * d.slider_var) / 100; p->missile_bases -= n; g->eto[active_player].reserve_bc += (n * game_get_base_cost(g, active_player)) / 4; flag_done = true; SETMAX(p->missile_bases, 0); } else if (oi == oi_minus) { d.slider_var -= 2; SETMAX(d.slider_var, 0); } else if (oi == oi_plus) { d.slider_var += 2; SETMIN(d.slider_var, 100); } if (!flag_done) { basescrap_draw_cb1(&d); ui_draw_finish(); ui_delay_ticks_or_click(3); } } uiobj_unset_callback(); uiobj_table_clear(); basescrap_free_data(&d); } 1oom-1.11.2/src/ui/classic/uibasescrap.h000066400000000000000000000002771476061725400177700ustar00rootroot00000000000000#ifndef INC_1OOM_UIBASESCRAP_H #define INC_1OOM_UIBASESCRAP_H #include "game_types.h" #include "types.h" struct game_s; extern void ui_basescrap(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uibattle.c000066400000000000000000002400371476061725400172730ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_battle.h" #include "game_battle_human.h" #include "game_misc.h" #include "game_shiptech.h" #include "game_str.h" #include "gfxaux.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "uibattlepre.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ #define MAX_VISIBLE_MISSILE 10 struct ui_battle_data_s { struct battle_s *bt; uint8_t *gfx_bg; bool show_switch; uint8_t frame_ship; uint8_t frame_missile; bool flag_scanning; battle_side_i_t scan_side; int16_t oi_ai; int16_t oi_missile; int16_t oi_special; int16_t oi_wait; int16_t oi_retreat; int16_t oi_planet; int16_t oi_scan; int16_t oi_auto; int16_t oi_done; int16_t oi_grid; int16_t oi_area[BATTLE_AREA_H][BATTLE_AREA_W]; ui_cursor_area_t cursor[1 + BATTLE_AREA_W * BATTLE_AREA_H]; }; /* -------------------------------------------------------------------------- */ static void ui_battle_draw_scan_cb(void *vptr) { const struct battle_s *bt = vptr; struct ui_battle_data_s *d = bt->uictx; int itembase, itemnum; itembase = (d->scan_side == SIDE_L) ? 1 : (bt->s[SIDE_L].items + 1); itemnum = bt->s[d->scan_side].items; ui_draw_color_buf(0x3a); lbxgfx_draw_frame(0, 0, ui_data.gfx.starmap.viewship, UI_SCREEN_W, ui_scale); for (int i = 0; i < itemnum; ++i) { const struct battle_item_s *b = &(bt->item[itembase + i]); int y; y = i * 32 + 5; lbxgfx_draw_frame(46, y - 1, ui_data.gfx.space.vs2, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(6, y, 38, y + 29, 0, ui_scale); ui_draw_stars(6, y + 1, 0, 32, ui_scale); ui_battle_draw_item(bt, itembase + i, 6, y + 1); lbxfont_select(2, 0xd, 0, 0); lbxfont_print_str_normal(52, y + 3, b->name, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xb, 0, 0); lbxfont_print_num_right(84, y + 13, b->defense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(84, y + 23, b->misdefense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(124, y + 13, b->complevel, UI_SCREEN_W, ui_scale); if (b->hp1 < b->hp2) { lbxfont_select(2, 5, 0, 0); } lbxfont_print_num_right(124, y + 23, b->hp1, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xb, 0, 0); lbxfont_print_num_right(161, y + 3, b->absorb, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(161, y + 13, b->hploss, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(161, y + 23, b->man - b->unman, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xa, 0, 0); for (int wi = 0; wi < WEAPON_SLOT_NUM; ++wi) { if (b->wpn[wi].n != 0) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[wi].t]); lbxfont_print_num_right(176, y + 3 + wi * 7, b->wpn[wi].n, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(181, y + 3 + wi * 7, *w->nameptr, UI_SCREEN_W, ui_scale); if (b->wpn[wi].numshots >= 0) { lbxfont_print_num_right(250, y + 3 + wi * 7, b->wpn[wi].numshots, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(252, y + 3 + wi * 7, "&", UI_SCREEN_W, ui_scale); } if (w->misstype == 1) { uint8_t c1, c2; if (b->wpn[wi].numfire > 0) { c1 = 0x6c; c2 = 0x6f; } else { c1 = 0x28; c2 = 0x41; } ui_draw_filled_rect(248, y + 3 + wi * 7, 253, y + 7 + wi * 7, c1, ui_scale); ui_draw_filled_rect(249, y + 4 + wi * 7, 252, y + 6 + wi * 7, c2, ui_scale); } } } if (b->special[0] == 0) { lbxfont_select(2, 0xa, 0, 0); } else { lbxfont_set_color_c_n(0xb5, 5); } lbxfont_print_str_center(286, y + 2, game_str_tbl_st_specsh[b->special[0]], UI_SCREEN_W, ui_scale); if (b->special[1] != 0) { lbxfont_print_str_center(286, y + 11, game_str_tbl_st_specsh[b->special[1]], UI_SCREEN_W, ui_scale); } if (b->special[2] != 0) { lbxfont_print_str_center(286, y + 20, game_str_tbl_st_specsh[b->special[2]], UI_SCREEN_W, ui_scale); } } uiobj_finish_frame(); ui_draw_copy_buf(); ui_draw_set_stars_xoffs(d->scan_side == SIDE_R); d->frame_ship = (d->frame_ship + 1) % 5; } static void ui_battle_draw_focusinfo(const struct battle_s *bt) { const struct battle_item_s *b; int16_t v = uiobj_at_cursor() - 1; if ((v < 0) || (v >= (BATTLE_AREA_W * BATTLE_AREA_H))) { v = 100; } else { int sx, sy; sx = v % BATTLE_AREA_W; sy = v / BATTLE_AREA_W; v = bt->area[sy][sx]; } if ((v == 1) || (v == 0)) { v = 100; } if (v < 0) { if (v == -30) { v = 0; } else { v = -v; } } if ((v >= 10) && (v < 30)) { v -= 10; } if (v >= 30) { v -= 30; } ui_draw_filled_rect(0, 193, 94, UI_VGA_H - 1, 0xe9, ui_scale); b = (v == 70) ? &(bt->item[bt->cur_item]) : &(bt->item[v]); lbxfont_select(2, 0xa, 5, 0); lbxfont_print_str_normal(2, 194, b->name, UI_SCREEN_W, ui_scale); if (v != 70) { if (b->num > 0) { char buf[32]; int h1 = b->hp1, h2 = b->hp2, ha = h1 - b->hploss, pos; pos = lib_sprintf(buf, sizeof(buf), "%i/", ha); if (h1 < h2) { buf[pos++] = 2; } lib_sprintf(&buf[pos], sizeof(buf) - pos, "%i", h1); lbxfont_print_str_right(92, 194, buf, UI_SCREEN_W, ui_scale); } } } static void ui_battle_clear_ois(struct ui_battle_data_s *d) { d->oi_missile = UIOBJI_INVALID; d->oi_special = UIOBJI_INVALID; d->oi_wait = UIOBJI_INVALID; d->oi_retreat = UIOBJI_INVALID; d->oi_planet = UIOBJI_INVALID; d->oi_scan = UIOBJI_INVALID; d->oi_auto = UIOBJI_INVALID; d->oi_done = UIOBJI_INVALID; d->oi_grid = UIOBJI_INVALID; for (int y = 0; y < BATTLE_AREA_H; ++y) { for (int x = 0; x < BATTLE_AREA_W; ++x) { d->oi_area[y][x] = UIOBJI_INVALID; /* BUG? not done in MOO1 */ } } } static void ui_battle_draw_bottom_no_ois(const struct battle_s *bt) { struct ui_battle_data_s *d = bt->uictx; const struct battle_item_s *b; uint8_t *gfx; ui_draw_filled_rect(0, 193, 319, 199, 0xe9, ui_scale); ui_draw_line1(120, 192, 120, 199, 0xeb, ui_scale); ui_draw_line1(96, 192, 96, 199, 0xeb, ui_scale); ui_draw_line1(0, 192, 319, 192, 0xeb, ui_scale); lbxfont_select(2, 0xa, 5, 0); b = &(bt->item[bt->cur_item]); if (bt->s[b->side].flag_auto) { lbxfont_print_str_normal(2, 194, game_str_bt_auto_move, UI_SCREEN_W, ui_scale); } else { ui_battle_draw_focusinfo(bt); } if (bt->item[0].side != SIDE_NONE) { gfx = ui_data.gfx.space.planet; lbxgfx_set_frame_0(gfx); } else { gfx = ui_data.gfx.space.planet_off; } lbxgfx_draw_frame(123, 193, gfx, UI_SCREEN_W, ui_scale); if (1 && ((bt->cur_item != 0) || (b->num > 0) || (!bt->s[b->side].flag_auto)) && (((b->man - b->unman) != 0) || (bt->cur_item == 0) || (!bt->s[b->side].flag_human)) ) { gfx = ui_data.gfx.space.retreat; lbxgfx_set_frame_0(gfx); } else { gfx = ui_data.gfx.space.retr_off; } lbxgfx_draw_frame(241, 193, gfx, UI_SCREEN_W, ui_scale); if (bt->s[b->side].flag_auto) { ui_battle_clear_ois(d); } if ((b->missile == -1) || bt->s[b->side].flag_auto) { gfx = ui_data.gfx.space.misl_off; } else if (bt->cur_item == 0) { gfx = ui_data.gfx.space.base_btn; if (tbl_shiptech_weap[b->wpn[0].t].nummiss == 1) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } else { gfx = ui_data.gfx.space.misbutt; if (b->missile == 0) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } lbxgfx_draw_frame(175, 193, gfx, UI_SCREEN_W, ui_scale); if ((bt->special_button == -1) || bt->s[b->side].flag_auto) { gfx = ui_data.gfx.space.spec_off; } else { gfx = ui_data.gfx.space.special; if (bt->special_button == 0) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } lbxgfx_draw_frame(210, 193, gfx, UI_SCREEN_W, ui_scale); if (bt->s[bt->s[b->side].flag_human ? b->side : SIDE_L].flag_have_scan) { gfx = ui_data.gfx.space.scan; lbxgfx_set_frame_0(gfx); } else { gfx = ui_data.gfx.space.scan_off; } lbxgfx_draw_frame(153, 193, gfx, UI_SCREEN_W, ui_scale); gfx = ui_data.gfx.space.done; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(297, 193, gfx, UI_SCREEN_W, ui_scale); gfx = ui_data.gfx.space.wait; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(274, 193, gfx, UI_SCREEN_W, ui_scale); gfx = ui_data.gfx.space.autob; if (bt->s[b->side].flag_auto) { lbxgfx_set_new_frame(gfx, 1); } else { lbxgfx_set_frame_0(gfx); } lbxgfx_draw_frame(99, 193, gfx, UI_SCREEN_W, ui_scale); } static void ui_battle_draw_bottom_add_ois(const struct battle_s *bt) { struct ui_battle_data_s *d = bt->uictx; const struct battle_item_s *b; uint8_t *gfx; uiobj_table_clear(); for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { int y0, y1; y0 = sy * 24; y1 = y0 + 23; for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { ui_cursor_area_t *cr = &(d->cursor[1 + sy * BATTLE_AREA_W + sx]); int x0, x1; x0 = sx * 32; x1 = x0 + 31; cr->x0 = x0 * ui_scale; cr->y0 = y0 * ui_scale; cr->x1 = x1 * ui_scale + ui_scale - 1; cr->y1 = y1 * ui_scale + ui_scale - 1; d->oi_area[sy][sx] = uiobj_add_mousearea(x0, y0, x1, y1, MOO_KEY_UNKNOWN); } } ui_draw_filled_rect(0, 193, 319, 199, 0xe9, ui_scale); ui_draw_line1(120, 192, 120, 199, 0xeb, ui_scale); ui_draw_line1(96, 192, 96, 199, 0xeb, ui_scale); ui_draw_line1(0, 192, 319, 192, 0xeb, ui_scale); if (bt->item[0].side != SIDE_NONE) { d->oi_planet = uiobj_add_t0(123, 193, "", ui_data.gfx.space.planet, MOO_KEY_p); } else { lbxgfx_draw_frame(123, 193, ui_data.gfx.space.planet_off, UI_SCREEN_W, ui_scale); d->oi_planet = UIOBJI_INVALID; } b = &(bt->item[bt->cur_item]); if (0 || ((b->side != SIDE_NONE) && (bt->s[b->side].items <= 0)) || ((bt->cur_item != 0) && (b->num <= 0)) || (((b->man - b->unman) != 0) && (bt->cur_item == 0)) ) { lbxgfx_draw_frame(241, 193, ui_data.gfx.space.retr_off, UI_SCREEN_W, ui_scale); d->oi_retreat = UIOBJI_INVALID; } else { d->oi_retreat = uiobj_add_t0(241, 193, "", ui_data.gfx.space.retreat, MOO_KEY_r); } d->oi_done = uiobj_add_t0(297, 193, "", ui_data.gfx.space.done, MOO_KEY_d); d->oi_grid = uiobj_add_inputkey(MOO_KEY_g); d->oi_wait = uiobj_add_t0(274, 193, "", ui_data.gfx.space.wait, MOO_KEY_w); #if 0 d->oi_auto = uiobj_add_t0(99, 193, "", ui_data.gfx.space.autob, MOO_KEY_a); #else /* HACK MOO1 does this. Breaks const *bt and requires flag to be int16_t, but works while it is not the player's turn. */ d->oi_auto = uiobj_add_t1(99, 193, "", ui_data.gfx.space.autob, &(((struct battle_s *)bt)->s[b->side].flag_auto), MOO_KEY_a); #endif if ((b->missile == 0) || (b->missile == 1)) { if (bt->cur_item == 0) { if (b->wpn[0].t != b->wpn[1].t) { d->oi_missile = uiobj_add_mousearea(175, 193, 208, 199, MOO_KEY_m); gfx = ui_data.gfx.space.base_btn; if (bt->s[b->side].flag_base_missile) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } else { gfx = ui_data.gfx.space.misl_off; d->oi_missile = UIOBJI_INVALID; } } else { d->oi_missile = uiobj_add_mousearea(175, 193, 208, 199, MOO_KEY_m); gfx = ui_data.gfx.space.misbutt; if (b->missile == 0) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } } else { gfx = ui_data.gfx.space.misl_off; d->oi_missile = UIOBJI_INVALID; } lbxgfx_draw_frame(175, 193, gfx, UI_SCREEN_W, ui_scale); if (bt->s[b->side].flag_have_scan) { d->oi_scan = uiobj_add_t0(153, 193, "", ui_data.gfx.space.scan, MOO_KEY_s); } else { lbxgfx_draw_frame(153, 193, ui_data.gfx.space.scan_off, UI_SCREEN_W, ui_scale); d->oi_scan = UIOBJI_INVALID; } if ((bt->special_button == 0) || ((bt->special_button == 1) && (bt->cur_item != 0))) { gfx = ui_data.gfx.space.special; if ((b->pulsar == 3) || (b->stasis == 3) || (b->pulsar == 4)) { lbxgfx_set_frame_0(gfx); d->oi_special = UIOBJI_INVALID; } else { d->oi_special = uiobj_add_mousearea(210, 193, 239, 199, MOO_KEY_p); if (bt->special_button == 0) { lbxgfx_set_frame_0(gfx); } else { lbxgfx_set_new_frame(gfx, 1); } } } else { gfx = ui_data.gfx.space.spec_off; d->oi_special = UIOBJI_INVALID; } lbxgfx_draw_frame(210, 193, gfx, UI_SCREEN_W, ui_scale); } static void ui_battle_draw_cb(void *vptr) { const struct battle_s *bt = vptr; ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_bottom_no_ois(bt); } static void ui_battle_transition_to(int px, int py, int steps) { uiobj_table_clear(); hw_video_copy_buf_out(ui_data.aux.screen.data); ui_draw_copy_buf(); memcpy(ui_data.gfx.vgafileh, ui_data.aux.screen.data, UI_SCREEN_W * UI_SCREEN_H); for (int i = 1; i <= steps; ++i) { int x, y, percent; ui_delay_prepare(); ui_data.aux.screen.w = UI_SCREEN_W; ui_data.aux.screen.h = UI_SCREEN_H; memcpy(ui_data.aux.screen.data, ui_data.gfx.vgafileh, UI_SCREEN_W * UI_SCREEN_H); x = px - ((i * px) / steps); y = py - ((i * py) / steps); percent = (i * 100) / steps; if ((x + (percent * UI_SCREEN_W) / 100) > UI_SCREEN_W) { x = UI_SCREEN_W - (percent * UI_SCREEN_W) / 100; } if ((y + (percent * UI_SCREEN_H) / 100) > UI_SCREEN_H) { y = UI_SCREEN_H - (percent * UI_SCREEN_H) / 100; } gfx_aux_scale(&ui_data.aux.screen, percent, percent); gfx_aux_color_replace(&ui_data.aux.screen, 0, 1); gfx_aux_draw_frame_from(x, y, &ui_data.aux.screen, UI_SCREEN_W, 1); uiobj_finish_frame(); ui_delay_us_or_click(MOO_TICKS_TO_US(1) / 3); } #if 0 /* test for scale up */ ui_data.aux.screen.w = UI_SCREEN_W; ui_data.aux.screen.h = UI_SCREEN_H; memcpy(ui_data.aux.screen.data, ui_data.gfx.vgafileh, UI_SCREEN_W * UI_SCREEN_H); struct gfx_auxbuf_s aux2; memset(&aux2, 0, sizeof(aux2)); for (int i = 1; i <= steps; ++i) { int x, y, percent; ui_delay_prepare(); lbxgfx_setup_auxbuf_wh(&aux2, 320, 200); aux2.w = 32; aux2.h = 24; gfx_aux_draw_frame_to(ui_data.gfx.ships[0x92], &aux2); percent = (i * 700) / steps; x = 320/2 - (percent * (200/2)) / 700; y = 200/2 - (percent * (200/2)) / 700; gfx_aux_scale(&aux2, percent, percent); memcpy(ui_data.aux.screen.data, ui_data.gfx.vgafileh, UI_SCREEN_W * UI_SCREEN_H); gfx_aux_color_replace(&ui_data.aux.screen, 0, 1); gfx_aux_overlay(x, y, &ui_data.aux.screen, &aux2); gfx_aux_draw_frame_from(0, 0, &ui_data.aux.screen, UI_SCREEN_W); uiobj_finish_frame(); ui_delay_us_or_click(MOO_TICKS_TO_US(1) / 3); } ui_delay_us_or_click(1000000); #endif } static void ui_battle_draw_beam_line(int fx, int fy, int tx, int ty, int d0, int d1, uint8_t v24, const uint8_t *ctbl) { int dist, x0, y0, x1, y1; dist = util_math_dist_fast(fx, fy, tx, ty); x0 = fx; y0 = fy; util_math_go_line_dist(&x0, &y0, tx, ty, (d0 * dist) / 100); x1 = x0; y1 = y0; util_math_go_line_dist(&x1, &y1, tx, ty, (d1 * dist) / 100); if ((v24 == 1) || (v24 == 3) || (v24 == 5)) { ui_draw_line1(x0, y0, x1, y1, ctbl[0], ui_scale); } else { const uint8_t *c; uint8_t revctbl[7]; if (x0 <= x1) { for (int i = 0; i < 7; ++i) { revctbl[6 - i] = ctbl[i]; } c = revctbl; } else { c = ctbl; } ui_draw_line_ctbl(x0, y0, x1, y1, c, 7, 1/*ctblpos*/, ui_scale); } } static void ui_battle_draw_beam_attack_do1(const struct battle_s *bt, int *fx, int *fy, int tx, int ty, weapon_t wpnt, int attacker_i, int v16, uint8_t btype) { const struct battle_item_s *b = &(bt->item[attacker_i]); const struct shiptech_weap_s *w = &(tbl_shiptech_weap[wpnt]); int frames = 2, xo = 0, yo = 0; for (int f = 0; f < frames; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 1); ui_battle_draw_bottom(bt); if (v16 > 1) { ui_battle_draw_beam_line(fx[0], fy[0], tx, ty, 0, 100 / frames + (100 / frames) * f, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx, ty, 0, 100 / frames + (100 / frames) * f, w->v24, w->dtbl); } /*53827*/ if (v16 != 2) { ui_battle_draw_beam_line(fx[2], fy[2], tx, ty, 0, 100 / frames + (100 / frames) * f, w->v24, w->dtbl); } /*53874*/ ui_battle_draw_item(bt, attacker_i, b->sx * 32, b->sy * 24); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } /*538c4*/ if (((btype == 1) || (w->numfire > 1)) && !(bt->s[SIDE_L].flag_auto && bt->s[SIDE_R].flag_auto)) { for (int f = 0; f < 7; ++f) { ui_delay_prepare(); if ((f & 1) == 1) { ui_battle_draw_arena(bt, attacker_i, 1); } ui_battle_draw_bottom(bt); if (w->numfire > 1) { xo = rnd_1_n(3, &ui_data.seed) - 2; yo = rnd_1_n(3, &ui_data.seed) - 2; } else { xo = 0; yo = 0; } if (btype == 1) { if (v16 > 1) { ui_draw_line1(fx[0], fy[0], tx + xo, ty + yo, w->dtbl[f], ui_scale); ui_draw_line1(fx[1], fy[1], tx + xo, ty + yo, w->dtbl[f], ui_scale); } if (v16 != 2) { ui_draw_line1(fx[2], fy[2], tx + xo, ty + yo, w->dtbl[f], ui_scale); } } if (btype == 0) { if (v16 > 1) { ui_draw_line_ctbl(fx[0], fy[0], tx + xo, ty + yo, w->dtbl, 7, 0, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx + xo, ty + yo, w->dtbl, 7, 0, ui_scale); } if (v16 != 2) { ui_draw_line_ctbl(fx[2], fy[2], tx + xo, ty + yo, w->dtbl, 7, 0, ui_scale); } } ui_battle_draw_item(bt, attacker_i, b->sx * 32, b->sy * 24); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } } if (bt->s[SIDE_L].flag_auto && bt->s[SIDE_R].flag_auto) { return; } frames = 4; for (int f = 0; f < frames; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); if (v16 > 1) { ui_battle_draw_beam_line(fx[0], fy[0], tx + xo, ty + yo, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx + xo, ty + yo, f * 25 + 25, 100, w->v24, w->dtbl); } if (v16 != 2) { ui_battle_draw_beam_line(fx[2], fy[2], tx + xo, ty + yo, f * 25 + 25, 100, w->v24, w->dtbl); } ui_battle_draw_item(bt, attacker_i, b->sx * 32, b->sy * 24); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } } static void ui_battle_draw_beam_attack_do2(const struct battle_s *bt, int *fx, int *fy, int tx, int ty, weapon_t wpnt, int attacker_i, int target_i, int v16) { /*btype = 5*/ const struct battle_item_s *b = &(bt->item[attacker_i]); const struct shiptech_weap_s *w = &(tbl_shiptech_weap[wpnt]); int y_ns, x_ns, frames = 4; y_ns = game_battle_get_xy_notsame(bt, attacker_i, target_i, &x_ns); for (int f = 0; f < frames; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 1); ui_battle_draw_bottom(bt); if (v16 > 1) { ui_battle_draw_beam_line(fx[0], fy[0], tx, ty, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx - y_ns, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx + y_ns, ty + x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx, ty, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - y_ns, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx + y_ns, ty + x_ns, 0, f * 25 + 25, w->v24, w->dtbl); /*if (btype == 5) always true*/ ui_battle_draw_beam_line(fx[0], fy[0], tx - y_ns * 2, ty - x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx + y_ns * 2, ty + x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - y_ns * 2, ty - x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx + y_ns * 2, ty + x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); if ((y_ns == 1) && (x_ns == 1)) { ui_battle_draw_beam_line(fx[0], fy[0], tx, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx - x_ns, ty, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - x_ns, ty, 0, f * 25 + 25, w->v24, w->dtbl); } } /*5435b*/ if (v16 != 2) { ui_battle_draw_beam_line(fx[2], fy[2], tx, ty, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx - y_ns, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx + y_ns, ty + x_ns, 0, f * 25 + 25, w->v24, w->dtbl); /*if (btype == 5) always true*/ ui_battle_draw_beam_line(fx[2], fy[2], tx - y_ns * 2, ty - x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx + y_ns * 2, ty + x_ns * 2, 0, f * 25 + 25, w->v24, w->dtbl); if ((y_ns == 1) && (x_ns == 1)) { ui_battle_draw_beam_line(fx[2], fy[2], tx, ty - x_ns, 0, f * 25 + 25, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx - x_ns, ty, 0, f * 25 + 25, w->v24, w->dtbl); } } /*5450f*/ ui_battle_draw_item(bt, attacker_i, b->sx * 32, b->sy * 24); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } /*5455f*/ for (int f = 0; f < 7; ++f) { ui_delay_prepare(); if ((w->v24 == 2) || (w->v24 == 4)) { if (v16 > 1) { ui_draw_line_ctbl(fx[0], fy[0], tx, ty, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[0], fy[0], tx - y_ns, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[0], fy[0], tx + y_ns, ty + x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx, ty, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx - y_ns, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx + y_ns, ty + x_ns, w->dtbl, 7, 6 - f, ui_scale); /*if (btype == 5) always true*/ ui_draw_line_ctbl(fx[0], fy[0], tx - y_ns * 2, ty - x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[0], fy[0], tx + y_ns * 2, ty + x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx - y_ns * 2, ty - x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx + y_ns * 2, ty + x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); if ((y_ns == 1) && (x_ns == 1)) { ui_draw_line_ctbl(fx[0], fy[0], tx, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[0], fy[0], tx - x_ns, ty, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[1], fy[1], tx - x_ns, ty, w->dtbl, 7, 6 - f, ui_scale); } } /*54879*/ if (v16 != 2) { ui_draw_line_ctbl(fx[2], fy[2], tx, ty, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[2], fy[2], tx - y_ns, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[2], fy[2], tx + y_ns, ty + x_ns, w->dtbl, 7, 6 - f, ui_scale); /*if (btype == 5) always true*/ ui_draw_line_ctbl(fx[2], fy[2], tx - y_ns * 2, ty - x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[2], fy[2], tx + y_ns * 2, ty + x_ns * 2, w->dtbl, 7, 6 - f, ui_scale); if ((y_ns == 1) && (x_ns == 1)) { ui_draw_line_ctbl(fx[2], fy[2], tx, ty - x_ns, w->dtbl, 7, 6 - f, ui_scale); ui_draw_line_ctbl(fx[2], fy[2], tx - x_ns, ty, w->dtbl, 7, 6 - f, ui_scale); } } } else { /*549fc*/ uint8_t c = w->dtbl[0]; if (v16 > 1) { ui_draw_line1(fx[0], fy[0], tx, ty, c, ui_scale); ui_draw_line1(fx[0], fy[0], tx - y_ns, ty - x_ns, c, ui_scale); ui_draw_line1(fx[0], fy[0], tx + y_ns, ty + x_ns, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx, ty, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx - y_ns, ty - x_ns, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx + y_ns, ty + x_ns, c, ui_scale); /*if (btype == 5) always true*/ ui_draw_line1(fx[0], fy[0], tx - y_ns * 2, ty - x_ns * 2, c, ui_scale); ui_draw_line1(fx[0], fy[0], tx + y_ns * 2, ty + x_ns * 2, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx - y_ns * 2, ty - x_ns * 2, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx + y_ns * 2, ty + x_ns * 2, c, ui_scale); if ((y_ns == 1) && (x_ns == 1)) { ui_draw_line1(fx[0], fy[0], tx, ty - x_ns, c, ui_scale); ui_draw_line1(fx[0], fy[0], tx - x_ns, ty, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx, ty - x_ns, c, ui_scale); ui_draw_line1(fx[1], fy[1], tx - x_ns, ty, c, ui_scale); } } /*54cb2*/ if (v16 != 2) { ui_draw_line1(fx[2], fy[2], tx, ty, c, ui_scale); ui_draw_line1(fx[2], fy[2], tx - y_ns, ty - x_ns, c, ui_scale); ui_draw_line1(fx[2], fy[2], tx + y_ns, ty + x_ns, c, ui_scale); /*if (btype == 5) always true*/ ui_draw_line1(fx[2], fy[2], tx - y_ns * 2, ty - x_ns * 2, c, ui_scale); ui_draw_line1(fx[2], fy[2], tx + y_ns * 2, ty + x_ns * 2, c, ui_scale); if ((y_ns == 1) && (x_ns == 1)) { ui_draw_line1(fx[2], fy[2], tx, ty - x_ns, c, ui_scale); ui_draw_line1(fx[2], fy[2], tx - x_ns, ty, c, ui_scale); } } } /*54e1d*/ ui_battle_draw_item(bt, attacker_i, b->sx * 32, b->sy * 24); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } /*54e6b*/ if (bt->s[SIDE_L].flag_auto && bt->s[SIDE_R].flag_auto) { return; } for (int f = 0; f < frames; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); if (v16 > 1) { ui_battle_draw_beam_line(fx[0], fy[0], tx, ty, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx - y_ns, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx + y_ns, ty + x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx, ty, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - y_ns, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx + y_ns, ty + x_ns, f * 25 + 25, 100, w->v24, w->dtbl); /*if (btype == 5) always true*/ ui_battle_draw_beam_line(fx[0], fy[0], tx - y_ns * 2, ty - x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx + y_ns * 2, ty + x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - y_ns * 2, ty - x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx + y_ns * 2, ty + x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); if ((y_ns == 1) && (x_ns == 1)) { ui_battle_draw_beam_line(fx[0], fy[0], tx, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[0], fy[0], tx - x_ns, ty, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[1], fy[1], tx - x_ns, ty, f * 25 + 25, 100, w->v24, w->dtbl); } } if (v16 != 2) { ui_battle_draw_beam_line(fx[2], fy[2], tx, ty, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx - y_ns, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx + y_ns, ty + x_ns, f * 25 + 25, 100, w->v24, w->dtbl); /*if (btype == 5) always true*/ ui_battle_draw_beam_line(fx[2], fy[2], tx - y_ns * 2, ty - x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx + y_ns * 2, ty + x_ns * 2, f * 25 + 25, 100, w->v24, w->dtbl); if ((y_ns == 1) && (x_ns == 1)) { ui_battle_draw_beam_line(fx[2], fy[2], tx, ty - x_ns, f * 25 + 25, 100, w->v24, w->dtbl); ui_battle_draw_beam_line(fx[2], fy[2], tx - x_ns, ty, f * 25 + 25, 100, w->v24, w->dtbl); } } uiobj_finish_frame(); ui_delay_ticks_or_click(1); } } static void ui_battle_draw_stasis_sub1(const struct battle_s *bt, int target_i, int frame) { const struct battle_item_s *b = &(bt->item[target_i]); int x, y; x = b->sx * 32; y = b->sy * 24; lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.ship_p1); if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.ship_p1); } gfx_aux_setup_wh(&ui_data.aux.btemp, 34, 26); gfx_aux_setup_wh(&ui_data.aux.ship_overlay, 34, 26); gfx_aux_overlay(1, 1, &ui_data.aux.ship_overlay, &ui_data.aux.ship_p1); gfx_aux_color_non0(&ui_data.aux.ship_p1, 0xc4); gfx_aux_overlay(0, 0, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(0, 1, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(0, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(1, 0, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(1, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); /*gfx_aux_overlay(1, 0, &ui_data.aux.btemp, &ui_data.aux.ship_p1); FIXME should be 2, 0 ? */ gfx_aux_overlay(2, 1, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(2, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.ship_p1); if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.ship_p1); } /*4c5fa*/ { const uint8_t ctbl[5] = { 0x18, 0x16, 0x14, 0x13, 0x12 }; gfx_aux_recolor_ctbl(&ui_data.aux.ship_p1, ctbl, 5); } gfx_aux_overlay(1, 1, &ui_data.aux.btemp, &ui_data.aux.ship_p1); lbxgfx_set_new_frame(ui_data.gfx.space.circle, frame - 5); gfx_aux_draw_frame_to(ui_data.gfx.space.circle, &ui_data.aux.ship_p1); gfx_aux_overlay_clear_unused(1, 1, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(0, 0, &ui_data.aux.ship_overlay, &ui_data.aux.btemp); gfx_aux_draw_frame_from_limit(x, y, &ui_data.aux.ship_overlay, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); if (b->num > 0) { lbxfont_set_temp_color(0); lbxfont_select_set_12_4(2, 0xd, 0, 0); if (b->side == SIDE_L) { lbxfont_print_num_right(x + 29, y + 18, b->num, UI_SCREEN_W, ui_scale); } else { lbxfont_print_num_normal(x + 3, y + 18, b->num, UI_SCREEN_W, ui_scale); } } } static void ui_battle_draw_colony_destroyed_cb(void *vptr) { ui_draw_copy_buf(); ui_draw_textbox_2str("", game_str_bt_coldest, 74, ui_scale); } /* -------------------------------------------------------------------------- */ ui_battle_autoresolve_t ui_battle_init(struct battle_s *bt) { static struct ui_battle_data_s ctx; /* HACK */ memset(&ctx, 0, sizeof(ctx)); bt->uictx = &ctx; ctx.bt = bt; ctx.show_switch = (bt->g->gaux->local_players > 1); if (ctx.show_switch) { ui_switch_2(bt->g, bt->s[SIDE_L].party, bt->s[SIDE_R].party); } ui_sound_play_music(8); { ui_battle_autoresolve_t ar = ui_battle_pre(bt->g, bt, ctx.show_switch, SIDE_NONE); if (ar != UI_BATTLE_AUTORESOLVE_OFF) { return ar; } } /* ui_battle_do_sub1: */ uiobj_set_callback_and_delay(ui_battle_draw_cb, bt, 2); ctx.cursor[0].cursor_i = 1; ctx.cursor[0].x1 = UI_SCREEN_W - 1; ctx.cursor[0].y1 = UI_SCREEN_H - 1; ui_battle_clear_ois(&ctx); ctx.oi_ai = UIOBJI_INVALID; /* from ui_battle_do: */ ctx.gfx_bg = ui_data.gfx.space.bg[bt->g->planet[bt->planet_i].battlebg]; ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_bottom_no_ois(bt); { const planet_t *p = &(bt->g->planet[bt->planet_i]); ui_battle_transition_to(p->x, p->y, 10 * 3); /* FIXME BUG? x,y not in screen coords */ } return UI_BATTLE_AUTORESOLVE_OFF; } void ui_battle_shutdown(struct battle_s *bt, bool colony_destroyed, int winner) { struct ui_battle_data_s *d = bt->uictx; ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); uiobj_set_help_id(-1); if (colony_destroyed && (!bt->autoresolve)) { bool flag_done = false; uiobj_set_callback_and_delay(ui_battle_draw_colony_destroyed_cb, 0, 1); ui_draw_copy_buf(); uiobj_finish_frame(); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); while (!flag_done) { ui_delay_prepare(); if (uiobj_handle_input_cond() != 0) { flag_done = true; } ui_battle_draw_colony_destroyed_cb(0); ui_draw_finish(); ui_delay_ticks_or_click(3); } } /*128c7*/ uiobj_unset_callback(); uiobj_table_clear(); if (bt->autoresolve) { ui_battle_pre(bt->g, bt, d->show_switch, winner); } ui_sound_stop_music(); if (!bt->autoresolve) { ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; } } void ui_battle_draw_planetinfo(const struct battle_s *bt, bool side_r) { const struct battle_item_s *b = &(bt->item[0/*planet*/]); int x = 100, y = 50; uiobj_unset_callback(); uiobj_table_clear(); ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_bottom_no_ois(bt); ui_draw_filled_rect(x, y, x + 131, y + 37, 0x3a, ui_scale); ui_draw_filled_rect(x + 85, y + 4, x + 131, y + 37, 0, ui_scale); lbxgfx_draw_frame(x, y, ui_data.gfx.space.vp2_top, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(x + 90, y + 9, b->gfx, UI_SCREEN_W, ui_scale); lbxfont_select(1, 0xa, 0, 0); lbxfont_print_str_center(x + 44, y + 7, b->name, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xa, 0, 0); lbxfont_print_str_normal(x + 7, y + 21, game_str_bt_pop, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x + 7, y + 30, game_str_bt_ind, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x + 60, y + 21, ":", UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 80, y + 21, bt->pop, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x + 60, y + 30, ":", UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 80, y + 30, bt->fact, UI_SCREEN_W, ui_scale); if (bt->s[bt->item[bt->cur_item].side].flag_have_scan || (side_r == (b->side == SIDE_R))) { int y1; ui_draw_filled_rect(x, y + 39, x + 131, y + 79, 0x3a, ui_scale); lbxgfx_draw_frame(x, y + 38, ui_data.gfx.space.vp2_data, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x + 68, y + 42, game_str_bt_bases, UI_SCREEN_W, ui_scale); if (bt->have_subspace_int) { ui_draw_filled_rect(x, y + 79, x + 131, y + 89, 0x3a, ui_scale); lbxgfx_draw_frame(x, y + 77, ui_data.gfx.space.vp2_line, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_normal(x + 10, y + 80, game_str_bt_subint, UI_SCREEN_W, ui_scale); y1 = y + 86; } else { y1 = y + 77; } lbxgfx_draw_frame(x, y1, ui_data.gfx.space.vp2_bottom, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); { char buf[80]; const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[0].t]); if ((!bt->s[b->side].flag_base_missile) && (w->nummiss == 1)) { w = &(tbl_shiptech_weap[b->wpn[1].t]); } lib_sprintf(buf, sizeof(buf), "3 %s %s", *w->nameptr, game_str_bt_launch); lbxfont_print_str_normal(x + 10, y + 71, buf, UI_SCREEN_W, ui_scale); } lbxfont_select(2, 0xb, 0, 0); lbxfont_print_num_right(x + 46, y + 51, b->defense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 46, y + 61, b->misdefense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 86, y + 51, b->complevel, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 86, y + 61, b->hp1, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 123, y + 51, b->hploss, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 124, y + 61, b->absorb, UI_SCREEN_W, ui_scale); } else { lbxgfx_draw_frame(x, y + 37, ui_data.gfx.space.vp2_bottom, UI_SCREEN_W, ui_scale); } uiobj_finish_frame(); ui_draw_copy_buf(); uiobj_input_wait(); uiobj_set_callback_and_delay(ui_battle_draw_cb, (void *)bt, 2); } void ui_battle_draw_scan(const struct battle_s *bt, bool side_r) { struct ui_battle_data_s *d = bt->uictx; d->flag_scanning = true; d->scan_side = side_r ? SIDE_R : SIDE_L; uiobj_unset_callback(); uiobj_table_clear(); ui_cursor_setup_area(1, &(d->cursor[0])); uiobj_set_help_id(0x23); uiobj_set_callback_and_delay(ui_battle_draw_scan_cb, (void *)bt, 2); uiobj_input_wait(); uiobj_unset_callback(); uiobj_set_help_id(7); uiobj_set_callback_and_delay(ui_battle_draw_cb, (void *)bt, 2); ui_cursor_setup_area(1 + BATTLE_AREA_W * BATTLE_AREA_H, &(d->cursor[0])); d->flag_scanning = false; } void ui_battle_draw_item(const struct battle_s *bt, int itemi, int x, int y) { const struct ui_battle_data_s *d = bt->uictx; const struct battle_item_s *b; b = &(bt->item[itemi]); if (b->selected && (!bt->s[b->side].flag_auto)) { if (b->selected != 2/*moving*/) { uint8_t *gfx; if ((b->sx != (BATTLE_AREA_W - 1)) && (!d->flag_scanning)) { gfx = (b->sy == (BATTLE_AREA_H - 1)) ? ui_data.gfx.space.box_y : ui_data.gfx.space.box; } else { gfx = (b->sy == (BATTLE_AREA_H - 1)) ? ui_data.gfx.space.box_xy : ui_data.gfx.space.box_x; } lbxgfx_set_frame_0(gfx); for (int i = 0; i <= d->frame_ship; ++i) { lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); } } if (b->side != SIDE_NONE) { lbxgfx_set_frame_0(b->gfx); for (int i = 0; i <= d->frame_ship; ++i) { gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.ship_p1); } } } else { /* FIXME no SIDE_NONE test? */ lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.ship_p1); } if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.ship_p1); } gfx_aux_setup_wh(&ui_data.aux.btemp, 34, 26); if (b->cloak == 1) { gfx_aux_draw_cloak(&ui_data.aux.ship_p1, 30, rnd_1_n(1000, &ui_data.seed)); } if (b->unman > 0) { int v = (b->unman * 100) / b->man; uint8_t *gfx; if (v > 75) { gfx = ui_data.gfx.space.warp4; } else if (v > 50) { gfx = ui_data.gfx.space.warp3; } else if (v > 25) { gfx = ui_data.gfx.space.warp2; } else { gfx = ui_data.gfx.space.warp1; } gfx_aux_draw_frame_to(gfx, &ui_data.aux.ship_overlay); gfx_aux_overlay_clear_unused(0, 0, &ui_data.aux.ship_overlay, &ui_data.aux.ship_p1); gfx_aux_overlay(0, 0, &ui_data.aux.ship_p1, &ui_data.aux.ship_overlay); } /*4fcf1*/ if (b->stasisby > 0) { const uint8_t ctbl[5] = { 0x18, 0x16, 0x14, 0x13, 0x12 }; gfx_aux_copy(&ui_data.aux.ship_overlay, &ui_data.aux.ship_p1); gfx_aux_recolor_ctbl(&ui_data.aux.ship_p1, ctbl, 5); gfx_aux_color_non0(&ui_data.aux.ship_overlay, 0xc4); gfx_aux_overlay(0, 0, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_overlay(0, 1, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_overlay(0, 2, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_overlay(1, 0, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_overlay(1, 2, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); /* BUG? 1,0 twice, no 2, 0 */ gfx_aux_overlay(2, 1, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_overlay(2, 2, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); } /*4fdf3*/ gfx_aux_overlay(1, 1, &ui_data.aux.btemp, &ui_data.aux.ship_p1); { int xa = x, ya = y; if (b->sbmask & (1 << SHIP_SPECIAL_BOOL_DISP)) { int xoff, yoff; xoff = rnd_0_nm1(5, &ui_data.seed) - 2; yoff = rnd_0_nm1(5, &ui_data.seed) - 2; xa += xoff; ya += yoff; } gfx_aux_draw_frame_from_limit(xa, ya, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } if (b->num > 0) { lbxfont_set_temp_color(0); lbxfont_select_set_12_4(2, 0xd, 0, 0); if (b->side == SIDE_L) { lbxfont_print_num_right(x + 29, y + 18, b->num, UI_SCREEN_W, ui_scale); } else { lbxfont_print_num_normal(x + 3, y + 18, b->num, UI_SCREEN_W, ui_scale); } } } void ui_battle_draw_arena(const struct battle_s *bt, int itemi, int dmode) { struct ui_battle_data_s *d = bt->uictx; d->frame_ship = (d->frame_ship + 1) % 5; d->frame_missile = (d->frame_missile + 1) % 4; ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, d->gfx_bg, UI_SCREEN_W, ui_scale); lbxfont_set_temp_color(0); lbxfont_select_set_12_4(2, 0xd, 0, 0); if (ui_extra_enabled && ui_data.battle.show_grid) { for (int x = 0; x < 10; ++x) { ui_draw_line1(x * 32, 0, x * 32, 24 * 8 - 1, 4, ui_scale); } for (int y = 0; y < 8; ++y) { ui_draw_line1(0, y * 24, 32 * 10 - 1, y * 24, 4, ui_scale); } } for (int i = 0; i <= bt->items_num; ++i) { if ((i != itemi) || (dmode == 0/*normal*/)) { const struct battle_item_s *b; b = &(bt->item[i]); if (b->side != SIDE_NONE) { ui_battle_draw_item(bt, i, b->sx * 32, b->sy * 24); } } } for (int i = 0; i < bt->num_rocks; ++i) { const struct battle_rock_s *r; r = &(bt->rock[i]); lbxgfx_draw_frame(r->sx * 32, r->sy * 24, r->gfx, UI_SCREEN_W, ui_scale); } for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); int8_t target; target = m->target; if ((target != MISSILE_TARGET_NONE) && ((target != itemi) || (dmode != 2/*hide target missile*/))) { const struct battle_item_s *b; b = &(bt->item[target]); ui_battle_draw_missile(bt, i, m->x, m->y, b->sx * 32 + 16, b->sy * 24 + 12); } } } void ui_battle_draw_misshield(const struct battle_s *bt, int target_i, int target_x, int target_y, int missile_i) { const struct battle_missile_s *m = &(bt->missile[missile_i]); int mx = m->x, my = m->y, target_x_hit, target_y_hit; const struct battle_item_s *b = &(bt->item[target_i]); { const struct firing_s *fr = &(bt->g->gaux->firing[b->look]); if (b->side == SIDE_R) { target_x_hit = target_x + 32 - fr->target_x; } else { target_x_hit = target_x + fr->target_x; } target_y_hit = target_y + fr->target_y; } if (b->misshield < 45) { const uint8_t colortbl[8] = { 0x1d, 0x42, 0x41, 0, 0, 0, 0x46, 0 }; for (int f = 0; f < 5; ++f) { ui_delay_prepare(); if (f == 3) { ui_sound_play_sfx(2); } ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom(bt); ui_battle_draw_item(bt, target_i, target_x, target_y); ui_draw_line_ctbl(target_x_hit, target_y_hit, mx, my, colortbl, 8, 0, ui_scale); if (f > 1) { gfx_aux_draw_frame_to(ui_data.gfx.space.explos[f - 2], &ui_data.aux.btemp); gfx_aux_scale(&ui_data.aux.btemp, 30, 30); gfx_aux_draw_frame_from(mx - 4, my - 4, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); } uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } else { uint8_t color = (b->misshield >= 90) ? 0xd6 : 0x46; for (int f = 0; f < 3; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.ship_overlay); if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.ship_overlay); } gfx_aux_setup_wh(&ui_data.aux.btemp, 38, 30); gfx_aux_copy(&ui_data.aux.ship_p1, &ui_data.aux.ship_overlay); gfx_aux_color_non0(&ui_data.aux.ship_p1, color); gfx_aux_overlay(3 - (f + 1), 3, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, f + 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, 3 - (f + 1), &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(f + 4, f + 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(f + 4, 3 - (f + 1), &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 - (f + 1), f + 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 - (f + 1), 3 - (f + 1), &ui_data.aux.btemp, &ui_data.aux.ship_p1); if (f > 0) { gfx_aux_copy(&ui_data.aux.ship_p1, &ui_data.aux.ship_overlay); gfx_aux_color_non0(&ui_data.aux.ship_p1, color - 4); gfx_aux_overlay(3 - f, 3, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 + f, 3, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, 3 + f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, 3 - f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 + f, 3 + f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 + f, 3 - f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 - f, 3 + f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3 - f, 3 - f, &ui_data.aux.btemp, &ui_data.aux.ship_p1); } if (f == 2) { gfx_aux_copy(&ui_data.aux.ship_p1, &ui_data.aux.ship_overlay); gfx_aux_color_non0(&ui_data.aux.ship_p1, 1); gfx_aux_overlay(2, 3, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(4, 3, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(3, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(4, 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(4, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(2, 4, &ui_data.aux.btemp, &ui_data.aux.ship_p1); gfx_aux_overlay(2, 2, &ui_data.aux.btemp, &ui_data.aux.ship_p1); } gfx_aux_overlay(3, 3, &ui_data.aux.btemp, &ui_data.aux.ship_overlay); gfx_aux_draw_frame_from_limit(target_x - 3, target_y - 3, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(5); } } ui_sound_stop_sfx(); } void ui_battle_draw_damage(const struct battle_s *bt, int target_i, int target_x, int target_y, uint32_t damage) { const struct battle_item_s *b = &(bt->item[target_i]); int target_x_hit, target_y_hit, si, v4, ax, ay, scale; bool flag_quick; si = (b->hp1 > 0) ? b->hp1 * 3 : 1; if ((b->num <= 0) || (si < damage)) { v4 = si; } else { v4 = damage; /* & 0xffff */ } if ((si / v4) >= 3) { v4 = si / 3 + 1; } scale = (v4 * 100) / si; ui_sound_play_sfx(((si / v4) < 3) ? 2 : 17); { const struct firing_s *fr = &(bt->g->gaux->firing[b->look]); if (b->side == SIDE_R) { target_x_hit = target_x + 32 - fr->target_x; } else { target_x_hit = target_x + fr->target_x; } target_y_hit = target_y + fr->target_y; } ax = target_x_hit - (v4 * 16) / si; ay = target_y_hit - (v4 * 15) / si; flag_quick = (bt->s[0].flag_auto && bt->s[1].flag_auto); for (int i = 0; i < (flag_quick ? 2 : 10); ++i) { int f; ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom_no_ois(bt); ui_battle_draw_item(bt, target_i, target_x, target_y); f = flag_quick ? (i * 2 + 4) : i; gfx_aux_draw_frame_to(ui_data.gfx.space.explos[f], &ui_data.aux.btemp); gfx_aux_scale(&ui_data.aux.btemp, scale, scale); gfx_aux_draw_frame_from_limit(ax, ay, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0, 0); lbxfont_print_num_center(target_x_hit, target_y_hit - 2, damage, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } } void ui_battle_draw_explos_small(const struct battle_s *bt, int x, int y) { gfx_aux_draw_frame_to(ui_data.gfx.space.explos[5], &ui_data.aux.btemp); gfx_aux_scale(&ui_data.aux.btemp, 30, 30); gfx_aux_draw_frame_from(x, y, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); } void ui_battle_draw_basic(const struct battle_s *bt) { ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_bottom(bt); uiobj_finish_frame(); } void ui_battle_draw_basic_copy(const struct battle_s *bt) { ui_battle_draw_basic(bt); ui_draw_copy_buf(); } void ui_battle_draw_finish(const struct battle_s *bt) { uiobj_finish_frame(); } void ui_battle_draw_missile(const struct battle_s *bt, int missilei, int x, int y, int tx, int ty) { const int8_t tbl_missile_off[MAX_VISIBLE_MISSILE][MAX_VISIBLE_MISSILE * 2/*x, y*/] = { { 0, 0 }, { -2, 0, 2, 0 }, { 0, -2, -3, 4, 3, 4 }, { -2, -2, 2, -2, 5, 2, -5, 2 }, { 0, -4, -3, 0, -6, 4, 6, 4, 3, 0 }, { 0, -4, -3, 0, -6, 4, 3, 0, 6, 4, 0, 4 }, { -2, -4, 2, -4, -5, 0, 5, 0, -8, 4, 0, 4, 8, 4 }, { 0, 5, -9, 0, 6, 2, 9, 0, 0, -6, 3, -2, -6, 2, -3, -2 }, { -2, -6, 2, -6, -5, -2, 5, -2, -8, 2, 0, 2, 8, 2, -4, 6, 4, 6 }, { 0, -7, -3, -3, -6, 1, 3, -3, 6, 1, 0, 1, -3, 5, -9, 5, 3, 5, 9, 5 } }; struct ui_battle_data_s *d = bt->uictx; const struct battle_missile_s *m = &(bt->missile[missilei]); const struct shiptech_weap_s *w = &(tbl_shiptech_weap[m->wpnt]); int extradiv = 0, angle, dir, nummissiles = m->nummissiles, axoff = 0, ayoff = 0; uint8_t *gfx; angle = util_math_calc_angle(tx - x, ty - y); if ((angle >= 337) || (angle < 22)) { dir = 2; angle = 0; } else if ((angle >= 22) && (angle < 67)) { dir = 3; angle = 45; } else if ((angle >= 67) && (angle < 112)) { dir = 4; angle = 90; } else if ((angle >= 112) && (angle < 157)) { dir = 5; angle = 135; } else if ((angle >= 157) && (angle < 202)) { dir = 6; angle = 180; } else if ((angle >= 202) && (angle < 247)) { dir = 7; angle = 225; } else if ((angle >= 247) && (angle < 292)) { dir = 0; angle = 270; } else /*if ((angle >= 292) && (angle < 337))*/ { dir = 1; angle = 315; } switch (w->misstype) { default: case 0: gfx = ui_data.gfx.missile.missiles[dir]; break; case 1: gfx = ui_data.gfx.missile.antimatr[dir]; break; case 2: gfx = ui_data.gfx.missile.hellfire[dir]; extradiv = 2; nummissiles /= 4; break; case 3: gfx = ui_data.gfx.missile.proton[dir]; extradiv = 2; nummissiles /= 4; break; case 4: gfx = ui_data.gfx.missile.plasmaqt[dir]; lbxgfx_set_new_frame(gfx, d->frame_missile); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx = 0; { int v; v = w->damagemax - (((w->v24 - m->fuel) * w->dtbl[0] + (w->dtbl[0] - m->speed))) / 2; /* FIXME check this calc */ if (v < 0) { v = 0; /*m->target = -1; XXX moved to game */ } v = (v * 100) / w->damagemax; gfx_aux_scale(&ui_data.aux.btemp, v, v); } extradiv = 10000; axoff = -1; ayoff = -1; break; } if (gfx) { lbxgfx_set_new_frame(gfx, d->frame_missile); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); } nummissiles /= 10; SETMIN(nummissiles, MAX_VISIBLE_MISSILE); if (extradiv) { nummissiles /= extradiv; } SETMAX(nummissiles, 1); angle = (angle + 90) % 360; /* FIXME set the correct angle in the if chain, it is not used between */ for (int i = 0; i < nummissiles; ++i) { int xoff, yoff; if ((extradiv > 0) && (extradiv != 10000) && ((i & 1) != 0)) { continue; } xoff = util_math_angle_dist_cos(angle, tbl_missile_off[nummissiles - 1][i * 2 + 0]) - util_math_angle_dist_sin(angle, tbl_missile_off[nummissiles - 1][i * 2 + 1]) + axoff - 3; yoff = util_math_angle_dist_cos(angle, tbl_missile_off[nummissiles - 1][i * 2 + 1]) + util_math_angle_dist_sin(angle, tbl_missile_off[nummissiles - 1][i * 2 + 0]) + ayoff - 3; gfx_aux_draw_frame_from_limit(x + xoff, y + yoff, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } } void ui_battle_draw_bomb_attack(const struct battle_s *bt, int attacker_i, int target_i, ui_battle_bomb_t bombtype) { uint8_t *gfx; int x, y, x0, y0, x1, y1; switch (bombtype) { default: case UI_BATTLE_BOMB_BOMB: gfx = ui_data.gfx.space.bombs; break; case UI_BATTLE_BOMB_BIO: gfx = ui_data.gfx.space.biologic; break; case UI_BATTLE_BOMB_WARPDIS: gfx = ui_data.gfx.space.dis_bem2; break; } lbxgfx_set_frame_0(gfx); { const struct battle_item_s *b; const struct firing_s *fr = &(bt->g->gaux->firing[0]); b = &(bt->item[attacker_i]); x = b->sx * 32; y = b->sy * 24; x0 = x + fr[b->look].target_x; y0 = y + fr[b->look].target_y; b = &(bt->item[target_i]); x1 = b->sx * 32 + fr[b->look].target_x; y1 = b->sy * 24 + fr[b->look].target_y; } for (int f = 0; f < 10; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); ui_battle_draw_item(bt, attacker_i, x, y); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_beam_attack(const struct battle_s *bt, int attacker_i, int target_i, int wpni) { const struct battle_item_s *b = &(bt->item[attacker_i]); const struct battle_item_s *b2 = &(bt->item[target_i]); const struct firing_s *fr = &(bt->g->gaux->firing[0]); weapon_t wpnt = b->wpn[wpni].t; uint8_t btype = tbl_shiptech_weap[wpnt].v24; int v16, fx[3], fy[3], tx, ty; bool dir = false; v16 = (b->wpn[wpni].n + 1) / 2; SETMIN(v16, 3); if (b->side == SIDE_R) { if (b->sx < b2->sx) { dir = true; } for (int i = 0; i < 3; ++i) { fx[i] = b->sx * 32 + 31 - game_aux_get_firing_param_x(bt->g->gaux, b->look, i + 1, dir); } tx = b2->sx * 32 + fr[b2->look].target_x; } else { /*53d58*/ if (b->sx > b2->sx) { dir = true; } for (int i = 0; i < 3; ++i) { fx[i] = b->sx * 32 + game_aux_get_firing_param_x(bt->g->gaux, b->look, i + 1, dir); } tx = b2->sx * 32 + 31 - fr[b2->look].target_x; } /*53e5c*/ for (int i = 0; i < 3; ++i) { fy[i] = b->sy * 24 + game_aux_get_firing_param_y(bt->g->gaux, b->look, i + 1, dir); } ty = b2->sy * 24 + fr[b2->look].target_y; switch (btype) { default: /* 0..3 */ if (btype == 2) { btype = 3; } ui_battle_draw_beam_attack_do1(bt, fx, fy, tx, ty, wpnt, attacker_i, v16, btype); break; case 4: ui_battle_draw_beam_attack_do2(bt, fx, fy, tx, ty, wpnt, attacker_i, target_i, v16); break; } } void ui_battle_draw_stasis(const struct battle_s *bt, int attacker_i, int target_i) { uint8_t *gfx = ui_data.gfx.space.stasis2; int x, y, x0, y0, x1, y1; lbxgfx_set_frame_0(gfx); { const struct battle_item_s *b; const struct firing_s *fr = &(bt->g->gaux->firing[0]); b = &(bt->item[attacker_i]); x0 = b->sx * 32 + fr[b->look].target_x; y0 = b->sy * 24 + fr[b->look].target_y; b = &(bt->item[target_i]); x = b->sx * 32; y = b->sy * 24; x1 = x + fr[b->look].target_x; y1 = y + fr[b->look].target_y; } for (int f = 0; f < 10; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); if (f > 4) { ui_battle_draw_stasis_sub1(bt, target_i, f); } else { ui_battle_draw_item(bt, target_i, x, y); } uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_pulsar(const struct battle_s *bt, int attacker_i, int ptype, const uint32_t *dmgtbl) { const uint8_t ctbl[5] = { 0x25, 0x40, 0x42, 0x44, 0x46 }; uint8_t *gfx = ui_data.gfx.space.sphere2; const struct firing_s *fr = &(bt->g->gaux->firing[0]); int x, y; lbxgfx_set_frame_0(gfx); { const struct battle_item_s *b; b = &(bt->item[attacker_i]); x = b->sx * 32; y = b->sy * 24; } for (int f = 0; f < 13; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); if (f < 6) { gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); if (ptype == 1) { gfx_aux_recolor_ctbl(&ui_data.aux.btemp, ctbl, 5); } gfx_aux_scale(&ui_data.aux.btemp, f * 10 + 50, f * 10 + 50); gfx_aux_draw_frame_from_limit(x - (f + 1) * 5, y - (f + 1) * 4, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } /*4cd27*/ if (f > 2) { gfx_aux_draw_frame_to(ui_data.gfx.space.explos[f - 3], &ui_data.aux.btemp); gfx_aux_scale(&ui_data.aux.btemp, 80, 80); for (int i = 0; i <= bt->items_num; ++i) { if (dmgtbl[i] > 0) { const struct battle_item_s *b = &(bt->item[i]); int x1, y1; if (b->side == SIDE_R) { x1 = b->sx * 32 + 32 - fr[b->look].target_x; /* FIXME usually + 31 - */ } else { x1 = b->sx * 32 + fr[b->look].target_x; } y1 = b->sy * 24 + fr[b->look].target_y; gfx_aux_draw_frame_from_limit(x1 - 13, y1 - 12, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0, 0); lbxfont_print_num_center(x1, y1 - 2, dmgtbl[i], UI_SCREEN_W, ui_scale); } } } uiobj_finish_frame(); ui_delay_ticks_or_click(1); } } void ui_battle_draw_stream1(const struct battle_s *bt, int attacker_i, int target_i) { const uint8_t ctbl[5] = { 0x25, 0x40, 0x42, 0x44, 0x46 }; uint8_t *gfx = ui_data.gfx.space.dis_bem2; int x, y, x0, y0, x1, y1; lbxgfx_set_frame_0(gfx); { const struct battle_item_s *b; const struct firing_s *fr = &(bt->g->gaux->firing[0]); b = &(bt->item[attacker_i]); x = b->sx * 32; y = b->sy * 24; x0 = x + fr[b->look].target_x; y0 = y + fr[b->look].target_y; b = &(bt->item[target_i]); x1 = b->sx * 32 + fr[b->look].target_x; y1 = b->sy * 24 + fr[b->look].target_y; } for (int f = 0; f < 10; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_recolor_ctbl(&ui_data.aux.btemp, ctbl, 5); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); ui_battle_draw_item(bt, attacker_i, x, y); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_stream2(const struct battle_s *bt, int attacker_i, int target_i) { const struct battle_item_s *b; uint8_t *gfx = ui_data.gfx.space.enviro; int x, y, x0, y0, x1, y1; lbxgfx_set_frame_0(gfx); { const struct firing_s *fr = &(bt->g->gaux->firing[0]); b = &(bt->item[attacker_i]); x = b->sx * 32; y = b->sy * 24; x0 = x + fr[b->look].target_x; y0 = y + fr[b->look].target_y; b = &(bt->item[target_i]); x1 = b->sx * 32 + fr[b->look].target_x; y1 = b->sy * 24 + fr[b->look].target_y; } for (int f = 0; f < 15; ++f) { ui_delay_prepare(); if (f < 10) { ui_battle_draw_arena(bt, attacker_i, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_draw_frame_from_rotate_limit(x0, y0, x1, y1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); ui_battle_draw_item(bt, attacker_i, x, y); } /*4c06a*/ if (f >= 10) { ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); } if (f > 7) { int s, x2, y2; gfx_aux_draw_frame_to(ui_data.gfx.space.envterm, &ui_data.aux.btemp); if (f < 11) { s = (100 * (f - 7)) / 4; x2 = b->sx * 32 + 12 - (f - 8) * 4; y2 = b->sy * 24 + 9 - (f - 8) * 3; } else { /*4c11d*/ s = (100 * (16 - f)) / 4; x2 = b->sx * 32 + (f - 12) * 4; y2 = b->sy * 24 + (f - 12) * 3; } gfx_aux_scale(&ui_data.aux.btemp, s, s); gfx_aux_draw_frame_from_limit(x2, y2, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } /*4c19d*/ uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_retreat(const struct battle_s *bt) { int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); uint8_t *gfx = ui_data.gfx.space.warpout; int x = b->sx * 32, y = b->sy * 24, /*di*/xf, yf; { const struct firing_s *fr = &(bt->g->gaux->firing[b->look]); if (b->side == SIDE_L) { xf = 32 - fr->target_x; } else { xf = fr->target_x; } yf = fr->target_y; } ui_sound_play_sfx(0x13); for (int f = 0; f < 4; ++f) { int s, x1; ui_delay_prepare(); ui_battle_draw_arena(bt, itemi, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); s = (f + 1) * (100 / 5); gfx_aux_scale(&ui_data.aux.btemp, s, s); if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.btemp); x1 = x + 16 - f * 4; } else { /*4da3c*/ x1 = x + (4 - f) * 3; } gfx_aux_draw_frame_from(x1, y + (4 - f) * 3, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.btemp); if (b->side == SIDE_L) { gfx_aux_flipx(&ui_data.aux.btemp); } gfx_aux_draw_frame_from_limit(x, y, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } for (int f = 0; f < 10; ++f) { int s, x1, y1; ui_delay_prepare(); ui_battle_draw_arena(bt, itemi, 1); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); if (b->side == SIDE_R) { gfx_aux_flipx(&ui_data.aux.btemp); } s = 100 - (f * 5); gfx_aux_scale(&ui_data.aux.btemp, s, s); gfx_aux_draw_frame_from(x + f / 2, y + (f * 3) / 5, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.btemp); s = 100 - (f * 10); gfx_aux_scale(&ui_data.aux.btemp, s, s); if (b->side == SIDE_L) { gfx_aux_flipx(&ui_data.aux.btemp); x1 = x; } else { x1 = x + (xf * 2 * f * 10) / 100; } y1 = y + (f * yf * 10) / 100; gfx_aux_draw_frame_from_limit(x1, y1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_blackhole(const struct battle_s *bt, int attacker_i, int target_i) { const uint8_t ctbl[5] = { 0xd8, 0xd4, 0xd3, 0xd2, 0xd1 }; const struct battle_item_s *b = &(bt->item[attacker_i]); const struct battle_item_s *bd = &(bt->item[target_i]); uint8_t *gfx = ui_data.gfx.space.blk_hole; int x, y, x2, y2, x0, y0, x1, y1, x_ns, y_ns; lbxgfx_set_frame_0(gfx); { const struct firing_s *fr = &(bt->g->gaux->firing[0]); x = b->sx * 32; y = b->sy * 24; x2 = bd->sx * 32; y2 = bd->sy * 24; /* FIXME both have the same + 31 - flip ?? */ if (b->side == SIDE_R) { x0 = x + 31 - fr[b->look].target_x; x1 = x2 + 32 - fr[bd->look].target_x; /* FIXME usually + 31 - */ } else { x0 = x + fr[b->look].target_x; x1 = x2 + fr[bd->look].target_x; } y0 = y + fr[b->look].target_y; y1 = y2 + fr[bd->look].target_y; } y_ns = game_battle_get_xy_notsame(bt, attacker_i, target_i, &x_ns); for (int f = 0; f < 16; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); if (f < 5) { ui_draw_line_ctbl(x0, y0, x1, y1, ctbl, 5, f, ui_scale); ui_draw_line_ctbl(x0, y0, x1 - y_ns, y1 - x_ns, ctbl, 5, (f + 1) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, x1 + y_ns, y1 + x_ns, ctbl, 5, (f + 2) % 5, ui_scale); } if (f > 3) { gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_draw_frame_from(x2 + 5, y2 + 3, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); } uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_technull(const struct battle_s *bt, int attacker_i, int target_i) { const struct battle_item_s *b = &(bt->item[attacker_i]); const struct battle_item_s *bd = &(bt->item[target_i]); uint8_t *gfx = ui_data.gfx.space.technull; int x, y, x2, y2, x0, y0, x1, y1, dist; { const struct firing_s *fr = &(bt->g->gaux->firing[0]); x = b->sx * 32; y = b->sy * 24; x2 = bd->sx * 32; y2 = bd->sy * 24; x0 = x + fr[b->look].target_x; y0 = y + fr[b->look].target_y; x1 = x2 + fr[bd->look].target_x; y1 = y2 + fr[bd->look].target_y; } dist = util_math_dist_fast(x0, y0, x1, y1); dist = (dist + 3) / 4; for (int f = 0; f < dist; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 0); ui_battle_draw_bottom(bt); if ((f & 1) == 0) { lbxgfx_set_frame_0(gfx); } gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); util_math_go_line_dist(&x0, &y0, x1, y1, 4); gfx_aux_draw_frame_from_limit(x0 - 16, y0 - 12, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(1); } lbxgfx_set_frame_0(gfx); for (int f = 0; f < 10; ++f) { ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 0); ui_battle_draw_bottom(bt); gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); gfx_aux_draw_frame_from_limit(x2, y2, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_repulse(const struct battle_s *bt, int attacker_i, int target_i, int sx, int sy) { const uint8_t ctbl[5] = { 0x71, 0x70, 0x6f, 0x6e, 0x6d }; const struct battle_item_s *b = &(bt->item[attacker_i]); const struct battle_item_s *bd = &(bt->item[target_i]); int numsteps = (bt->s[SIDE_L].flag_auto && bt->s[SIDE_R].flag_auto) ? 2 : 8; int tx = bd->sx * 32, ty = bd->sy * 24, x0, y0, fx, fy, tdx, tdy, xstep, ystep, xo = 1, yo = 0; { const struct firing_s *fa = &(bt->g->gaux->firing[b->look]); const struct firing_s *fd = &(bt->g->gaux->firing[bd->look]); if (b->side == SIDE_R) { fx = fd->target_x; x0 = b->sx * 32 + 31 - fa->target_x; } else { fx = 31 - fd->target_x; x0 = b->sx * 32 + fa->target_x; } fy = fd->target_y; y0 = b->sy * 24 + fa->target_y; } tdx = sx - bd->sx; tdy = sy - bd->sy; if (tdx == 0) { xstep = 0; xo = 1; } else { xstep = (tdx * (32 / numsteps)) / abs(tdx); } if (tdy == 0) { ystep = 0; yo = 0; } else { ystep = (tdy * (24 / numsteps)) / abs(tdy); } if ((tdx - tdy) == 0) { xo = -1; } ui_sound_play_sfx(0x13); for (int i = 0; i < numsteps; ++i) { ui_delay_prepare(); ui_battle_draw_arena(bt, attacker_i, 0); ui_battle_draw_bottom(bt); ui_draw_line_ctbl(x0, y0, tx + fx, ty + fy, ctbl, 5, i % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo, ty + fy - xo, ctbl, 5, (i + 1) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo, ty + fy + xo, ctbl, 5, (i + 2) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo * 2, ty + fy - xo * 2, ctbl, 5, (i + 3) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo * 2, ty + fy + xo * 2, ctbl, 5, (i + 4) % 5, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } for (int i = 0; i < numsteps; ++i) { ui_delay_prepare(); tx += xstep; ty += ystep; ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom(bt); ui_battle_draw_item(bt, target_i, tx, ty); ui_draw_line_ctbl(x0, y0, tx + fx, ty + fy, ctbl, 5, i % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo, ty + fy - xo, ctbl, 5, (i + 1) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo, ty + fy + xo, ctbl, 5, (i + 2) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo * 2, ty + fy - xo * 2, ctbl, 5, (i + 3) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo * 2, ty + fy + xo * 2, ctbl, 5, (i + 4) % 5, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } /* MOO1 sets bd->sx,sy here, we avoid modifying bt in ui/ */ for (int i = 0; i < numsteps; ++i) { ui_delay_prepare(); ui_battle_draw_arena(bt, target_i, 1); ui_battle_draw_bottom(bt); ui_battle_draw_item(bt, target_i, sx * 32, sy * 24); ui_draw_line_ctbl(x0, y0, tx + fx, ty + fy, ctbl, 5, i % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo, ty + fy - xo, ctbl, 5, (i + 1) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo, ty + fy + xo, ctbl, 5, (i + 2) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx - yo * 2, ty + fy - xo * 2, ctbl, 5, (i + 3) % 5, ui_scale); ui_draw_line_ctbl(x0, y0, tx + fx + yo * 2, ty + fy + xo * 2, ctbl, 5, (i + 4) % 5, ui_scale); uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_cloaking(const struct battle_s *bt, int from, int to, int sx, int sy) { int step = (from <= to) ? 10 : -10; const struct battle_item_s *b = &(bt->item[bt->cur_item]); for (int i = from; i != to; i += step) { ui_delay_prepare(); ui_battle_draw_arena(bt, bt->cur_item, 1); ui_battle_draw_bottom(bt); lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.btemp); if (b->side != SIDE_L) { gfx_aux_flipx(&ui_data.aux.btemp); } gfx_aux_draw_cloak(&ui_data.aux.btemp, i, rnd_1_n(1000, &ui_data.seed)); gfx_aux_draw_frame_from_limit(b->sx * 32 + 1, b->sy * 24 + 1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); if (sx >= 0) { lbxgfx_set_frame_0(b->gfx); gfx_aux_draw_frame_to(b->gfx, &ui_data.aux.btemp); if (b->side != SIDE_L) { gfx_aux_flipx(&ui_data.aux.btemp); } gfx_aux_draw_cloak(&ui_data.aux.btemp, from - i, rnd_1_n(1000, &ui_data.seed)); gfx_aux_draw_frame_from_limit(sx * 32 + 1, sy * 24 + 1, &ui_data.aux.btemp, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } uiobj_finish_frame(); ui_delay_ticks_or_click(2); } } void ui_battle_draw_bottom(const struct battle_s *bt) { if (bt->s[bt->item[bt->cur_item].side].flag_auto) { ui_battle_draw_bottom_no_ois(bt); } else { ui_battle_draw_bottom_add_ois(bt); ui_battle_draw_focusinfo(bt); } } void ui_battle_area_setup(const struct battle_s *bt) { struct ui_battle_data_s *d = bt->uictx; const struct battle_item_s *b = &(bt->item[bt->cur_item]); bool is_auto = bt->s[b->side].flag_auto; if (is_auto) { d->cursor[0].cursor_i = 1; } for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { ui_cursor_area_t *cr = &(d->cursor[1 + sy * BATTLE_AREA_W + sx]); if (is_auto) { cr->cursor_i = 1; } else { int8_t v; v = bt->area[sy][sx]; if (v <= 0) { cr->cursor_i = 2; cr->mouseoff = 0/*battle_cursor_2_mouseoff*/; } else if (v == 1) { cr->cursor_i = 3; cr->mouseoff = 0/*battle_cursor_3_mouseoff*/; } else if (v >= 30) { cr->cursor_i = 4; cr->mouseoff = 0/*battle_cursor_4_mouseoff*/; } else { cr->cursor_i = 5; cr->mouseoff = 0/*battle_cursor_5_mouseoff*/; } } } } ui_cursor_setup_area(1 + BATTLE_AREA_W * BATTLE_AREA_H, &(d->cursor[0])); } void ui_battle_turn_pre(const struct battle_s *bt) { ui_delay_prepare(); } void ui_battle_turn_post(const struct battle_s *bt) { ui_delay_ticks_or_click(2); } ui_battle_action_t ui_battle_turn(const struct battle_s *bt) { const struct ui_battle_data_s *d = bt->uictx; int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); /*4ece2*/ int16_t oi; oi = uiobj_handle_input_cond(); if ((b->stasisby > 0) || ((itemi == 0) && (b->num <= 0))) { oi = d->oi_done; } if (0 || (oi == d->oi_done) || (bt->turn_done) || (oi == UIOBJI_ESC) || ((b->missile != 0) && (b->maxrange == 0) && bt->has_attacked) ) { if (oi == d->oi_done) { ui_sound_play_sfx_24(); } return UI_BATTLE_ACT_DONE; } if (oi == d->oi_grid) { ui_data.battle.show_grid = !ui_data.battle.show_grid; } /*4eddd*/ if (oi == d->oi_wait) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_WAIT; } /*4ee70*/ if (oi == d->oi_auto) { ui_sound_play_sfx_24(); /*bt->s[b->side].flag_auto = 1;*/ if (b->missile == 0) { /*b->missile = 1;*/ ui_battle_draw_bottom_no_ois(bt); uiobj_finish_frame(); } return UI_BATTLE_ACT_AUTO; } /*4eeb8*/ if (oi == d->oi_missile) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_MISSILE; } /*4ef23*/ if (oi == d->oi_planet) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_PLANET; } /*4ef45*/ if (oi == d->oi_scan) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_SCAN; } /*4ef92*/ if (oi == d->oi_special) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_SPECIAL; } if (oi == d->oi_retreat) { ui_sound_play_sfx_24(); return UI_BATTLE_ACT_RETREAT; } for (int sy = 0; sy < BATTLE_AREA_H; ++sy) { for (int sx = 0; sx < BATTLE_AREA_W; ++sx) { if (oi == d->oi_area[sy][sx]) { return UI_BATTLE_ACT_CLICK(sx, sy); } } } game_rng_step(bt->g); return UI_BATTLE_ACT_NONE; } void ui_battle_ai_pre(const struct battle_s *bt) { struct ui_battle_data_s *d = bt->uictx; uiobj_table_clear(); d->oi_ai = uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); } bool ui_battle_ai_post(const struct battle_s *bt) { struct ui_battle_data_s *d = bt->uictx; bool got_input; int16_t oi; oi = uiobj_handle_input_cond(); got_input = ((oi == d->oi_ai) || (oi == UIOBJI_ESC)); uiobj_table_clear(); d->oi_ai = UIOBJI_INVALID; return got_input; } 1oom-1.11.2/src/ui/classic/uibattlepre.c000066400000000000000000000207301476061725400177760ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_aux.h" #include "game_battle.h" #include "game_str.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uigmap.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct ui_battle_pre_data_s { struct game_s *g; int party_u; int party_d; int party_winner; uint8_t planet_i; bool flag_human_att; bool hide_other; shipsum_t force[2][SHIP_HULL_NUM]; shipsum_t bases; uint8_t *gfx_contbutt; uint8_t *gfx_fleet; uint8_t *gfx_dfleet; uint8_t *gfx_ufleet; void *gmapctx; }; /* -------------------------------------------------------------------------- */ static void battle_pre_load_data(struct ui_battle_pre_data_s *d) { int iu, id; struct game_s *g = d->g; d->gfx_contbutt = lbxfile_item_get(LBXFILE_BACKGRND, 0x0c); d->gfx_fleet = lbxfile_item_get(LBXFILE_BACKGRND, 0x15); id = (d->party_d < PLAYER_NUM) ? g->eto[d->party_d].banner : 6; iu = (d->party_u < PLAYER_NUM) ? g->eto[d->party_u].banner : 6; if (!d->flag_human_att) { uint8_t t = id; id = iu; iu = t; } d->gfx_dfleet = lbxfile_item_get(LBXFILE_BACKGRND, 0x28 + id); d->gfx_ufleet = lbxfile_item_get(LBXFILE_BACKGRND, 0x21 + iu); d->gmapctx = ui_gmap_basic_init(g, true); } static void battle_pre_free_data(struct ui_battle_pre_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_contbutt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_fleet); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_dfleet); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_ufleet); ui_gmap_basic_shutdown(d->gmapctx); } static void ui_battle_pre_draw_cb(void *vptr) { struct ui_battle_pre_data_s *d = vptr; struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet_i]); char buf[32]; hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(227, 57, d->gfx_ufleet, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(227, 102, d->gfx_dfleet, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_fleet, UI_SCREEN_W, ui_scale); if (d->hide_other) { ui_gmap_basic_draw_only(d->gmapctx, d->planet_i); } else { ui_gmap_basic_draw_frame(d->gmapctx, d->party_u); } ui_gmap_draw_planet_border(g, d->planet_i); ui_starmap_draw_planetinfo_2(g, d->party_u, d->party_d, d->planet_i); if (p->owner != PLAYER_NONE) { uint8_t *gfx; int x, y; x = (p->x * 215) / g->galaxy_maxx + 5; y = (p->y * 171) / g->galaxy_maxy + 5; gfx = ui_data.gfx.starmap.smalflag[g->eto[p->owner].banner]; lbxgfx_draw_frame(x + 3, y - 2, gfx, UI_SCREEN_W, ui_scale); } lbxfont_select_set_12_4(3, 0, 0, 0); lbxfont_print_str_center(267, 64, game_str_bp_scombat, UI_SCREEN_W, ui_scale); if (d->party_d >= PLAYER_NUM) { lib_strcpy(buf, game_str_tbl_mon_names[d->party_d - PLAYER_NUM], sizeof(buf)); } else { race_t race = g->eto[d->flag_human_att ? d->party_u : d->party_d].race; lib_strcpy(buf, game_str_tbl_races[race], sizeof(buf)); } if (ui_space_combat_autoresolve) { if (d->flag_human_att) { lbxfont_print_str_normal(230, 80, buf, UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_right(308, 80, buf, UI_SCREEN_W, ui_scale); } } else { lbxfont_print_str_center(267, 100, buf, UI_SCREEN_W, ui_scale); } lbxfont_print_str_center(267, ui_space_combat_autoresolve ? 90 : 115, (d->party_d >= PLAYER_NUM) ? game_str_bp_attacks : game_str_bp_attack, UI_SCREEN_W, ui_scale); { race_t race = g->eto[d->flag_human_att ? d->party_d : d->party_u].race; lib_strcpy(buf, game_str_tbl_races[race], sizeof(buf)); } if (ui_space_combat_autoresolve) { if (d->flag_human_att) { lbxfont_print_str_right(308, 100, buf, UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_normal(230, 100, buf, UI_SCREEN_W, ui_scale); } } else { lbxfont_print_str_center(267, 130, buf, UI_SCREEN_W, ui_scale); } if (ui_space_combat_autoresolve) { int y = 112; lbxfont_set_temp_color(0x0); lbxfont_select_set_12_4(0, 0x2, 0, 0); for (int i = 0; i < SHIP_HULL_NUM; ++i, y += 8) { lbxfont_print_num_normal(230, y, d->force[SIDE_L][i], UI_SCREEN_W, ui_scale); lbxfont_print_num_right(308, y, d->force[SIDE_R][i], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(269, y, game_str_tbl_st_hull[i], UI_SCREEN_W, ui_scale); } if (d->bases) { if (d->flag_human_att) { lbxfont_print_num_right(308, y, d->bases, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(230, y, game_str_bt_bases, UI_SCREEN_W, ui_scale); } else { lbxfont_print_num_normal(230, y, d->bases, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(308, y, game_str_bt_bases, UI_SCREEN_W, ui_scale); } } if (d->party_winner >= 0) { const char *str; if (d->party_winner >= PLAYER_NUM) { str = game_str_tbl_mon_names[d->party_winner - PLAYER_NUM]; } else { race_t race = g->eto[d->party_winner].race; str = game_str_tbl_races[race]; lbxfont_set_color0(tbl_banner_color[g->eto[d->party_winner].banner]); lbxfont_select_set_12_4(0, tbl_banner_fontparam[g->eto[d->party_winner].banner], 0, 0); } lib_sprintf(buf, sizeof(buf), "%s %s", str, game_str_bp_won); y += 8; lbxfont_print_str_center(267, y, buf, UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ ui_battle_autoresolve_t ui_battle_pre(struct game_s *g, const struct battle_s *bt, bool hide_other, int winner) { struct ui_battle_pre_data_s d[1]; int16_t oi_cont = UIOBJI_INVALID, oi_cont2 = UIOBJI_INVALID, oi_auto = UIOBJI_INVALID, oi_retreat = UIOBJI_INVALID; int16_t oi_esc = UIOBJI_INVALID; bool flag_done = false; ui_battle_autoresolve_t ret; int party_u = bt->s[SIDE_L].party, party_d = bt->s[SIDE_R].party; memset(d, 0, sizeof(*d)); d->g = g; d->party_u = party_u; d->party_d = party_d; d->party_winner = (winner != SIDE_NONE) ? bt->s[winner].party : -1; d->planet_i = bt->planet_i; d->flag_human_att = bt->flag_human_att; d->hide_other = hide_other; battle_pre_load_data(d); if (IS_HUMAN(g, party_u)) { g->planet_focus_i[party_u] = bt->planet_i; } if (IS_HUMAN(g, party_d)) { g->planet_focus_i[party_d] = bt->planet_i; } if (ui_space_combat_autoresolve) { d->bases = bt->bases; game_battle_count_hulls(bt, d->force); } uiobj_table_clear(); oi_cont = uiobj_add_t0(227, 163, "", d->gfx_contbutt, MOO_KEY_c); oi_cont2 = uiobj_add_inputkey(MOO_KEY_SPACE); if (ui_space_combat_autoresolve && (winner == SIDE_NONE)) { oi_auto = uiobj_add_t0(250, 152, "", ui_data.gfx.space.autob, MOO_KEY_a); oi_retreat = uiobj_add_t0(270, 152, "", ui_data.gfx.space.retreat, MOO_KEY_r); } if (ui_space_combat_autoresolve) { oi_esc = UIOBJI_ESC; } uiobj_set_focus(oi_cont); uiobj_set_callback_and_delay(ui_battle_pre_draw_cb, &d, 4); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_cont) || (oi == oi_cont2)) { ui_sound_play_sfx_24(); ret = UI_BATTLE_AUTORESOLVE_OFF; flag_done = true; } else if (oi == oi_auto || oi == oi_esc) { ui_sound_play_sfx_24(); ret = UI_BATTLE_AUTORESOLVE_AUTO; flag_done = true; } else if (oi == oi_retreat) { ui_sound_play_sfx_24(); ret = UI_BATTLE_AUTORESOLVE_RETREAT; flag_done = true; } if (!flag_done) { ui_battle_pre_draw_cb(d); ui_draw_finish(); } ui_delay_ticks_or_click(4); } uiobj_table_clear(); uiobj_unset_callback(); battle_pre_free_data(d); return ret; } 1oom-1.11.2/src/ui/classic/uibattlepre.h000066400000000000000000000004041476061725400177770ustar00rootroot00000000000000#ifndef INC_1OOM_UIBATTLEPRE_H #define INC_1OOM_UIBATTLEPRE_H #include "ui.h" #include "types.h" struct game_s; struct battle_s; extern ui_battle_autoresolve_t ui_battle_pre(struct game_s *g, const struct battle_s *bt, bool hide_other, int winner); #endif 1oom-1.11.2/src/ui/classic/uibomb.c000066400000000000000000000220771476061725400167410ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uigmap.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct bomb_data_s { struct game_s *g; player_id_t api; player_id_t owner; uint8_t planet; bool hide_other; int pop_inbound; int popdmg; int factdmg; uint8_t *gfx_bombback; uint8_t *gfx_bombbutt; uint8_t *gfx_bombbutc; uint8_t *gfx_explobac; uint8_t *gfx_contbutt; uint8_t *gfx_bombard; void *gmap; }; static void bomb_load_data(struct bomb_data_s *d) { d->gfx_bombback = lbxfile_item_get(LBXFILE_BACKGRND, 0x11); d->gfx_bombbutt = lbxfile_item_get(LBXFILE_BACKGRND, 0x13); d->gfx_bombbutc = lbxfile_item_get(LBXFILE_BACKGRND, 0x12); d->gfx_explobac = lbxfile_item_get(LBXFILE_BACKGRND, 0xf); d->gfx_contbutt = lbxfile_item_get(LBXFILE_BACKGRND, 0xc); d->gfx_bombard = lbxfile_item_get(LBXFILE_BACKGRND, 0x10); } static void bomb_free_data(struct bomb_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_bombback); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_bombbutt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_bombbutc); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_explobac); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_contbutt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_bombard); } static void bomb_draw_anim(uint8_t *gfx, bool anim) { int frame = anim ? lbxgfx_get_frame(gfx) : 0; lbxgfx_set_frame_0(gfx); for (int f = 0; f <= frame; ++f) { lbxgfx_draw_frame(227, 58, gfx, UI_SCREEN_W, ui_scale); } switch (frame) { case 3: ui_sound_play_sfx(0x25); break; case 6: ui_sound_play_sfx(0x2); break; case 0xf: ui_sound_play_sfx(0x11); break; default: break; } } static void bomb_ask_draw_cb(void *vptr) { struct bomb_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet]); const empiretechorbit_t *e = &(g->eto[p->owner]); char buf[0x80]; hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_bombback, UI_SCREEN_W, ui_scale); ui_starmap_draw_planetinfo_2(g, d->api, d->api, d->planet); bomb_draw_anim(d->gfx_bombard, false); lbxfont_select_set_12_4(5, tbl_banner_fontparam[e->banner], 0, 0); lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_race[e->race], game_str_sm_colony); lbxfont_print_str_center(270, 84, buf, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(3, 0xa, 0, 0); lbxfont_print_str_center(268, 60, game_str_sm_bomb1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(268, 69, game_str_sm_bomb2, UI_SCREEN_W, ui_scale); /*game_update_visibility(g);*/ ui_gmap_basic_draw_frame(d->gmap, d->api); ui_gmap_draw_planet_border(g, d->planet); lbxfont_select_set_12_4(0, 0xa, 0, 0); lbxfont_print_str_normal(230, 115, game_str_sb_pop, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(305, 115, p->pop, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(230, 125, game_str_sb_fact, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(305, 125, p->factories, UI_SCREEN_W, ui_scale); if (d->pop_inbound) { lbxfont_select_set_12_4(0, 0x0, 0, 0); lib_sprintf(buf, sizeof(buf), "%i %s", d->pop_inbound, (d->pop_inbound == 1) ? game_str_sm_trinb1 : game_str_sm_trinb1s); lbxfont_print_str_center(268, 140, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(268, 148, game_str_sm_trinb2, UI_SCREEN_W, ui_scale); } } static void bomb_show_draw_cb(void *vptr) { struct bomb_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet]); const empiretechorbit_t *e = &(g->eto[d->owner]); char buf[0x80]; hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_explobac, UI_SCREEN_W, ui_scale); ui_starmap_draw_planetinfo_2(g, d->api, d->api, d->planet); bomb_draw_anim(d->gfx_bombard, true); /*d615*/ ui_draw_line1(227, 57, 227, 160, 0, ui_scale); ui_draw_line1(227, 57, 310, 57, 0, ui_scale); ui_draw_line1(310, 57, 310, 160, 0, ui_scale); if (d->hide_other) { ui_gmap_basic_draw_only(d->gmap, d->planet); } else { ui_gmap_basic_draw_frame(d->gmap, d->api); } ui_gmap_draw_planet_border(g, d->planet); lbxfont_select_set_12_4(3, 0xa, 0, 0); lbxfont_print_str_center(267, 60, game_str_sm_obomb1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 69, game_str_sm_obomb2, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, tbl_banner_fontparam[e->banner], 0, 0); { const char *s; if ((g->gaux->local_players == 1) && IS_HUMAN(g, d->owner)) { s = game_str_sb_your; } else { s = game_str_tbl_race[e->race]; } lib_sprintf(buf, sizeof(buf), "%s %s", s, game_str_sm_colony); } lbxfont_print_str_center(270, 84, buf, UI_SCREEN_W, ui_scale); if (p->owner == PLAYER_NONE) { lbxfont_select_set_12_4(3, 0x0, 0, 0); lbxfont_print_str_center(268, 135, game_str_sm_cdest1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(268, 145, game_str_sm_cdest2, UI_SCREEN_W, ui_scale); } else if ((d->popdmg == 0) && (d->factdmg == 0)) { lbxfont_select_set_12_4(3, 0x0, 0, 0); lbxfont_print_str_center(268, 135, game_str_sm_ineff1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(268, 145, game_str_sm_ineff2, UI_SCREEN_W, ui_scale); } else { lbxfont_select_set_12_4(0, 0x0, 0, 0); if (d->popdmg) { lib_sprintf(buf, sizeof(buf), "%i %s", d->popdmg, game_str_sm_bkill1); lbxfont_print_str_center(267, 120, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 127, game_str_sm_bkill2, UI_SCREEN_W, ui_scale); } if (d->factdmg) { lib_sprintf(buf, sizeof(buf), "%i %s", d->factdmg, (d->factdmg == 1) ? game_str_sm_bfact1 : game_str_sm_bfact1s); lbxfont_print_str_center(267, 140, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 147, game_str_sm_bfact2, UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ bool ui_bomb_ask(struct game_s *g, int pi, uint8_t planet_i, int pop_inbound) { struct bomb_data_s d; int16_t oi_y, oi_n; bool flag_done = false, flag_do_bomb = false; ui_switch_1(g, pi); d.g = g; d.api = pi; d.planet = planet_i; d.pop_inbound = pop_inbound; d.gmap = ui_gmap_basic_init(g, true); bomb_load_data(&d); uiobj_set_callback_and_delay(bomb_ask_draw_cb, &d, 4); uiobj_table_clear(); oi_n = uiobj_add_t0(227, 164, "", d.gfx_bombbutc, MOO_KEY_ESCAPE); oi_y = uiobj_add_t0(271, 164, "", d.gfx_bombbutt, MOO_KEY_b); ui_sound_play_music(0xd); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_n)) { ui_sound_play_sfx_06(); flag_done = true; } if (oi == oi_y) { ui_sound_play_sfx_24(); flag_done = true; flag_do_bomb = true; } bomb_ask_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } uiobj_unset_callback(); uiobj_table_clear(); ui_sound_stop_music(); bomb_free_data(&d); return flag_do_bomb; } void ui_bomb_show(struct game_s *g, int pi, int attacker_i, int owner_i, uint8_t planet_i, int popdmg, int factdmg, bool play_music, bool hide_other) { struct bomb_data_s d; bool flag_done = false; ui_switch_2(g, attacker_i, owner_i); d.g = g; d.api = pi; d.hide_other = hide_other; d.owner = owner_i; d.planet = planet_i; d.popdmg = popdmg; d.factdmg = factdmg; d.gmap = ui_gmap_basic_init(g, true); bomb_load_data(&d); uiobj_set_callback_and_delay(bomb_show_draw_cb, &d, 4); uiobj_table_clear(); uiobj_add_t0(227, 164, "", d.gfx_contbutt, MOO_KEY_c); uiobj_add_inputkey(MOO_KEY_SPACE); if (g->planet[planet_i].owner == PLAYER_NONE) { ui_sound_play_music(0xe); } else if (play_music) { ui_sound_play_music(0xd); } while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } bomb_show_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } uiobj_unset_callback(); uiobj_table_clear(); ui_sound_stop_music(); bomb_free_data(&d); } 1oom-1.11.2/src/ui/classic/uicaught.c000066400000000000000000000054661476061725400173000ustar00rootroot00000000000000#include "config.h" #include #include "uicaught.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct caught_data_s { struct game_s *g; uint8_t *gfx; player_id_t api; }; static void caught_data_load(struct caught_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 0x1e); } static void caught_data_free(struct caught_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void caught_draw_cb(void *vptr) { struct caught_data_s *d = vptr; struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); char buf[0x40]; int x = 56, y = 50, n = 0; lbxgfx_draw_frame(x, y, d->gfx, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(x + 5, y + 5, x + 110, y + 63, 0xfb, ui_scale); lbxfont_select(2, 0, 0, 0); lbxfont_print_str_normal(x + 10, y + 8, game_str_sc_caught, UI_SCREEN_W, ui_scale); /* FIXME split str to 3 and place using x */ lbxfont_select(2, 6, 0, 0); y += 20; for (int i = 0; i < g->players; ++i) { if ((i != d->api) && BOOLVEC_IS1(e->contact, i)) { int v; lib_sprintf(buf, sizeof(buf), "%s:", game_str_tbl_race[g->eto[i].race]); lbxfont_print_str_normal(x + 11, y, buf, UI_SCREEN_W, ui_scale); v = g->evn.spies_caught[i][d->api]; lbxfont_print_num_normal(x + 68, y, v, UI_SCREEN_W, ui_scale); v = g->evn.spies_caught[d->api][i]; lbxfont_print_num_normal(x + 96, y, v, UI_SCREEN_W, ui_scale); ++n; y += 8; } } } /* -------------------------------------------------------------------------- */ void ui_caught(struct game_s *g, player_id_t active_player) { struct caught_data_s d; bool flag_done = false; int16_t oi_ma; caught_data_load(&d); d.g = g; d.api = active_player; ui_draw_copy_buf(); uiobj_finish_frame(); ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); uiobj_table_clear(); oi_ma = uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_callback_and_delay(caught_draw_cb, &d, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ma) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; } if (!flag_done) { caught_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); caught_data_free(&d); } 1oom-1.11.2/src/ui/classic/uicaught.h000066400000000000000000000002431476061725400172710ustar00rootroot00000000000000#ifndef INC_1OOM_UICAUGHT_H #define INC_1OOM_UICAUGHT_H #include "game_types.h" struct game_s; extern void ui_caught(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiclassic.c000066400000000000000000000617011476061725400174400ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "bits.h" #include "cfg.h" #include "comp.h" #include "font8x8_draw.h" #include "game_shiptech.h" /* for sounds used */ #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "options.h" #include "palette.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uipal.h" #include "uiobj.h" /* -------------------------------------------------------------------------- */ #define UI_ICON_MAX 147 static int ui_icon = 146/*guardian*/; /* -------------------------------------------------------------------------- */ void ui_extra_toggle_preset(bool enabled) { ui_extra_enabled = enabled; ui_fixbugs_enabled = enabled; ui_load_opts_extra = enabled; game_opt_skip_intro_always = enabled; ui_space_combat_autoresolve = enabled; ui_sm_ships_enabled = enabled; ui_sm_expanded_scroll = enabled; ui_sm_explicit_cursor_context = enabled; ui_sm_no_question_mark_cursor = enabled; ui_illogical_hotkey_fix = enabled; ui_sm_smoother_scrolling = enabled; ui_kbd_cursor_keys_fix = enabled; ui_mouse_lmb_fix = enabled; ui_mouse_warp_disabled = enabled; } static bool check_ui_scale(void *var) { int v = (int)(intptr_t)var; if ((v > 0) && (v <= UI_SCALE_MAX)) { return true; } else { log_error("invalid ui_scale %i, must be 0 < N <= %i\n", v, UI_SCALE_MAX); return false; } } static bool check_ui_icon(void *var) { int v = (int)(intptr_t)var; if ((v >= 0) && (v < UI_ICON_MAX)) { return true; } else { log_error("invalid ui_icon %i, must be 0 <= N < %i\n", v, UI_ICON_MAX); return false; } } static bool check_ui_sm_scroll_speed(void *var) { int v = (int)(intptr_t)var; if ((v >= 0) && (v <= UI_SCROLL_SPEED_MAX)) { return true; } else { log_error("invalid ui_sm_scroll_speed %i, must be 0 <= N <= %i\n", v, UI_SCROLL_SPEED_MAX); return false; } } const struct cfg_items_s ui_cfg_items[] = { CFG_ITEM_INT("uiscale", &ui_scale_hint, check_ui_scale), CFG_ITEM_BOOL("uiextra", &ui_extra_enabled), CFG_ITEM_BOOL("uifixbugs", &ui_fixbugs_enabled), CFG_ITEM_BOOL("illogical_hotkey_fix", &ui_illogical_hotkey_fix), CFG_ITEM_BOOL("load_opts_extra", &ui_load_opts_extra), CFG_ITEM_BOOL("space_combat_autoresolve", &ui_space_combat_autoresolve), CFG_ITEM_BOOL("ui_sm_ships_enabled", &ui_sm_ships_enabled), CFG_ITEM_BOOL("sm_expanded_scroll", &ui_sm_expanded_scroll), CFG_ITEM_BOOL("sm_no_question_mark_cursor", &ui_sm_no_question_mark_cursor), CFG_ITEM_BOOL("sm_explicit_cursor_context", &ui_sm_explicit_cursor_context), CFG_ITEM_BOOL("mouse_lmb_fix", &ui_mouse_lmb_fix), CFG_ITEM_BOOL("mouse_warp_disabled", &ui_mouse_warp_disabled), CFG_ITEM_BOOL("copy_protection_disabled", &ui_copyprotection_disabled), CFG_ITEM_BOOL("sm_mouseover_focus", &ui_sm_mouseover_focus), CFG_ITEM_BOOL("sm_smoother_scrolling", &ui_sm_smoother_scrolling), CFG_ITEM_BOOL("sm_mouse_scroll", &ui_sm_mouse_scroll), CFG_ITEM_BOOL("sm_uhjk_scroll", &ui_sm_uhjk_scroll), CFG_ITEM_BOOL("kbd_cursor_keys_fix", &ui_kbd_cursor_keys_fix), CFG_ITEM_COMMENT("0..146"), CFG_ITEM_INT("uiicon", &ui_icon, check_ui_icon), CFG_ITEM_COMMENT("Invert mouse wheel for sliders"), CFG_ITEM_BOOL("mwislider", &ui_mwi_slider), CFG_ITEM_COMMENT("Invert mouse wheel for counters"), CFG_ITEM_BOOL("mwicounter", &ui_mwi_counter), CFG_ITEM_COMMENT("Starmap scroll speed (1..10, 0 = instant)"), CFG_ITEM_INT("sm_scroll_speed", &ui_sm_scroll_speed, check_ui_sm_scroll_speed), CFG_ITEM_BOOL("kbd_repeat", &ui_kbd_repeat), CFG_ITEM_END }; static int ui_options_set_scale(char **argv, void *var) { int v = atoi(argv[1]); if (check_ui_scale((void *)(intptr_t)v)) { ui_scale_hint = v; return 0; } return -1; } static int ui_options_set_scroll_speed(char **argv, void *var) { int v = atoi(argv[1]); if (check_ui_sm_scroll_speed((void *)(intptr_t)v)) { ui_sm_scroll_speed = v; return 0; } return -1; } const struct cmdline_options_s ui_cmdline_options[] = { { "-uiscale", 1, ui_options_set_scale, 0, "SCALE", "UI scaling factor" }, { "-uiextra", 0, options_enable_bool_var, (void *)&ui_extra_enabled, NULL, "Enable UI extras" }, { "-nouiextra", 0, options_disable_bool_var, (void *)&ui_extra_enabled, NULL, "Disable UI extras" }, { "-mwislider", 0, options_enable_bool_var, (void *)&ui_mwi_slider, NULL, "Invert mouse wheel for sliders" }, { "-nomwislider", 0, options_disable_bool_var, (void *)&ui_mwi_slider, NULL, "Do not invert mouse wheel for sliders" }, { "-mwicounter", 0, options_enable_bool_var, (void *)&ui_mwi_counter, NULL, "Invert mouse wheel for counters" }, { "-nomwicounter", 0, options_disable_bool_var, (void *)&ui_mwi_counter, NULL, "Do not invert mouse wheel for counters" }, { "-uismscroll", 1, ui_options_set_scroll_speed, 0, "SPEED", "Starmap scroll speed (1..10, 0 = instant)" }, { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ const char *idstr_ui = "classic"; struct ui_data_s ui_data = { 0 }; int ui_screen_w = 0; int ui_screen_h = 0; int ui_scale = 0; int ui_scale_hint = 0; int starmap_scale = 0; bool ui_extra_enabled = false; bool ui_fixbugs_enabled = false; bool ui_illogical_hotkey_fix = false; bool ui_load_opts_extra = false; bool ui_space_combat_autoresolve = false; bool ui_sm_ships_enabled = false; bool ui_sm_expanded_scroll = false; bool ui_sm_no_question_mark_cursor = false; bool ui_sm_explicit_cursor_context = false; bool ui_mouse_lmb_fix = false; bool ui_mouse_warp_disabled = false; bool ui_copyprotection_disabled = false; bool ui_sm_mouseover_focus = false; bool ui_sm_smoother_scrolling = false; bool ui_sm_mouse_scroll = false; bool ui_sm_uhjk_scroll = false; bool ui_kbd_cursor_keys_fix = false; bool ui_mwi_slider = false; bool ui_mwi_counter = false; int ui_sm_scroll_speed = 3; bool ui_kbd_repeat = true; bool ui_use_audio = true; /* -------------------------------------------------------------------------- */ static void init_lbx_design(void) { ui_data.gfx.design.blank = lbxfile_item_get(LBXFILE_DESIGN, 1); ui_data.gfx.design.icon_up = lbxfile_item_get(LBXFILE_DESIGN, 3); ui_data.gfx.design.icon_dn = lbxfile_item_get(LBXFILE_DESIGN, 2); ui_data.gfx.design.count_up = lbxfile_item_get(LBXFILE_DESIGN, 4); ui_data.gfx.design.count_dn = lbxfile_item_get(LBXFILE_DESIGN, 5); ui_data.gfx.design.bg = lbxfile_item_get(LBXFILE_DESIGN, 0); ui_data.gfx.design.pop1_ul = lbxfile_item_get(LBXFILE_DESIGN, 6); ui_data.gfx.design.pop1_ur = lbxfile_item_get(LBXFILE_DESIGN, 7); ui_data.gfx.design.pop1_dl = lbxfile_item_get(LBXFILE_DESIGN, 9); ui_data.gfx.design.pop1_dr = lbxfile_item_get(LBXFILE_PLANETS, 0x31); ui_data.gfx.design.titlebox = lbxfile_item_get(LBXFILE_DESIGN, 8); ui_data.gfx.design.popscrol_u = lbxfile_item_get(LBXFILE_DESIGN, 0xb); ui_data.gfx.design.popscrol_d = lbxfile_item_get(LBXFILE_DESIGN, 0xc); } static void init_lbx_space(void) { for (int i = 0; i < 5; ++i) { ui_data.gfx.space.bg[i] = lbxfile_item_get(LBXFILE_SPACE, 0x1a + i); } ui_data.gfx.space.box = lbxfile_item_get(LBXFILE_SPACE, 1); ui_data.gfx.space.box_x = lbxfile_item_get(LBXFILE_SPACE, 0x32); ui_data.gfx.space.box_y = lbxfile_item_get(LBXFILE_SPACE, 0x33); ui_data.gfx.space.box_xy = lbxfile_item_get(LBXFILE_SPACE, 0x34); ui_data.gfx.space.done = lbxfile_item_get(LBXFILE_SPACE, 3); ui_data.gfx.space.retreat = lbxfile_item_get(LBXFILE_SPACE, 5); ui_data.gfx.space.retr_off = lbxfile_item_get(LBXFILE_SPACE, 2); ui_data.gfx.space.wait = lbxfile_item_get(LBXFILE_SPACE, 6); ui_data.gfx.space.autob = lbxfile_item_get(LBXFILE_SPACE, 0x11); ui_data.gfx.space.special = lbxfile_item_get(LBXFILE_SPACE, 0x12); ui_data.gfx.space.spec_off = lbxfile_item_get(LBXFILE_SPACE, 0x20); ui_data.gfx.space.scan = lbxfile_item_get(LBXFILE_SPACE, 0x15); ui_data.gfx.space.scan_off = lbxfile_item_get(LBXFILE_SPACE, 0x14); ui_data.gfx.space.planet = lbxfile_item_get(LBXFILE_SPACE, 0x16); ui_data.gfx.space.planet_off = lbxfile_item_get(LBXFILE_SPACE, 0x1f); for (int i = 0; i < 10; ++i) { ui_data.gfx.space.explos[i] = lbxfile_item_get(LBXFILE_SPACE, 7 + i); } ui_data.gfx.space.warp1 = lbxfile_item_get(LBXFILE_SPACE, 0x17); ui_data.gfx.space.warp2 = lbxfile_item_get(LBXFILE_SPACE, 0x2d); ui_data.gfx.space.warp3 = lbxfile_item_get(LBXFILE_SPACE, 0x2e); ui_data.gfx.space.warp4 = lbxfile_item_get(LBXFILE_SPACE, 0x2f); ui_data.gfx.space.technull = lbxfile_item_get(LBXFILE_SPACE, 0x18); ui_data.gfx.space.misbutt = lbxfile_item_get(LBXFILE_SPACE, 0x19); ui_data.gfx.space.misl_off = lbxfile_item_get(LBXFILE_SPACE, 4); ui_data.gfx.space.warpout = lbxfile_item_get(LBXFILE_SPACE, 0x21); ui_data.gfx.space.envterm = lbxfile_item_get(LBXFILE_SPACE, 0x22); ui_data.gfx.space.enviro = lbxfile_item_get(LBXFILE_SPACE, 0x13); ui_data.gfx.space.base_btn = lbxfile_item_get(LBXFILE_SPACE, 0x23); ui_data.gfx.space.dis_bem2 = lbxfile_item_get(LBXFILE_SPACE, 0x24); ui_data.gfx.space.stasis2 = lbxfile_item_get(LBXFILE_SPACE, 0x25); ui_data.gfx.space.vs2 = lbxfile_item_get(LBXFILE_SPACE, 0x27); ui_data.gfx.space.vp2_top = lbxfile_item_get(LBXFILE_SPACE, 0x2a); ui_data.gfx.space.vp2_data = lbxfile_item_get(LBXFILE_SPACE, 0x2b); ui_data.gfx.space.vp2_line = lbxfile_item_get(LBXFILE_SPACE, 0x2c); ui_data.gfx.space.vp2_bottom = lbxfile_item_get(LBXFILE_SPACE, 0x39); ui_data.gfx.space.blk_hole = lbxfile_item_get(LBXFILE_SPACE, 0x26); ui_data.gfx.space.bombs = lbxfile_item_get(LBXFILE_SPACE, 0x30); ui_data.gfx.space.biologic = lbxfile_item_get(LBXFILE_SPACE, 0x31); ui_data.gfx.space.circle = lbxfile_item_get(LBXFILE_SPACE, 0x35); ui_data.gfx.space.sphere2 = lbxfile_item_get(LBXFILE_SPACE, 0x36); ui_data.gfx.space.asteroid[0] = lbxfile_item_get(LBXFILE_SPACE, 0x28); ui_data.gfx.space.asteroid[1] = lbxfile_item_get(LBXFILE_SPACE, 0x29); ui_data.gfx.space.asteroid[2] = lbxfile_item_get(LBXFILE_SPACE, 0x37); ui_data.gfx.space.asteroid[3] = lbxfile_item_get(LBXFILE_SPACE, 0x38); for (int i = 0; i < 8; ++i) { ui_data.gfx.missile.missiles[i] = lbxfile_item_get(LBXFILE_MISSILE, i); ui_data.gfx.missile.antimatr[i] = lbxfile_item_get(LBXFILE_MISSILE, 0x8 + i); ui_data.gfx.missile.hellfire[i] = lbxfile_item_get(LBXFILE_MISSILE, 0x10 + i); ui_data.gfx.missile.proton[i] = lbxfile_item_get(LBXFILE_MISSILE, 0x18 + i); ui_data.gfx.missile.plasmaqt[i] = lbxfile_item_get(LBXFILE_MISSILE, 0x20 + i); } } static void init_lbx_news(void) { ui_data.gfx.news.tv = lbxfile_item_get(LBXFILE_NEWSCAST, 0); ui_data.gfx.news.gnn = lbxfile_item_get(LBXFILE_NEWSCAST, 1); ui_data.gfx.news.nc = lbxfile_item_get(LBXFILE_NEWSCAST, 2); ui_data.gfx.news.world = lbxfile_item_get(LBXFILE_NEWSCAST, 3); ui_data.gfx.news.icon = 0; } static void init_gfx(void) { for (int i = 0; i < NEBULA_MAX; ++i) { ui_data.gfx.starmap.nebula[i] = NULL; ui_data.gfx.starmap.smnebula[i] = NULL; } ui_data.gfx.starmap.mainview = lbxfile_item_get(LBXFILE_STARMAP, 0); ui_data.gfx.starmap.starback = lbxfile_item_get(LBXFILE_STARMAP, 1); ui_data.gfx.starmap.starbak2 = lbxfile_item_get(LBXFILE_STARMAP, 2); for (int i = 0; i < 12; ++i) { const int jtbl[12] = { 0, 1, 2, 4, 3, 5, 6, 7, 8, 10, 9, 11 }; ui_data.gfx.starmap.stars[jtbl[i]] = lbxfile_item_get(LBXFILE_STARMAP, 3 + i); } ui_data.gfx.starmap.planbord = lbxfile_item_get(LBXFILE_STARMAP, 0x19); ui_data.gfx.starmap.yourplnt = lbxfile_item_get(LBXFILE_STARMAP, 0x1a); ui_data.gfx.starmap.unexplor = lbxfile_item_get(LBXFILE_STARMAP, 0x1b); ui_data.gfx.starmap.en_colny = lbxfile_item_get(LBXFILE_STARMAP, 0x1c); ui_data.gfx.starmap.no_colny = lbxfile_item_get(LBXFILE_STARMAP, 0x1d); ui_data.gfx.starmap.col_butt_ship = lbxfile_item_get(LBXFILE_STARMAP, 0x1e); ui_data.gfx.starmap.col_butt_reloc = lbxfile_item_get(LBXFILE_STARMAP, 0x1f); ui_data.gfx.starmap.col_butt_trans = lbxfile_item_get(LBXFILE_STARMAP, 0x20); ui_data.gfx.starmap.sky = lbxfile_item_get(LBXFILE_STARMAP, 0x2f); for (int i = 0; i < 6; ++i) { const int jtbl[6] = { 0, 1, 2, 4, 3, 5 }; ui_data.gfx.starmap.smstars[jtbl[i]] = lbxfile_item_get(LBXFILE_STARMAP, 0x21 + i); } for (int i = 0; i < 6; ++i) { ui_data.gfx.starmap.smalflag[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x27 + i); } ui_data.gfx.starmap.stargate = lbxfile_item_get(LBXFILE_STARMAP, 0x2d); ui_data.gfx.starmap.smallstr = lbxfile_item_get(LBXFILE_STARMAP, 0x2e); for (int i = 0; i < 0xa; ++i) { ui_data.gfx.starmap.smneb[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x35 + i); } for (int i = 0; i < 0x1e; ++i) { ui_data.gfx.starmap.smneb[0xa + i] = lbxfile_item_get(LBXFILE_NEBULA, i); } ui_data.gfx.starmap.relocate = lbxfile_item_get(LBXFILE_STARMAP, 0x3f); ui_data.gfx.starmap.reloc_bu_cancel = lbxfile_item_get(LBXFILE_STARMAP, 0x40); ui_data.gfx.starmap.reloc_bu_accept = lbxfile_item_get(LBXFILE_STARMAP, 0x41); ui_data.gfx.starmap.tran_bar = lbxfile_item_get(LBXFILE_STARMAP, 0x42); for (int i = 0; i < 6; ++i) { ui_data.gfx.starmap.smalship[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x43 + i); ui_data.gfx.starmap.smaltran[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x49 + i); ui_data.gfx.starmap.tinyship[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x4f + i); ui_data.gfx.starmap.tinytran[i] = lbxfile_item_get(LBXFILE_STARMAP, 0x55 + i); } ui_data.gfx.starmap.move_shi = lbxfile_item_get(LBXFILE_STARMAP, 0x5b); ui_data.gfx.starmap.move_but_p = lbxfile_item_get(LBXFILE_STARMAP, 0x5c); ui_data.gfx.starmap.move_but_m = lbxfile_item_get(LBXFILE_STARMAP, 0x5d); ui_data.gfx.starmap.move_but_a = lbxfile_item_get(LBXFILE_STARMAP, 0x5e); ui_data.gfx.starmap.move_but_n = lbxfile_item_get(LBXFILE_STARMAP, 0x5f); ui_data.gfx.starmap.shipbord = lbxfile_item_get(LBXFILE_STARMAP, 0x60); ui_data.gfx.starmap.movextra = lbxfile_item_get(LBXFILE_STARMAP, 0x61); ui_data.gfx.starmap.movextr2 = lbxfile_item_get(LBXFILE_STARMAP, 0x62); ui_data.gfx.starmap.movextr3 = lbxfile_item_get(LBXFILE_STARMAP, 0x63); ui_data.gfx.starmap.scanner = lbxfile_item_get(LBXFILE_STARMAP, 0x64); ui_data.gfx.starmap.tranship = lbxfile_item_get(LBXFILE_STARMAP, 0x65); ui_data.gfx.starmap.tranbord = lbxfile_item_get(LBXFILE_STARMAP, 0x66); ui_data.gfx.starmap.tranxtra = lbxfile_item_get(LBXFILE_STARMAP, 0x67); ui_data.gfx.starmap.dismiss = lbxfile_item_get(LBXFILE_STARMAP, 0x68); ui_data.gfx.starmap.fleetbut_view = lbxfile_item_get(LBXFILE_STARMAP, 0x69); ui_data.gfx.starmap.fleetbut_scrap = lbxfile_item_get(LBXFILE_STARMAP, 0x6a); ui_data.gfx.starmap.fleetbut_ok = lbxfile_item_get(LBXFILE_STARMAP, 0x6b); ui_data.gfx.starmap.fleetbut_down = lbxfile_item_get(LBXFILE_STARMAP, 0x6c); ui_data.gfx.starmap.fleetbut_up = lbxfile_item_get(LBXFILE_STARMAP, 0x6d); ui_data.gfx.starmap.viewship = lbxfile_item_get(LBXFILE_STARMAP, 0x6e); ui_data.gfx.starmap.viewshp2 = lbxfile_item_get(LBXFILE_STARMAP, 0x6f); ui_data.gfx.starmap.viewshbt = lbxfile_item_get(LBXFILE_STARMAP, 0x70); ui_data.gfx.starmap.scrap = lbxfile_item_get(LBXFILE_STARMAP, 0x71); ui_data.gfx.starmap.scrapbut_no = lbxfile_item_get(LBXFILE_STARMAP, 0x72); ui_data.gfx.starmap.scrapbut_yes = lbxfile_item_get(LBXFILE_STARMAP, 0x73); ui_data.gfx.starmap.reprtbut_ok = lbxfile_item_get(LBXFILE_STARMAP, 0x75); ui_data.gfx.starmap.reprtbut_up = lbxfile_item_get(LBXFILE_STARMAP, 0x76); ui_data.gfx.starmap.reprtbut_down = lbxfile_item_get(LBXFILE_STARMAP, 0x77); ui_data.gfx.starmap.gr_arrow_u = lbxfile_item_get(LBXFILE_STARMAP, 0x78); ui_data.gfx.starmap.gr_arrow_d = lbxfile_item_get(LBXFILE_STARMAP, 0x79); ui_data.gfx.starmap.slanbord = lbxfile_item_get(LBXFILE_STARMAP, 0x74); for (int i = 0; i < 0x23; ++i) { ui_data.gfx.planets.planet[i] = lbxfile_item_get(LBXFILE_PLANETS, i); } for (int i = 0; i < 10; ++i) { ui_data.gfx.planets.race[i] = lbxfile_item_get(LBXFILE_PLANETS, 0x23 + i); } ui_data.gfx.planets.smonster = lbxfile_item_get(LBXFILE_PLANETS, 0x2d); ui_data.gfx.planets.tmonster = lbxfile_item_get(LBXFILE_PLANETS, 0x2e); ui_data.gfx.screens.tech_but_up = lbxfile_item_get(LBXFILE_SCREENS, 1); ui_data.gfx.screens.tech_but_down = lbxfile_item_get(LBXFILE_SCREENS, 2); ui_data.gfx.screens.tech_but_ok = lbxfile_item_get(LBXFILE_SCREENS, 3); ui_data.gfx.screens.litebulb_off = lbxfile_item_get(LBXFILE_SCREENS, 4); ui_data.gfx.screens.litebulb_on = lbxfile_item_get(LBXFILE_SCREENS, 5); ui_data.gfx.screens.techback = lbxfile_item_get(LBXFILE_SCREENS, 6); ui_data.gfx.screens.race_pnt = lbxfile_item_get(LBXFILE_SCREENS, 8); ui_data.gfx.screens.races_bu.sabotage = lbxfile_item_get(LBXFILE_SCREENS, 0x9); ui_data.gfx.screens.races_bu.espionage = lbxfile_item_get(LBXFILE_SCREENS, 0xa); ui_data.gfx.screens.races_bu.hiding = lbxfile_item_get(LBXFILE_SCREENS, 0xb); ui_data.gfx.screens.races_bu.status = lbxfile_item_get(LBXFILE_SCREENS, 0xc); ui_data.gfx.screens.races_bu.report = lbxfile_item_get(LBXFILE_SCREENS, 0xd); ui_data.gfx.screens.races_bu.audience = lbxfile_item_get(LBXFILE_SCREENS, 0xe); ui_data.gfx.screens.races_bu.ok = lbxfile_item_get(LBXFILE_SCREENS, 0xf); init_lbx_design(); init_lbx_space(); ui_data.gfx.starmap.stargate2 = lbxfile_item_get(LBXFILE_V11, 5); for (int i = 0; i < 0x1c; ++i) { ui_data.gfx.colonies.d[i] = lbxfile_item_get(LBXFILE_COLONIES, i); } ui_data.gfx.colonies.current = NULL; init_lbx_news(); ui_data.gfx.vgafileh = lib_malloc(UI_SCREEN_W * UI_SCREEN_H); gfx_aux_setup_wh(&ui_data.aux.screen, UI_SCREEN_W, UI_SCREEN_H); gfx_aux_setup_wh(&ui_data.aux.ship_overlay, 34, 26); gfx_aux_setup_wh(&ui_data.aux.btemp, 50, 40); ui_data.gfx.initialized = true; } static int init_lbx_ships(void) { for (int i = 0; i < 0x48; ++i) { uint8_t *t; if (i < 0x46) { t = lbxfile_item_get(LBXFILE_SHIPS2, i); } else if (i == 0x46) { t = lbxfile_item_get(LBXFILE_PLANETS, i - 0x17); } else /*(i == 0x47)*/ { t = lbxfile_item_get(LBXFILE_SCREENS, 7); } ui_data.gfx.ships[i] = t; ui_data.gfx.ships[0x48 + i] = lbxfile_item_get(LBXFILE_SHIPS, i); } for (int i = 0; i < 3; ++i) { ui_data.gfx.ships[0x48 * 2 + i] = lbxfile_item_get(LBXFILE_SHIPS2, 0x48 + i); } gfx_aux_setup_wh(&ui_data.aux.ship_p1, 34, 26); return 0; } static int set_ui_icon(void) { struct gfx_aux_s *aux = &ui_data.aux.ship_p1; uint8_t *gfx, *pal; gfx = ui_data.gfx.ships[ui_icon]; pal = lbxfile_item_get(LBXFILE_FONTS, 2); memcpy(lbxpal_palette, pal, 256 * 3); gfx_aux_draw_frame_to(gfx, aux); hw_icon_set(aux->data, pal, aux->w, aux->h); /* do not care if the icon got set */ lbxfile_item_release(LBXFILE_FONTS, pal); return 0; } /* -------------------------------------------------------------------------- */ void ui_early_show_message_box(const char *msg) { if (hw_video_init(320, 200)) { return; } bool initialized = false; int64_t init_time = hw_get_time_us(); lbxpal_init(); ui_palette_set_color(0, 0, 0, 0); ui_palette_set_color(1, 0x3f, 0x3f, 0x3f); hw_video_refresh_palette(); while (1) { if (!initialized && (hw_get_time_us() - init_time) > 1000000) { memset(hw_video_get_buf(), 0, 320 * 200); font8x8_drawstr_rect(50, 20, 270, 180, 320, msg, 1, 0); hw_video_draw_buf(); initialized = true; } hw_event_handle(); if (kbd_have_keypress()) { uint32_t k; k = kbd_get_keypress(); if ((KBD_GET_KEY(k) == MOO_KEY_SPACE) ||(KBD_GET_KEY(k) == MOO_KEY_ESCAPE)) { break; } } } } int ui_early_init(void) { return 0; } int ui_init(void) { memset(&ui_data, 0, sizeof(ui_data)); return 0; } int ui_late_init(void) { if (!lbxfile_exists(LBXFILE_V11)) { log_error("V11.LBX not found! Make sure that your MOO1 is updated to v1.3.\n"); return 1; } if (ui_scale_hint == 0) { ui_scale_hint = 1; } ui_scale = ui_scale_hint; starmap_scale = ui_scale_hint; ui_screen_w = UI_VGA_W * ui_scale; ui_screen_h = UI_VGA_H * ui_scale; ui_cursor_init(ui_scale); log_message("UI: scale %i -> %ix%i\n", ui_scale, ui_screen_w, ui_screen_h); uiobj_set_limits_all(); if (0 || lbxfont_init() || init_lbx_ships() || set_ui_icon() || hw_video_init(UI_SCREEN_W, UI_SCREEN_H) || lbxpal_init() ) { return 1; } if (opt_audio_enabled) { const uint8_t sounds[] = { /* sounds used by ui or game code */ 0x24, 0x06, /* these are the most common sounds and are prepared first */ 0x02, 0x09, 0x0e, 0x11, 0x13, 0x15, 0x16, 0x18, 0x1d, 0x20 }; uint32_t t0; int res; BOOLVEC_DECLARE(sound_added, NUM_SOUNDS); BOOLVEC_CLEAR(sound_added, NUM_SOUNDS); t0 = hw_get_time_us(); res = hw_audio_sfx_batch_start(NUM_SOUNDS); if (res < 0) { return -1; } else if (res == 0) { log_message("Preparing sounds, this may take a while...\n"); } else { log_message("Preparing sounds in a thread\n"); } for (int ti = 0; ti < TBLLEN(sounds); ++ti) { uint32_t len; int i; i = sounds[ti]; BOOLVEC_SET1(sound_added, i); LOG_DEBUG((4, "%s: sfx 0x%02x\n", __func__, i)); ui_data.sfx[i] = lbxfile_item_get_with_len(LBXFILE_SOUNDFX, i, &len); hw_audio_sfx_init(i, ui_data.sfx[i], len); } for (int ti = 0; ti < WEAPON_NUM; ++ti) { uint32_t len; int i; i = tbl_shiptech_weap[ti].sound; if (BOOLVEC_IS0(sound_added, i)) { BOOLVEC_SET1(sound_added, i); LOG_DEBUG((4, "%s: sfx 0x%02x\n", __func__, i)); ui_data.sfx[i] = lbxfile_item_get_with_len(LBXFILE_SOUNDFX, i, &len); hw_audio_sfx_init(i, ui_data.sfx[i], len); } } res = hw_audio_sfx_batch_end(); if (res < 0) { return -1; } else if (res == 0) { uint32_t t1; t1 = hw_get_time_us(); log_message("Preparing sounds took %i ms\n", (t1 - t0) / 1000); } } ui_data.music_i = -1; init_gfx(); ui_data.have_help = lbxfile_exists(LBXFILE_HELP); if (!ui_data.have_help) { log_warning("Help disabled due to missing %s\n", lbxfile_name(LBXFILE_HELP)); } uiobj_table_clear(); kbd_clear(); hw_kbd_set_repeat(ui_kbd_repeat); return 0; } void ui_shutdown(void) { hw_audio_music_stop(); hw_audio_sfx_stop(); if (ui_data.mus) { hw_audio_music_release(0); lbxfile_item_release(LBXFILE_MUSIC, ui_data.mus); } for (int i = 0; i < NUM_SOUNDS; ++i) { if (ui_data.sfx[i]) { hw_audio_sfx_release(i); lbxfile_item_release(LBXFILE_SOUNDFX, ui_data.sfx[i]); } } if (ui_data.gfx.initialized) { gfx_aux_free(&ui_data.starmap.star_aux); gfx_aux_free(&ui_data.aux.screen); gfx_aux_free(&ui_data.aux.ship_p1); gfx_aux_free(&ui_data.aux.ship_overlay); gfx_aux_free(&ui_data.aux.btemp); memset(&ui_data.aux, 0, sizeof(ui_data.aux)); lbxfile_item_release_file(LBXFILE_STARMAP); lbxfile_item_release_file(LBXFILE_NEBULA); lbxfile_item_release_file(LBXFILE_SHIPS); lbxfile_item_release_file(LBXFILE_SHIPS2); lbxfile_item_release_file(LBXFILE_SCREENS); lbxfile_item_release_file(LBXFILE_RESEARCH); lbxfile_item_release_file(LBXFILE_DIPLOMAT); lbxfile_item_release_file(LBXFILE_DESIGN); lbxfile_item_release_file(LBXFILE_SPACE); lbxfile_item_release_file(LBXFILE_MISSILE); lbxfile_item_release_file(LBXFILE_V11); lbxfile_item_release_file(LBXFILE_COLONIES); lbxfile_item_release_file(LBXFILE_NEWSCAST); lib_free(ui_data.gfx.vgafileh); memset(&ui_data.gfx, 0, sizeof(ui_data.gfx)); } lbxfont_shutdown(); } char *ui_get_strbuf(void) { return ui_data.strbuf; } uint8_t *ui_gfx_get_ship(int look) { return ui_data.gfx.ships[look]; } uint8_t *ui_gfx_get_planet(int look) { return ui_data.gfx.planets.planet[look]; } uint8_t *ui_gfx_get_rock(int look) { return ui_data.gfx.space.asteroid[look]; } 1oom-1.11.2/src/ui/classic/uicopyprotection.c000066400000000000000000000140051476061725400210730ustar00rootroot00000000000000#include "config.h" #include #include #include "comp.h" #include "game.h" #include "game_news.h" #include "game_str.h" #include "game_turn.h" #include "game_types.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "rnd.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct copyprotection_data_s { struct game_s *g; uint8_t *gfx; uint8_t *gfx2; uint16_t seed; uint16_t page_min; uint16_t page_max; uint16_t ship_name_id[8]; uint16_t correct_answer_id; }; static void ui_copyprotection_draw_cb(void *vptr) { uint8_t look_i[] = { 0x12,0x68,0x87,0x2A,0x39,0x6D,0x5A,0x83,0x17,0x42, 0x0D,0x4E,0x8B,0x27,0x7,0x73,0x54,0x23,0x45,0x41, 0x15,0x67,0x89,0x2E,0x38,0x6F,0x5D,0x80,0x2F,0x46, 0x11,0x51,0x8F,0x29,0x0B,0x77,0x56,0x1F,0x5C,0x40 }; char buf[64]; struct copyprotection_data_s *d = vptr; lbxgfx_draw_frame(0, 0, d->gfx, UI_SCREEN_W, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.ships[look_i[d->seed]]); lbxgfx_draw_frame(208, 23, ui_data.gfx.ships[look_i[d->seed]], UI_SCREEN_W, ui_scale); lbxfont_select(5, 0, 0, 0); lbxfont_print_str_normal(197, 48, "Pages", UI_SCREEN_W, ui_scale); lib_sprintf(buf, 64, "%d-%d", d->page_min, d->page_max); lbxfont_print_str_normal(224, 48, buf, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_copyprotection_check(struct game_s *g) { struct copyprotection_data_s d; bool flag_done = false; int16_t oi_ship_name[8]; int16_t oi; d.g = g; if (ui_copyprotection_disabled) { copyprot_status = -99; return; } uiobj_set_xyoff(1, 1); if (copyprot_status == 0) { return; } ui_delay_1(); ui_sound_stop_music(); d.gfx = lbxfile_item_get(LBXFILE_BACKGRND, 0x20); d.gfx2 = lbxfile_item_get(LBXFILE_BACKGRND, 0x2f); uiobj_table_clear(); if (ui_draw_finish_mode == 0) { ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; } lbxpal_select(9, -1, 0); lbxpal_set_update_range(0, 255); ui_draw_erase_buf(); ui_draw_finish(); ui_draw_erase_buf(); ui_palette_set_n(); for (int attempts_left = 3; attempts_left > 0; --attempts_left) { d.seed = rnd_0_nm1(40, &g->seed); do { d.page_min = d.seed + 0x1a - rnd_0_nm1(4, &g->seed); d.page_max = d.seed + rnd_1_n(4, &g->seed) + 0x19; } while (d.page_min == d.page_max); SETMAX(d.page_min, 0x1a); SETMIN(d.page_max, 0x41); for (int si = 0; si < 8;) { bool flag_again = false; d.ship_name_id[si] = rnd_0_nm1(40, &g->seed); for (int di = 0; di < si; ++di) { if (d.ship_name_id[si] == d.seed) { flag_again = true; } if (d.ship_name_id[si] == d.ship_name_id[di]) { flag_again = true; } } if (!flag_again) { ++si; } } d.correct_answer_id = rnd_0_nm1(8, &g->seed); d.ship_name_id[d.correct_answer_id] = d.seed; uiobj_set_callback_and_delay(ui_copyprotection_draw_cb, &d, 1); uiobj_table_clear(); for (int si = 0; si < 8; ++si) { uint16_t x, y; x = (si / 4) * 0x48 + 0x75; y = (si % 4) * 0x13 + 0x3e; lbxfont_select(0, 0, 0, 0); oi_ship_name[si] = uiobj_add_t0(x, y, game_str_tbl_copyprotection_ship_names[d.ship_name_id[si]], d.gfx2, MOO_KEY_UNKNOWN); } flag_done = false; while (!flag_done) { oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } ui_copyprotection_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(1); } int pick = -1; for (int i = 0; i < 8; ++i) { if (oi_ship_name[i] == oi) { pick = i; break; } } if (d.ship_name_id[pick] == d.seed) { copyprot_status = -99; ui_sound_play_sfx_24(); } else { ui_sound_play_sfx_06(); } if (copyprot_status != 1) { break; } } uiobj_table_clear(); uiobj_unset_callback(); ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); lbxpal_select(0, -1, 0); lbxpal_set_update_range(0, 255); lbxfile_item_release(LBXFILE_BACKGRND, d.gfx); lbxfile_item_release(LBXFILE_BACKGRND, d.gfx2); } void ui_copyprotection_lose(struct game_s *g, struct game_end_s *ge) { struct news_s ns; int best_ai = 0; int best_planet_num = 0; int planet_num[6] = {0, 0, 0, 0, 0, 0}; player_id_t api = 0; for (player_id_t i = PLAYER_0; i < g->players; ++i) { api = i; if (IS_HUMAN(g, i)) { break; } } for (int si = 0; si < g->galaxy_stars; ++si) { if (g->planet[si].owner == -1) { continue; } if (IS_HUMAN(g, g->planet[si].owner)) { continue; } /* ++planet_num[si]; WASBUG: wrong index */ ++planet_num[g->planet[si].owner]; } for (int si = 0; si < g->players; ++si) { if (si == api) { continue; } if (planet_num[si] <= best_planet_num) { continue; } best_planet_num = planet_num[si]; best_ai = si; } /* MOO deletes save_7 here */ ns.type = GAME_NEWS_GENOCIDE; ns.subtype = 3; ns.num1 = 0; ns.race = g->eto[api].race; ui_data.news.flag_also = false; ui_news(g, &ns); ge->banner_dead = g->eto[api].banner; ge->race = g->eto[best_ai].banner; ge->type = GAME_END_LOST_FUNERAL; } 1oom-1.11.2/src/ui/classic/uicursor.c000066400000000000000000000174451476061725400173420ustar00rootroot00000000000000#include "config.h" #include #include "uicursor.h" #include "comp.h" #include "hw.h" #include "lbxpal.h" #include "mouse.h" #include "types.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ #define CURSOR_W 16 #define CURSOR_H 16 static ui_cursor_area_t *ui_cursor_area_def_ptr = 0; static int ui_cursor_area_def_num = 1; static uint16_t ui_cursor_gfx_i_old = 0; struct cursor_bg_s { int x, y; uint8_t data[CURSOR_W * CURSOR_H * UI_SCALE_MAX * UI_SCALE_MAX]; }; static struct cursor_bg_s cursor_bg0; static struct cursor_bg_s cursor_bg1; static bool cursor_i0_bg_stored = false; /* -------------------------------------------------------------------------- */ static const ui_cursor_area_t ui_cursor_area_all_i0_default = { 0, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }; static const ui_cursor_area_t ui_cursor_area_all_i1_default = { 1, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }; static const ui_cursor_area_t ui_cursor_area_tbl_default[UI_CURSOR_AREA_NUM] = { /*0*/ { 1, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*1*/ { 1, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*2*/ { 8, 0, UI_CURSOR_SCALE_MODE_STARMAP, 3, 2, 218, 174 }, /*3*/ { 1, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*4*/ { 7, 4, UI_CURSOR_SCALE_MODE_STARMAP, 3, 2, 218, 174 }, /*5*/ { 1, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*6*/ { 7, 4, UI_CURSOR_SCALE_MODE_STARMAP, 3, 2, 218, 174 }, /*7*/ { 5, 0, UI_CURSOR_SCALE_MODE_STARMAP, 0, 0, 0, 0 }, /*8*/ { 9, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*9*/ { 10, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 }, /*a*/ { 11, 0, UI_CURSOR_SCALE_MODE_NORMAL, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1 } }; ui_cursor_area_t ui_cursor_area_all_i0 = {0}; ui_cursor_area_t ui_cursor_area_all_i1 = {0}; ui_cursor_area_t ui_cursor_area_tbl[UI_CURSOR_AREA_NUM] = {0}; uint16_t ui_cursor_mouseoff = 0; uint16_t ui_cursor_gfx_i = 0; /* -------------------------------------------------------------------------- */ static void ui_cursor_clamp_xy(int *mx, int *my) { if (*mx < 0) { *mx = 0; } if (*my < 0) { *my = 0; } if (*mx >= UI_SCREEN_W) { *mx = UI_SCREEN_W - 1; } if (*my >= UI_SCREEN_H) { *my = UI_SCREEN_H - 1; } } static void ui_cursor_store_bg(int mx, int my, uint8_t *p, struct cursor_bg_s *bg) { int w, h; uint8_t *q = bg->data; ui_cursor_clamp_xy(&mx, &my); bg->x = mx; bg->y = my; p += my * UI_SCREEN_W + mx; w = CURSOR_W * mouse_cursor_scale; if ((mx + w) > UI_SCREEN_W) { w = UI_SCREEN_W - mx; } h = CURSOR_H * mouse_cursor_scale; if ((my + h) > UI_SCREEN_H) { h = UI_SCREEN_H - my; } for (int y = 0; y < h; ++y) { memcpy(q, p, w); p += UI_SCREEN_W; q += w; } } static void ui_cursor_draw(int mx, int my, uint8_t *p) { if (ui_cursor_gfx_i == 0) { return; } int w, h; uint8_t *q = lbxpal_cursors + ((ui_cursor_gfx_i - 1) * CURSOR_W * CURSOR_H); ui_cursor_clamp_xy(&mx, &my); p += my * UI_SCREEN_W + mx; w = CURSOR_W * mouse_cursor_scale; if ((mx + w) > UI_SCREEN_W) { w = UI_SCREEN_W - mx; } h = CURSOR_H * mouse_cursor_scale; if ((my + h) > UI_SCREEN_H) { h = UI_SCREEN_H - my; } for (int y = 0; y < h; ++y) { for (int x = 0; x < w; ++x) { uint8_t b = q[x / mouse_cursor_scale * CURSOR_W]; if (b) { p[x] = b; } } p += UI_SCREEN_W; if ((y + 1) % mouse_cursor_scale == 0) { ++q; } } } static void ui_cursor_erase(uint8_t *p, struct cursor_bg_s *bg) { int w, h; int mx = bg->x; int my = bg->y; uint8_t *q = bg->data; ui_cursor_clamp_xy(&mx, &my); p += my * UI_SCREEN_W + mx; w = CURSOR_W * mouse_cursor_scale; if ((mx + w) > UI_SCREEN_W) { w = UI_SCREEN_W - mx; } h = CURSOR_H * mouse_cursor_scale; if ((my + h) > UI_SCREEN_H) { h = UI_SCREEN_H - my; } for (int y = 0; y < h; ++y) { memcpy(p, q, w); p += UI_SCREEN_W; q += w; } } static void ui_cursor_init_do(int scale, const ui_cursor_area_t *src, ui_cursor_area_t *area) { *area = *src; area->x0 *= scale; area->x0 += area->mouseoff * (scale - 1); area->y0 *= scale; area->y0 += area->mouseoff * (scale - 1); if (area->x1 == (UI_VGA_W - 1)) { area->x1 = UI_SCREEN_W - 1; } else { area->x1 *= scale; area->x1 += area->mouseoff * (scale - 1); } if (area->y1 == (UI_VGA_H - 1)) { area->y1 = UI_SCREEN_H - 1; } else { area->y1 *= scale; area->y1 += area->mouseoff * (scale - 1); } } /* -------------------------------------------------------------------------- */ void ui_cursor_init(int scale) { ui_cursor_init_do(scale, &ui_cursor_area_all_i0_default, &ui_cursor_area_all_i0); ui_cursor_init_do(scale, &ui_cursor_area_all_i1_default, &ui_cursor_area_all_i1); for (int i = 0; i < TBLLEN(ui_cursor_area_tbl); ++i) { ui_cursor_init_do(scale, &ui_cursor_area_tbl_default[i], &ui_cursor_area_tbl[i]); } } void ui_cursor_setup_area(int num, ui_cursor_area_t *area) { ui_cursor_area_def_num = num; ui_cursor_area_def_ptr = area; if (--num > 0) { area += num; while (num && (area->x0 || area->y0)) { --num; --area; } } mouse_cursor_scale = (area->cursor_scale_mode == UI_CURSOR_SCALE_MODE_STARMAP) ? starmap_scale : ui_scale; ui_cursor_mouseoff = area->mouseoff * mouse_cursor_scale; ui_cursor_gfx_i = area->cursor_i; } void ui_cursor_update_gfx_i(int mx, int my) { int num = ui_cursor_area_def_num; ui_cursor_area_t *area = ui_cursor_area_def_ptr; ui_cursor_gfx_i_old = ui_cursor_gfx_i; if (!area) { return; } if (--num) { area += num; while ((num >= 0) && ((mx < area->x0) || (mx > area->x1) || (my < area->y0) || (my > area->y1))) { --num; --area; } } mouse_cursor_scale = (area->cursor_scale_mode == UI_CURSOR_SCALE_MODE_STARMAP) ? starmap_scale : ui_scale; ui_cursor_mouseoff = area->mouseoff * mouse_cursor_scale; ui_cursor_gfx_i = area->cursor_i; } void ui_cursor_store_bg1(int mx, int my) { if ((ui_cursor_gfx_i == 0) && (ui_cursor_gfx_i_old == 0)) { if (cursor_i0_bg_stored) { return; } cursor_i0_bg_stored = true; } ui_cursor_store_bg(mx, my, hw_video_get_buf(), &cursor_bg1); } void ui_cursor_store_bg0(int mx, int my) { if (ui_cursor_gfx_i == 0) { if (cursor_i0_bg_stored) { return; } cursor_i0_bg_stored = true; } ui_cursor_store_bg(mx, my, hw_video_get_buf_front(), &cursor_bg0); } void ui_cursor_draw1(int mx, int my) { if (ui_cursor_gfx_i != 0) { ui_cursor_draw(mx, my, hw_video_get_buf()); } } void ui_cursor_draw0(int mx, int my) { if (ui_cursor_gfx_i != 0) { ui_cursor_draw(mx, my, hw_video_get_buf_front()); } } void ui_cursor_erase0(void) { if (ui_cursor_gfx_i_old != 0) { ui_cursor_erase(hw_video_get_buf_front(), &cursor_bg0); } } void ui_cursor_erase1(void) { if (ui_cursor_gfx_i != 0) { ui_cursor_erase(hw_video_get_buf(), &cursor_bg1); } } void ui_cursor_copy_bg1_to_bg0(void) { memcpy(&cursor_bg0, &cursor_bg1, sizeof(cursor_bg0)); } void ui_cursor_refresh(int mx, int my) { if (ui_cursor_gfx_i == 0) { return; } ui_cursor_store_bg0(mx, my); ui_cursor_draw0(mx, my); hw_video_redraw_front(); ui_cursor_erase0(); } 1oom-1.11.2/src/ui/classic/uicursor.h000066400000000000000000000023031476061725400173320ustar00rootroot00000000000000#ifndef INC_1OOM_UICURSOR_H #define INC_1OOM_UICURSOR_H #include "types.h" typedef enum { UI_CURSOR_SCALE_MODE_NORMAL, UI_CURSOR_SCALE_MODE_STARMAP, } ui_cursor_scale_mode_t; typedef struct ui_cursor_area_s { uint8_t cursor_i; uint8_t mouseoff; uint8_t cursor_scale_mode; uint16_t x0; uint16_t y0; uint16_t x1; /* inclusive */ uint16_t y1; /* inclusive */ } ui_cursor_area_t; extern ui_cursor_area_t ui_cursor_area_all_i0; extern ui_cursor_area_t ui_cursor_area_all_i1; #define UI_CURSOR_AREA_NUM 11 extern ui_cursor_area_t ui_cursor_area_tbl[UI_CURSOR_AREA_NUM]; /* not const! */ extern uint16_t ui_cursor_gfx_i; extern uint16_t ui_cursor_mouseoff; extern void ui_cursor_init(int scale); extern void ui_cursor_setup_area(int num, ui_cursor_area_t *area); extern void ui_cursor_update_gfx_i(int mx, int my); extern void ui_cursor_store_bg1(int mx, int my); extern void ui_cursor_store_bg0(int mx, int my); extern void ui_cursor_draw1(int mx, int my); extern void ui_cursor_draw0(int mx, int my); extern void ui_cursor_erase0(void); extern void ui_cursor_erase1(void); extern void ui_cursor_copy_bg1_to_bg0(void); extern void ui_cursor_refresh(int mx, int my); #endif 1oom-1.11.2/src/ui/classic/uidefs.h000066400000000000000000000226211476061725400167430ustar00rootroot00000000000000#ifndef INC_1OOM_UIDEFS_H #define INC_1OOM_UIDEFS_H #include "boolvec.h" #include "game.h" #include "game_planet.h" #include "game_types.h" #include "gfxaux.h" #include "osdefs.h" #include "ui.h" #include "types.h" #ifdef OS_UI_SCALE_MAX #define UI_SCALE_MAX OS_UI_SCALE_MAX #else #define UI_SCALE_MAX 6 #endif #define UI_SCROLL_SPEED_MAX 10 #define UI_VGA_W 320 #define UI_VGA_H 200 #define UI_SCREEN_W ui_screen_w #define UI_SCREEN_H ui_screen_h #define NUM_SOUNDS 0x29 #define NUM_MUSICS 0x28 typedef enum { UI_MAIN_LOOP_STARMAP = 0, UI_MAIN_LOOP_GAMEOPTS, /*1*/ UI_MAIN_LOOP_DESIGN, /*2*/ UI_MAIN_LOOP_FLEET, /*3*/ UI_MAIN_LOOP_MAP, /*4*/ UI_MAIN_LOOP_RACES, /*5*/ UI_MAIN_LOOP_PLANETS, /*6*/ UI_MAIN_LOOP_TECH, /*7*/ UI_MAIN_LOOP_NEXT_TURN, /*8*/ UI_MAIN_LOOP_RELOC, /*9*/ UI_MAIN_LOOP_TRANS, /*a*/ UI_MAIN_LOOP_STARVIEW, /*b*/ UI_MAIN_LOOP_ORBIT_OWN_SEL, /*c*/ UI_MAIN_LOOP_TRANSPORT_SEL, /*d*/ UI_MAIN_LOOP_ENROUTE_SEL, /*e*/ UI_MAIN_LOOP_SPECS, /*f*/ UI_MAIN_LOOP_MUSTSCRAP, /*10*/ UI_MAIN_LOOP_EMPIRESTATUS, /*12*/ UI_MAIN_LOOP_EMPIREREPORT, /*13*/ UI_MAIN_LOOP_AUDIENCE, /*14*/ UI_MAIN_LOOP_ORBIT_EN_SEL, /*15*/ UI_MAIN_LOOP_SCRAP_BASES, /*16*/ UI_MAIN_LOOP_SPIES_CAUGHT, /*17*/ UI_MAIN_LOOP_PLANET_SHIPS, UI_MAIN_LOOP_NUM } ui_main_loop_action_t; typedef enum { UI_SM_STAR_TEXT_NAME, UI_SM_STAR_TEXT_POPULATION, UI_SM_STAR_TEXT_DISTANCE, UI_SM_STAR_TEXT_ENVIRONMENT, UI_SM_STAR_TEXT_SPECIAL, UI_SM_STAR_TEXT_NUM, } ui_starmap_star_text_t; struct ui_data_s { uint32_t seed; uint8_t *sfx[NUM_SOUNDS]; uint8_t *mus; int music_i; struct { struct { uint8_t *nebula[NEBULA_MAX]; /* varies based on game data */ uint8_t *smnebula[NEBULA_MAX]; /* varies based on game data */ uint8_t *bmap; /* varies based on game data */ /* every other gfx.* is the same for every game */ uint8_t *mainview; uint8_t *starback; uint8_t *starbak2; uint8_t *stars[12]; uint8_t *planbord; uint8_t *yourplnt; uint8_t *unexplor; uint8_t *en_colny; uint8_t *no_colny; uint8_t *col_butt_ship; uint8_t *col_butt_reloc; uint8_t *col_butt_trans; uint8_t *sky; uint8_t *smstars[6]; uint8_t *smalflag[BANNER_NUM]; uint8_t *stargate; /* starmap.lbx */ uint8_t *smallstr; uint8_t *smneb[4 * 10]; /* 10.. from nebula.lbx */ uint8_t *relocate; uint8_t *reloc_bu_cancel; uint8_t *reloc_bu_accept; uint8_t *tran_bar; uint8_t *smalship[BANNER_NUM]; uint8_t *smaltran[BANNER_NUM]; uint8_t *tinyship[BANNER_NUM]; uint8_t *tinytran[BANNER_NUM]; uint8_t *move_shi; uint8_t *move_but_p; uint8_t *move_but_m; uint8_t *move_but_a; uint8_t *move_but_n; uint8_t *shipbord; uint8_t *movextra; uint8_t *movextr2; uint8_t *movextr3; uint8_t *scanner; uint8_t *tranship; uint8_t *tranbord; uint8_t *tranxtra; uint8_t *dismiss; uint8_t *fleetbut_view; uint8_t *fleetbut_scrap; uint8_t *fleetbut_ok; uint8_t *fleetbut_down; uint8_t *fleetbut_up; uint8_t *viewship; uint8_t *viewshp2; uint8_t *viewshbt; uint8_t *scrap; uint8_t *scrapbut_no; uint8_t *scrapbut_yes; uint8_t *reprtbut_ok; uint8_t *reprtbut_up; uint8_t *reprtbut_down; uint8_t *gr_arrow_u; uint8_t *gr_arrow_d; uint8_t *slanbord; uint8_t *stargate2; /* v11.lbx */ } starmap; struct { uint8_t *planet[0x23]; uint8_t *race[10]; uint8_t *smonster; uint8_t *tmonster; } planets; uint8_t *ships[0x48 * 2 + 3]; /* 0..0x47 from ships2, 0x48.. from ships */ struct { uint8_t *tech_but_up; uint8_t *tech_but_down; uint8_t *tech_but_ok; uint8_t *litebulb_off; uint8_t *litebulb_on; uint8_t *techback; uint8_t *race_pnt; struct { uint8_t *sabotage; uint8_t *espionage; uint8_t *hiding; uint8_t *status; uint8_t *report; uint8_t *audience; uint8_t *ok; } races_bu; } screens; struct { uint8_t *bg; uint8_t *blank; uint8_t *icon_dn; uint8_t *icon_up; uint8_t *count_up; uint8_t *count_dn; uint8_t *pop1_ul; uint8_t *pop1_ur; uint8_t *pop1_dl; uint8_t *pop1_dr; /* planets.lbx 0x31 */ uint8_t *titlebox; uint8_t *popscrol_u; uint8_t *popscrol_d; } design; struct { uint8_t *bg[5]; uint8_t *box; uint8_t *box_x; uint8_t *box_y; uint8_t *box_xy; uint8_t *done; uint8_t *retreat; uint8_t *retr_off; uint8_t *wait; uint8_t *autob; uint8_t *special; uint8_t *spec_off; uint8_t *scan; uint8_t *scan_off; uint8_t *planet; uint8_t *planet_off; uint8_t *explos[10]; uint8_t *warp1; uint8_t *warp2; uint8_t *warp3; uint8_t *warp4; uint8_t *technull; uint8_t *misbutt; uint8_t *misl_off; uint8_t *warpout; uint8_t *envterm; uint8_t *enviro; uint8_t *base_btn; uint8_t *dis_bem2; uint8_t *stasis2; uint8_t *vs2; uint8_t *vp2_top; uint8_t *vp2_data; uint8_t *vp2_line; uint8_t *vp2_bottom; uint8_t *blk_hole; uint8_t *bombs; uint8_t *biologic; uint8_t *circle; uint8_t *sphere2; uint8_t *asteroid[4]; } space; struct { /* directions: u, ur, r, dr, d, dl, l, ul */ uint8_t *missiles[8]; uint8_t *antimatr[8]; uint8_t *hellfire[8]; uint8_t *proton[8]; uint8_t *plasmaqt[8]; } missile; struct { uint8_t *d[0x1c]; uint8_t *current; } colonies; struct { uint8_t *tv; uint8_t *gnn; uint8_t *nc; uint8_t *world; uint8_t *icon; bool flag_also; } news; uint8_t *vgafileh; bool initialized; } gfx; struct { int x; int y; int x2; int y2; int xhold; int yhold; bool flag_show_grid; bool flag_show_own_routes; ui_starmap_star_text_t star_text_type; int line_anim_phase; int frame_ship; int frame_scanner; int scanner_delay; int stars_xoff1; int stars_xoff2; struct gfx_aux_s star_aux; int fleet_selected; int orbit_player; BOOLVEC_DECLARE(select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_DECLARE(select_prio_trans, TRANSPORT_MAX); } starmap; struct { struct gfx_aux_s screen; struct gfx_aux_s ship_p1; struct gfx_aux_s ship_overlay; struct gfx_aux_s btemp; } aux; struct { bool flag_also; } news; struct { const struct game_s *g; uint16_t index[FLEET_ENROUTE_MAX + PLANETS_MAX]; uint32_t value[FLEET_ENROUTE_MAX + PLANETS_MAX]; int fleet_order[PLAYER_NUM]; int planets_order[PLAYER_NUM]; int weapon_type[PLAYER_NUM]; } sorted; /* global for qsort */ struct { bool show_grid; } battle; uint8_t star_frame[PLANETS_MAX]; ui_main_loop_action_t ui_main_loop_action; ui_main_loop_action_t ui_main_loop_action_prev; ui_main_loop_action_t ui_main_loop_action_next; uint8_t start_planet_focus_i; bool flag_scrap_for_new_design; bool have_help; BOOLVEC_DECLARE(players_viewing, PLAYER_NUM); char strbuf[UI_STRBUF_SIZE]; }; extern struct ui_data_s ui_data; extern int ui_scale; extern int ui_scale_hint; extern int starmap_scale; extern int ui_screen_w; extern int ui_screen_h; extern bool ui_extra_enabled; extern bool ui_fixbugs_enabled; extern bool ui_illogical_hotkey_fix; extern bool ui_load_opts_extra; extern bool ui_space_combat_autoresolve; extern bool ui_sm_ships_enabled; extern bool ui_sm_expanded_scroll; extern bool ui_sm_no_question_mark_cursor; extern bool ui_sm_explicit_cursor_context; extern bool ui_mouse_lmb_fix; extern bool ui_mouse_warp_disabled; extern bool ui_copyprotection_disabled; extern bool ui_sm_mouseover_focus; extern bool ui_sm_smoother_scrolling; extern bool ui_sm_mouse_scroll; extern bool ui_sm_uhjk_scroll; extern bool ui_kbd_cursor_keys_fix; extern bool ui_mwi_slider; extern bool ui_mwi_counter; extern int ui_sm_scroll_speed; extern bool ui_kbd_repeat; extern void ui_extra_toggle_preset(bool enabled); #endif 1oom-1.11.2/src/ui/classic/uidelay.c000066400000000000000000000032531476061725400171130ustar00rootroot00000000000000#include "config.h" #include #include "uidelay.h" #include "hw.h" #include "mouse.h" #include "types.h" #include "uicursor.h" /* -------------------------------------------------------------------------- */ #define DELAY_EVENT_HANDLE_LIMIT 12500 #define DELAY_MOUSE_UPDATE_LIMIT 20000 static int64_t delay_start; /* -------------------------------------------------------------------------- */ void ui_delay_prepare(void) { delay_start = hw_get_time_us(); } bool ui_delay_ticks_or_click(int ticks) { return ui_delay_us_or_click(MOO_TICKS_TO_US(ticks)); } bool ui_delay_us_or_click(uint32_t delay) { bool pressed = false; int mx = moouse_x, my = moouse_y; int64_t mouse_time = hw_get_time_us(); hw_event_handle(); while (1) { int64_t diff; int64_t now; now = hw_get_time_us(); diff = now - delay_start; if ((diff < 0) || (diff >= (int64_t)delay)) { return false; } if (diff < DELAY_EVENT_HANDLE_LIMIT) { continue; } hw_event_handle(); if (!pressed) { if (mouse_buttons) { pressed = true; } } else { if (!mouse_buttons) { return true; } } if (((mx != moouse_x) || (my != moouse_y)) && ((now - mouse_time) > DELAY_MOUSE_UPDATE_LIMIT)) { mouse_time = now; mx = moouse_x; my = moouse_y; ui_cursor_refresh(mx, my); } } } void ui_delay_1(void) { ui_delay_prepare(); ui_delay_ticks_or_click(1); } void ui_delay_1e(void) { ui_delay_prepare(); ui_delay_ticks_or_click(0x1e); } 1oom-1.11.2/src/ui/classic/uidelay.h000066400000000000000000000010461476061725400171160ustar00rootroot00000000000000#ifndef INC_1OOM_UIDELAY_H #define INC_1OOM_UIDELAY_H #include "types.h" /* The ticks used by MOO1 are from 0040:005C, which is incremented by INT 8 at 18.2 Hz. (FIXME ... unless the sound driver messes with it.) Hence the ratio 10000000 / 182 == */ #define MOO_TICKS_TO_US(_t_) (((_t_) * 5000000) / 91) extern void ui_delay_prepare(void); /* returns true if exit by click */ extern bool ui_delay_ticks_or_click(int ticks); extern bool ui_delay_us_or_click(uint32_t us); extern void ui_delay_1(void); extern void ui_delay_1e(void); #endif 1oom-1.11.2/src/ui/classic/uidesign.c000066400000000000000000001415521476061725400172730ustar00rootroot00000000000000#include "config.h" #include #include #include "uidesign.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_design.h" #include "game_misc.h" #include "game_num.h" #include "game_shiptech.h" #include "game_str.h" #include "game_tech.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "util.h" /* -------------------------------------------------------------------------- */ struct ui_design_data_s { struct design_data_s *d; int16_t oi_tbl_weap[WEAPON_SLOT_NUM]; int16_t oi_tbl_weap_up[WEAPON_SLOT_NUM]; /* + 1 */ int16_t oi_tbl_weap_dn[WEAPON_SLOT_NUM]; /* + 2 */ int16_t oi_tbl_weap_n_scroll[WEAPON_SLOT_NUM]; int16_t oi_cancel; int16_t oi_build; int16_t oi_clear; int16_t oi_name; int16_t oi_idn; int16_t oi_iup; int16_t oi_iscroll; int16_t oi_man; int16_t oi_comp; int16_t oi_jammer; int16_t oi_shield; int16_t oi_armor; int16_t oi_engine; int16_t oi_tbl_spec[SPECIAL_SLOT_NUM]; int16_t oi_tbl_hull[SHIP_HULL_NUM]; int16_t oi_icon; int16_t scroll; }; static const uint8_t colortbls_sd[] = { /*00*/ 0x45, 0x44, 0x42, 0x41, 0x40, 0x3f, 0x30, 0x26, /*08*/ 0x80, 0x00, /*0a*/ 0xbc, 0xb9, 0xb9, /*0d*/ 0xb6, 0xb6, 0xb6, /*10*/ 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, /*15*/ 0xba, 0xba, 0xba, 0xba, 0xba, /*padding*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; static uint8_t const * const colortbl_sd_textinput = &colortbls_sd[0x00]; static uint8_t const * const colortbl_sd_bc = &colortbls_sd[0x0a]; static uint8_t const * const colortbl_sd_b6 = &colortbls_sd[0x0d]; static uint8_t const * const colortbl_sd_bf = &colortbls_sd[0x10]; static uint8_t const * const colortbl_sd_ba = &colortbls_sd[0x15]; /* -------------------------------------------------------------------------- */ static void design_draw_cb(void *vptr) { struct ui_design_data_s *u = vptr; struct design_data_s *d = u->d; shipdesign_t *sd = &(d->gd->sd); int16_t oi; char buf[64]; uint8_t extraman; ui_draw_filled_rect(5, 5, 315, 195, 1, ui_scale); lbxgfx_draw_frame(0, 0, ui_data.gfx.design.bg, UI_SCREEN_W, ui_scale); oi = uiobj_get_clicked_oi(); lbxfont_select(0, 6, 0, 3); lbxfont_set_colors(((u->oi_comp == oi) || d->flag_disable_comp) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(17, 22, game_str_sd_comp, UI_SCREEN_W, ui_scale); lbxfont_set_colors(((u->oi_shield == oi) || d->flag_disable_shield) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(17, 34, game_str_sd_shield, UI_SCREEN_W, ui_scale); lbxfont_set_colors(((u->oi_jammer == oi) || d->flag_disable_jammer) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(17, 46, game_str_sd_ecm, UI_SCREEN_W, ui_scale); lbxfont_set_colors(((u->oi_armor == oi) || d->flag_disable_armor) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(167, 22, game_str_sd_armor, UI_SCREEN_W, ui_scale); lbxfont_set_colors(((u->oi_engine == oi) || d->flag_disable_engine) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(167, 34, game_str_sd_engine, UI_SCREEN_W, ui_scale); lbxfont_set_colors(((u->oi_man == oi) || d->flag_disable_cspeed) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(167, 46, game_str_sd_man, UI_SCREEN_W, ui_scale); for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { lbxfont_set_colors(((u->oi_tbl_spec[i] == oi) || d->flag_tbl_special[i]) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(17, 116 + i * 10, game_str_tbl_sd_spec[i], UI_SCREEN_W, ui_scale); } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { lbxfont_set_colors(((u->oi_tbl_weap[i] == oi) || d->flag_tbl_weapon[i]) ? colortbl_sd_ba : colortbl_sd_bf); lbxfont_print_str_normal(17, 71 + i * 10, game_str_tbl_sd_weap[i], UI_SCREEN_W, ui_scale); } lbxfont_select(0, 6, 0, 3); lbxfont_set_colors(colortbl_sd_bf); lbxfont_print_str_normal(59, 61, game_str_sd_count, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(88, 61, game_str_sd_sweap, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(163, 61, game_str_sd_damage, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(196, 61, game_str_sd_rng, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(215, 61, game_str_sd_notes, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0, 0, 3); lbxfont_print_str_normal(262, 163, game_str_bc, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(257, 163, sd->cost, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(270, 175, game_design_get_hull_space(d->gd), UI_SCREEN_W, ui_scale); lbxfont_print_num_right(270, 187, sd->space, UI_SCREEN_W, ui_scale); { ship_hull_t acthull; acthull = sd->hull; for (ship_hull_t i = SHIP_HULL_SMALL; i < SHIP_HULL_NUM; ++i) { lbxfont_select(0, 0, 4, 7); if (d->flag_tbl_hull[i]) { lbxfont_select_subcolors_13not2(); uiobj_ta_set_val_0(u->oi_tbl_hull[i]); } else { if (i != acthull) { lbxfont_select_subcolors_13not1(); } uiobj_ta_set_val_1(u->oi_tbl_hull[i]); } lbxfont_print_str_center(38, 163 + i * 7, *tbl_shiptech_hull[i].nameptr, UI_SCREEN_W, ui_scale); } } { ship_hull_t hull = sd->hull; uint8_t look, lookbase; lookbase = SHIP_LOOK_PER_HULL * hull + d->gd->lookbase; look = sd->look; if ((look < lookbase) || (look >= (lookbase + SHIP_LOOK_PER_HULL))) { sd->look = look = d->gd->tbl_shiplook_hull[hull]; } lbxgfx_set_frame_0(ui_data.gfx.ships[look]); lbxgfx_draw_frame(93, 165, ui_data.gfx.ships[look], UI_SCREEN_W, ui_scale); } lbxfont_select(2, 8, 0, 8); lbxfont_set_colors(colortbl_sd_b6); for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi; wi = sd->wpnt[i]; if (wi != WEAPON_NONE) { lbxfont_print_str_normal(88, 73 + i * 10, *tbl_shiptech_weap[wi].nameptr, UI_SCREEN_W, ui_scale); } } lbxfont_print_str_normal(200, 22, *tbl_shiptech_armor[sd->armor].nameptr, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(200, 34, *tbl_shiptech_engine[sd->engine].nameptr, UI_SCREEN_W, ui_scale); { uint8_t v; extraman = 0; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { v = tbl_shiptech_special[sd->special[i]].extraman; SETMAX(extraman, v); } v = extraman + sd->man + 1; lbxfont_print_num_right(220, 46, v, UI_SCREEN_W, ui_scale); } if (sd->comp) { lbxfont_print_str_normal(60, 22, *tbl_shiptech_comp[sd->comp].nameptr, UI_SCREEN_W, ui_scale); } if (sd->shield) { lbxfont_print_str_normal(60, 34, *tbl_shiptech_shield[sd->shield].nameptr, UI_SCREEN_W, ui_scale); } if (sd->jammer) { lbxfont_print_str_normal(60, 46, *tbl_shiptech_jammer[sd->jammer].nameptr, UI_SCREEN_W, ui_scale); } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t si; si = sd->special[i]; if (si != SHIP_SPECIAL_NONE) { lbxfont_print_str_normal(61, 116 + i * 10, *tbl_shiptech_special[si].nameptr, UI_SCREEN_W, ui_scale); } } lbxfont_select(2, 8, 3, 2); lbxfont_set_colors(colortbl_sd_bc); for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi; wi = sd->wpnt[i]; if (wi != WEAPON_NONE) { int y, dmin, dmax; y = 73 + i * 10; lbxfont_print_str_normal(215, y, *tbl_shiptech_weap[wi].extratextptr, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(77, y, sd->wpnn[i], UI_SCREEN_W, ui_scale); lbxfont_print_num_right(207, y, tbl_shiptech_weap[wi].range, UI_SCREEN_W, ui_scale); dmin = tbl_shiptech_weap[wi].damagemin; dmax = tbl_shiptech_weap[wi].damagemax; if (dmin != dmax) { lbxfont_print_range_right(188, y, dmin, dmax, UI_SCREEN_W, ui_scale); } else { lbxfont_print_num_right(188, y, dmin, UI_SCREEN_W, ui_scale); } } } lbxfont_print_str_normal(250, 22, game_str_sd_hp, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(302, 22, sd->hp, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(250, 34, game_str_sd_warp, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(272, 34, tbl_shiptech_engine[sd->engine].warp, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(280, 34, game_str_sd_def, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(250, 46, game_str_sd_cspeed, UI_SCREEN_W, ui_scale); /* FIXME these calculations should be a function somewhere else */ { uint8_t v; v = extraman + sd->man + tbl_shiptech_hull[sd->hull].defense + 1; lbxfont_print_num_right(302, 34, v, UI_SCREEN_W, ui_scale); v = (extraman / 2) + (sd->man + 3) / 2; lbxfont_print_num_right(302, 46, v, UI_SCREEN_W, ui_scale); } if (sd->shield) { uint8_t v = tbl_shiptech_shield[sd->shield].absorb; lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sd_absorbs, v, (v == 1) ? game_str_sd_hit : game_str_sd_hits); lbxfont_print_str_normal(101, 34, buf, UI_SCREEN_W, ui_scale); } lbxfont_print_str_normal(101, 46, game_str_sd_misdef, UI_SCREEN_W, ui_scale); { uint8_t v; v = extraman + sd->man + tbl_shiptech_jammer[sd->jammer].level + tbl_shiptech_hull[sd->hull].defense + 1; lbxfont_print_num_right(155, 46, v, UI_SCREEN_W, ui_scale); } lbxfont_print_str_normal(101, 22, game_str_sd_att, UI_SCREEN_W, ui_scale); { uint16_t v = 0; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { v |= tbl_shiptech_special[sd->special[i]].boolmask; } v = tbl_shiptech_comp[sd->comp].level + ((v & (1 << SHIP_SPECIAL_BOOL_SCANNER)) ? 1 : 0); lbxfont_print_num_right(155, 22, v, UI_SCREEN_W, ui_scale); } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t si; si = sd->special[i]; if (si != SHIP_SPECIAL_NONE) { lbxfont_print_str_normal(172, (116 + i * 10), *tbl_shiptech_special[si].extratextptr, UI_SCREEN_W, ui_scale); } } } static void design_clear_ois(struct ui_design_data_s *u) { for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { u->oi_tbl_weap[i] = UIOBJI_INVALID; u->oi_tbl_weap_up[i] = UIOBJI_INVALID; u->oi_tbl_weap_dn[i] = UIOBJI_INVALID; u->oi_tbl_weap_n_scroll[i] = UIOBJI_INVALID; } u->oi_cancel = UIOBJI_INVALID; u->oi_build = UIOBJI_INVALID; u->oi_clear = UIOBJI_INVALID; u->oi_name = UIOBJI_INVALID; u->oi_idn = UIOBJI_INVALID; u->oi_iup = UIOBJI_INVALID; u->oi_iscroll = UIOBJI_INVALID; u->oi_man = UIOBJI_INVALID; u->oi_comp = UIOBJI_INVALID; u->oi_jammer = UIOBJI_INVALID; u->oi_shield = UIOBJI_INVALID; u->oi_armor = UIOBJI_INVALID; u->oi_engine = UIOBJI_INVALID; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { u->oi_tbl_spec[i] = UIOBJI_INVALID; } for (int i = 0; i < SHIP_HULL_NUM; ++i) { u->oi_tbl_hull[i] = UIOBJI_INVALID; } u->oi_icon = UIOBJI_INVALID; u->scroll = 0; } static void design_init_ois(struct ui_design_data_s *u) { struct design_data_s *d = u->d; lbxfont_select(0, 1, 0, 3); u->oi_iup = uiobj_add_t0(143, 162, "", ui_data.gfx.design.icon_up, MOO_KEY_UNKNOWN); u->oi_idn = uiobj_add_t0(143, 179, "", ui_data.gfx.design.icon_dn, MOO_KEY_UNKNOWN); u->oi_icon = uiobj_add_mousearea(89, 161, 128, 192, MOO_KEY_UNKNOWN); u->oi_iscroll = uiobj_add_mousewheel(89, 161, 150, 192, &u->scroll); lbxfont_select(2, 6, 0, 3); u->oi_cancel = uiobj_add_t0(282, 150, game_str_sd_cancel, ui_data.gfx.design.blank, MOO_KEY_ESCAPE); u->oi_build = uiobj_add_t0(282, 182, game_str_sd_build, ui_data.gfx.design.blank, MOO_KEY_b); u->oi_clear = uiobj_add_t0(282, 166, game_str_sd_clear, ui_data.gfx.design.blank, MOO_KEY_c); lbxfont_select(0, 0, 5, 3); u->oi_name = uiobj_add_textinput(214, 151, 56, d->gd->sd.name, SHIP_NAME_LEN - 1, 1, true, false, colortbl_sd_textinput, MOO_KEY_UNKNOWN); uiobj_dec_y1(u->oi_name); SETMIN(d->gd->sd.man, d->gd->sd.engine); u->oi_man = uiobj_add_mousearea(167, 45, 305, 52, MOO_KEY_UNKNOWN); u->oi_comp = uiobj_add_mousearea(17, 21, 155, 28, MOO_KEY_UNKNOWN); u->oi_jammer = uiobj_add_mousearea(17, 45, 155, 52, MOO_KEY_UNKNOWN); u->oi_shield = uiobj_add_mousearea(17, 33, 155, 48, MOO_KEY_UNKNOWN); u->oi_armor = uiobj_add_mousearea(167, 21, 305, 28, MOO_KEY_UNKNOWN); u->oi_engine = uiobj_add_mousearea(167, 33, 305, 40, MOO_KEY_UNKNOWN); lbxfont_select(0, 0, 7, 5); for (int i = 0; i < SHIP_HULL_NUM; ++i) { const int y[SHIP_HULL_NUM] = { 162, 169, 176, 184 }; u->oi_tbl_hull[i] = uiobj_add_mousearea(21, y[i], 57, y[i] + 7, MOO_KEY_UNKNOWN); } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { u->oi_tbl_weap_dn[i] = uiobj_add_t2(59, i * 10 + 74, "", ui_data.gfx.design.count_dn, &d->flag_tbl_weap_dn[i], MOO_KEY_UNKNOWN); u->oi_tbl_weap_up[i] = uiobj_add_t2(59, i * 10 + 69, "", ui_data.gfx.design.count_up, &d->flag_tbl_weap_up[i], MOO_KEY_UNKNOWN); u->oi_tbl_weap[i] = uiobj_add_mousearea(16, i * 10 + 70, 305, i * 10 + 77, MOO_KEY_UNKNOWN); u->oi_tbl_weap_n_scroll[i] = uiobj_add_mousewheel(59, i * 10 + 69, 80, i * 10 + 77, &u->scroll); } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { u->oi_tbl_spec[i] = uiobj_add_mousearea(17, 115 + i * 10, 305, 123 + i * 10, MOO_KEY_UNKNOWN); } u->scroll = 0; } struct xy_s { int x; int y; }; static struct xy_s ui_design_draw_selbox(int xpos, int xoff1, int xoff2, int xoff3, int n, const char *str) { struct xy_s xy; int x0, y0, x1, y1; x0 = (320 / 2 - 1) - (xpos + xoff1) / 2; x1 = x0 + xpos + 20; y0 = (200 / 2 - 1) - (n * 8 + 20) / 2; y1 = y0 + n * 8; SETMAX(x0, 0); SETMIN(x1, 159); SETMAX(y0, 0); if (ui_extra_enabled) { hw_video_copy_back_from_page3(); } else { ui_cursor_erase1(); /* HACK should not be needed */ } ui_draw_box_grain(x0 + 4, y0 + 4, x0 + xpos + xoff2, y1 + 20, 1, 2, 0x37, ui_scale); /*uiobj_set_limits(x0, y0, x1, y1);*/ lbxgfx_draw_frame_offs(x0, y0, ui_data.gfx.design.pop1_ul, x0, y0, x1, y1, UI_SCREEN_W, ui_scale); /*uiobj_set_limits(x1, y0, UI_SCREEN_W - 1, y1);*/ lbxgfx_draw_frame_offs(x0 + xpos + xoff3, y0, ui_data.gfx.design.pop1_ur, x1, y0, UI_SCREEN_W - 1, y1, UI_SCREEN_W, ui_scale); /*uiobj_set_limits(x0, y1, x1, UI_SCREEN_H - 1);*/ lbxgfx_draw_frame_offs(x0, y1, ui_data.gfx.design.pop1_dl, x0, y1, x1, UI_SCREEN_H - 1, UI_SCREEN_W, ui_scale); /*uiobj_set_limits(x1, y1, UI_SCREEN_W - 1, UI_SCREEN_H - 1);*/ lbxgfx_draw_frame_offs(x0 + xpos + xoff3, y1, ui_data.gfx.design.pop1_dr, x1, y1, UI_SCREEN_W - 1, UI_SCREEN_H - 1, UI_SCREEN_W, ui_scale); /*uiobj_set_limits_all();*/ lbxgfx_draw_frame(118, y0 + 3, ui_data.gfx.design.titlebox, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xe, 0xe, 0xe); lbxfont_print_str_center(159, y0 + 5, str, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); lbxfont_select(2, 0, 4, 0xe); xy.x = x0; xy.y = y0; return xy; } static void ui_design_sel_comp(struct design_data_s *d) { int8_t havebuf[SHIP_COMP_NUM]; bool flag_tbl_enable[SHIP_COMP_NUM]; ship_comp_t tbl_comp[SHIP_COMP_NUM]; int xpos, n = 0; int16_t curcomp; char titlebuf[0x80]; char linebuf[SHIP_COMP_NUM * 0x50]; const char *lineptr[SHIP_COMP_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_comp_t actcomp = sd->comp; lbxfont_select(2, 0, 4, 0xe); { int havelast, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; xpos = 0; for (int i = 0; i < SHIP_COMP_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_comp[i].nameptr); SETMAX(xpos, w); } xpos += 20; s1[1] = (char)(xpos + 8); s2[1] = (char)(xpos + 33); s3[1] = (char)(xpos + 56); s4[1] = (char)(xpos + 85); sd->comp = 0; game_design_update_engines(sd); space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); havelast = game_design_build_tbl_fit_comp(d->g, d->gd, havebuf); /* game_design_build_tbl_fit_comp ensures that havelast < SHIP_COMP_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int space2, power, cost2, sizei; flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actcomp) { curcomp = n; } tbl_comp[n] = i; sd->comp = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(d->gd); power = tbl_shiptech_comp[i].power[sd->hull]; cost2 = game_design_calc_cost(d->gd) - cost; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_COMP, i); strbuild_catf(&line_builder, "%s%s%i%s%i%s%i%s%i", *tbl_shiptech_comp[i].nameptr, s1, cost2, s2, sizei, s3, power, s4, space2); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s%s", game_str_sd_comptype, s1, game_str_sd_cost, s2, game_str_sd_size, s3, game_str_sd_power, s4, game_str_sd_space); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 130, 125, -30, n + 2, game_str_sd_comps); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 103, titlebuf, lineptr, &curcomp, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->comp = actcomp; } else { sd->comp = tbl_comp[listi]; } game_design_update_engines(sd); } } static void ui_design_sel_shield(struct design_data_s *d) { int8_t havebuf[SHIP_SHIELD_NUM]; bool flag_tbl_enable[SHIP_SHIELD_NUM]; ship_shield_t tbl_shield[SHIP_SHIELD_NUM]; int xpos, n = 0; int16_t curshield; char titlebuf[0x80]; char linebuf[SHIP_SHIELD_NUM * 0x50]; const char *lineptr[SHIP_SHIELD_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_shield_t actshield = sd->shield; lbxfont_select(2, 0, 4, 0xe); { int havelast, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; xpos = 0; for (int i = 0; i < SHIP_SHIELD_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_shield[i].nameptr); SETMAX(xpos, w); } xpos += 20; s1[1] = (char)(xpos + 8); s2[1] = (char)(xpos + 33); s3[1] = (char)(xpos + 56); s4[1] = (char)(xpos + 85); sd->shield = 0; game_design_update_engines(sd); space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); havelast = game_design_build_tbl_fit_shield(d->g, d->gd, havebuf); /* game_design_build_tbl_fit_shield ensures that havelast < SHIP_SHIELD_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int space2, power, cost2, sizei; flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actshield) { curshield = n; } tbl_shield[n] = i; sd->shield = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(d->gd); power = tbl_shiptech_shield[i].power[sd->hull]; cost2 = game_design_calc_cost(d->gd) - cost; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_SHIELD, i); strbuild_catf(&line_builder, "%s%s%i%s%i%s%i%s%i", *tbl_shiptech_shield[i].nameptr, s1, cost2, s2, sizei, s3, power, s4, space2); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s%s", game_str_sd_shieldtype, s1, game_str_sd_cost, s2, game_str_sd_size, s3, game_str_sd_power, s4, game_str_sd_space); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 130, 125, -30, n + 2, game_str_sd_shields); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 103, titlebuf, lineptr, &curshield, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->shield = actshield; } else { sd->shield = tbl_shield[listi]; } game_design_update_engines(sd); } } static void ui_design_sel_jammer(struct design_data_s *d) { int8_t havebuf[SHIP_JAMMER_NUM]; bool flag_tbl_enable[SHIP_JAMMER_NUM]; ship_jammer_t tbl_jammer[SHIP_JAMMER_NUM]; int xpos, n = 0; int16_t curjammer; char titlebuf[0x80]; char linebuf[SHIP_JAMMER_NUM * 0x50]; const char *lineptr[SHIP_SHIELD_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_jammer_t actjammer = sd->jammer; lbxfont_select(2, 0, 4, 0xe); { int havelast, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; xpos = 0; for (int i = 0; i < SHIP_JAMMER_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_jammer[i].nameptr); SETMAX(xpos, w); } xpos += 20; s1[1] = (char)(xpos + 8); s2[1] = (char)(xpos + 33); s3[1] = (char)(xpos + 56); s4[1] = (char)(xpos + 85); sd->jammer = 0; game_design_update_engines(sd); space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); havelast = game_design_build_tbl_fit_jammer(d->g, d->gd, havebuf); /* game_design_build_tbl_fit_jammer ensures that havelast < SHIP_JAMMER_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int space2, power, cost2, sizei; flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actjammer) { curjammer = n; } tbl_jammer[n] = i; sd->jammer = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(d->gd); power = tbl_shiptech_jammer[i].power[sd->hull]; cost2 = game_design_calc_cost(d->gd) - cost; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_JAMMER, i); strbuild_catf(&line_builder, "%s%s%i%s%i%s%i%s%i", *tbl_shiptech_jammer[i].nameptr, s1, cost2, s2, sizei, s3, power, s4, space2); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s%s", game_str_sd_ecmtype, s1, game_str_sd_cost, s2, game_str_sd_size, s3, game_str_sd_power, s4, game_str_sd_space); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 130, 125, -30, n + 2, game_str_sd_ecm2); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 103, titlebuf, lineptr, &curjammer, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->jammer = actjammer; } else { sd->jammer = tbl_jammer[listi]; } game_design_update_engines(sd); } } static void ui_design_sel_armor(struct design_data_s *d) { int8_t havebuf[SHIP_ARMOR_NUM]; bool flag_tbl_enable[SHIP_ARMOR_NUM]; ship_armor_t tbl_armor[SHIP_ARMOR_NUM]; int xpos, n = 0; int16_t curarmor; char titlebuf[0x80]; char linebuf[SHIP_ARMOR_NUM * 0x50]; const char *lineptr[SHIP_ARMOR_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_armor_t actarmor = sd->armor; lbxfont_select(2, 0, 4, 0xe); { int havelast; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; xpos = 0; for (int i = 0; i < SHIP_ARMOR_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_armor[i].nameptr); SETMAX(xpos, w); } s1[1] = (char)(xpos + 25); s2[1] = (char)(xpos + 50); havelast = game_design_build_tbl_fit_armor(d->g, d->gd, havebuf); /* game_design_build_tbl_fit_armor ensures that havelast < SHIP_ARMOR_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int cost2, sizei; flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actarmor) { curarmor = n; } tbl_armor[n] = i; sd->armor = i; game_design_update_engines(sd); cost2 = game_design_calc_cost_item(d->gd, DESIGN_SLOT_ARMOR, i); sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_ARMOR, i); strbuild_catf(&line_builder, "%s%s%i%s%i", *tbl_shiptech_armor[i].nameptr, s1, cost2, s2, sizei); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s", game_str_sd_armortype, s1, game_str_sd_cost, s2, game_str_sd_size); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 90, 85, -70, n + 2, game_str_sd_armor2); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 62, titlebuf, lineptr, &curarmor, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->armor = actarmor; } else { sd->armor = tbl_armor[listi]; } game_design_update_engines(sd); } } static void ui_design_sel_engine(struct design_data_s *d) { int8_t havebuf[SHIP_ENGINE_NUM]; bool flag_tbl_enable[SHIP_ENGINE_NUM]; ship_engine_t tbl_engine[SHIP_ENGINE_NUM]; int xpos, n = 0; int16_t curengine; char titlebuf[0x80]; char linebuf[SHIP_ENGINE_NUM * 0x50]; const char *lineptr[SHIP_ENGINE_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_engine_t actengine = sd->engine; lbxfont_select(2, 0, 4, 0xe); { int havelast; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; xpos = 0; for (int i = 0; i < SHIP_ENGINE_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_engine[i].nameptr); SETMAX(xpos, w); } s1[1] = (char)(xpos + 8); s2[1] = (char)(xpos + 33); s3[1] = (char)(xpos + 56); s4[1] = (char)(xpos + 105); sd->engine = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_engine(d->g, d->gd, havebuf); /* game_design_build_tbl_fit_engine ensures that havelast < SHIP_ENGINE_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int cost2, sizei, sizet, ne; flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actengine) { curengine = n; } tbl_engine[n] = i; sd->engine = i; game_design_update_engines(sd); ne = sd->engines; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_ENGINE, i); sizet = (sizei * ne) / 10; cost2 = game_design_calc_cost_item(d->gd, DESIGN_SLOT_ENGINE, i); strbuild_catf(&line_builder, "%s%s%i%s%i%s%i.%i%s%i", *tbl_shiptech_engine[i].nameptr, s1, cost2, s2, sizei, s3, ne / 10, ne % 10, s4, sizet); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s%s", game_str_sd_engtype, s1, game_str_sd_cost, s2, game_str_sd_size, s3, game_str_sd_numengs, s4, game_str_sd_space); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 155, 145, -7, n + 2, game_str_sd_engs); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 124, titlebuf, lineptr, &curengine, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->engine = actengine; } else { sd->engine = tbl_engine[listi]; } game_design_update_engines(sd); } } static void ui_design_sel_man(struct design_data_s *d) { bool flag_tbl_enable[SHIP_ENGINE_NUM]; int xpos, n = 0; int16_t curman; char titlebuf[0x80]; char linebuf[SHIP_ENGINE_NUM * 0x50]; const char *lineptr[SHIP_ENGINE_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_engine_t actman = sd->man; lbxfont_select(2, 0, 4, 0xe); { int havelast = sd->engine, powperwarp, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; xpos = 0; for (int i = 0; i <= havelast; ++i) { int w; lib_sprintf(linebuf, sizeof(linebuf), "%s %s", game_str_sd_class, game_str_tbl_roman[i + 1]); w = lbxfont_calc_str_width(linebuf); SETMAX(xpos, w); } xpos += 5; s1[1] = (char)(xpos + 9); s2[1] = (char)(xpos + 38); s3[1] = (char)(xpos + 69); s4[1] = (char)(xpos + 99); sd->man = 0; curman = 0; game_design_update_engines(sd); powperwarp = tbl_shiptech_hull[sd->hull].power / tbl_shiptech_engine[sd->engine].warp; sd->engines = sd->engines - (powperwarp * 10) / tbl_shiptech_engine[sd->engine].power; space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); for (int i = 0; i <= havelast; ++i) { int cost2, space2, spacet; sd->man = i; game_design_update_engines(sd); spacet = game_design_calc_space(d->gd); space2 = space - spacet; SETMAX(space2, 1); flag_tbl_enable[n] = (spacet >= 0); if (i == actman) { curman = n; } powperwarp = (tbl_shiptech_hull[sd->hull].power * (i + 1)) / tbl_shiptech_engine[sd->engine].warp; SETMAX(powperwarp, 1); cost2 = game_design_calc_cost(d->gd) - cost; SETMAX(cost2, 1); strbuild_catf(&line_builder, "%s %s%s%i%s%i%s%i%s%i", game_str_sd_class, game_str_tbl_roman[i + 1], s1, (i + 3) / 2, s2, cost2, s3, powperwarp, s4, space2); lineptr[n++] = strbuild_finish(&line_builder); } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s%s", game_str_sd_man1, s1, game_str_sd_speed, s2, game_str_sd_cost, s3, game_str_sd_power, s4, game_str_sd_space); } { int listi; struct xy_s xy; xy = ui_design_draw_selbox(xpos, 150, 138, -15, n + 2, game_str_sd_man2); listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 117, titlebuf, lineptr, &curman, flag_tbl_enable, 1, 0x60, false); if (listi < 0) { sd->man = actman; } else { sd->man = curman; } game_design_update_engines(sd); } } static void ui_design_sel_weapon(struct design_data_s *d, int wslot) { int8_t havebuf[WEAPON_NUM]; bool flag_tbl_enable[WEAPON_NUM]; weapon_t tbl_weapon[WEAPON_NUM]; int xpos, xpos2, n, numlines; int16_t curweap; char titlebuf[0x80]; char linebuf[WEAPON_NUM * 0x58]; const char *lineptr[WEAPON_NUM + 1]; struct strbuild_s line_builder; shipdesign_t *sd = &(d->gd->sd); weapon_t actwpnt = sd->wpnt[wslot]; uint8_t actwpnn = sd->wpnn[wslot]; again: n = 0; numlines = 0; curweap = 0; line_builder = strbuild_init(linebuf, sizeof(linebuf)); lbxfont_select(2, 0, 4, 0xe); { int havelast, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; char s5[3] = "\x1dX"; char s6[3] = "\x1dX"; char s7[3] = "\x1dX"; xpos = xpos2 = 0; for (int i = 0; i < WEAPON_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_weap[i].nameptr); SETMAX(xpos, w); w = lbxfont_calc_str_width(*tbl_shiptech_weap[i].extratextptr); SETMAX(xpos2, w); } s1[1] = (char)(15); s2[1] = (char)(xpos + 19); xpos += xpos2 + 14; s3[1] = (char)(xpos + 12); s4[1] = (char)(xpos + 44); s5[1] = (char)(xpos + 65); s6[1] = (char)(xpos + 86); s7[1] = (char)(xpos + 95); sd->wpnt[wslot] = 0; sd->wpnn[wslot] = 0; game_design_update_engines(sd); space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); havelast = 0; while (!havelast) { havelast = game_design_build_tbl_fit_weapon(d->g, d->gd, havebuf, wslot, ui_data.sorted.weapon_type[d->api]); if (!havelast) { ui_data.sorted.weapon_type[d->api] = (ui_data.sorted.weapon_type[d->api] + 1) % WEAPON_GROUP_NUM; } } { int i = havelast + 1, firsti; if ((game_num_weapon_list_max > 0) && (game_num_weapon_list_max < WEAPON_NUM)) { int j; for (j = 0; (j < game_num_weapon_list_max) && (i > 0); ) { --i; if (havebuf[i] >= 0) { ++j; } } firsti = i; if (firsti > 0) { i = 0; } } else { firsti = 0; i = 0; } /* game_design_build_tbl_fit_weapon ensures that havelast < WEAPON_NUM. */ while (i <= havelast) { if (havebuf[i] >= 0) { int space2, cost2, power, sizei, dmin, dmax; ++numlines; sd->wpnt[wslot] = i; sd->wpnn[wslot] = 1; game_design_update_engines(sd); space2 = space - game_design_calc_space(d->gd); flag_tbl_enable[n] = (havebuf[i] > 0); if ((i == actwpnt) && (actwpnn != 0)) { curweap = n; } tbl_weapon[n] = i; power = tbl_shiptech_weap[i].power; cost2 = game_design_calc_cost(d->gd) - cost; if (i == 0) { havebuf[i] = 0; } sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_WEAPON1, i); dmin = tbl_shiptech_weap[i].damagemin; dmax = tbl_shiptech_weap[i].damagemax; strbuild_catf(&line_builder, "%i%s%s%s%s%s%i", havebuf[i], s1, *tbl_shiptech_weap[i].nameptr, s2, *tbl_shiptech_weap[i].extratextptr, s3, dmin); if (dmin != dmax) { strbuild_catf(&line_builder, "-%i", dmax); } strbuild_catf(&line_builder, "%s%i%s%i%s%i%s %i", s4, cost2, s5, sizei, s6, power, s7, space2); lineptr[n++] = strbuild_finish(&line_builder); } ++i; if ((firsti > 0) && (i == 1)) { i = firsti; } } } lineptr[n] = 0; lib_sprintf(titlebuf, sizeof(titlebuf), "%s %s%s%s%s%s%s%s%s%s%s%s%s %s", game_str_sd_max, game_str_sd_weapname, s2, game_str_sd_descr, s3, game_str_sd_dmg, s4, game_str_sd_cost, s5, game_str_sd_size, s6, game_str_sd_power, s7, game_str_sd_space); } { int listi; struct xy_s xy; SETMIN(n, 18); xy = ui_design_draw_selbox(xpos, 160, 160, 0, n + 2, ui_extra_enabled ? game_str_sd_wgroup_names[ui_data.sorted.weapon_type[d->api]] : game_str_sd_weaps); if (numlines < 18) { listi = uiobj_select_from_list3(xy.x + 14, xy.y + 20, xpos + 131, titlebuf, lineptr, &curweap, flag_tbl_enable, 1, 0x60, false, ui_extra_enabled, xy.x, xy.y); } else { listi = uiobj_select_from_list4(xy.x + 14, xy.y + 20, xpos + 131, titlebuf, lineptr, &curweap, flag_tbl_enable, 18, 312, 19, ui_data.gfx.design.popscrol_u, 313, 183, ui_data.gfx.design.popscrol_d, 1, 0x60, false, ui_extra_enabled, xy.x, xy.y); } if (listi == -2) { ui_data.sorted.weapon_type[d->api] = (ui_data.sorted.weapon_type[d->api] + 1) % WEAPON_GROUP_NUM; goto again; } else if (listi < 0) { sd->wpnt[wslot] = actwpnt; sd->wpnn[wslot] = actwpnn; } else { weapon_t wi = tbl_weapon[listi]; uint8_t wn = havebuf[wi]; sd->wpnt[wslot] = wi; SETMIN(wn, actwpnn); SETMAX(wn, 1); sd->wpnn[wslot] = wn; } game_design_update_engines(sd); } } static void ui_design_sel_special(struct design_data_s *d, int sslot) { int8_t havebuf[SHIP_SPECIAL_NUM]; bool flag_tbl_enable[SHIP_SPECIAL_NUM]; ship_special_t tbl_special[SHIP_SPECIAL_NUM]; int xpos, xpos2, n = 0, numlines = 0; int16_t curspec; char titlebuf[0x80]; char linebuf[SHIP_SPECIAL_NUM * 0x5d]; const char *lineptr[SHIP_SPECIAL_NUM + 1]; struct strbuild_s line_builder = strbuild_init(linebuf, sizeof(linebuf)); shipdesign_t *sd = &(d->gd->sd); ship_special_t actspec = sd->special[sslot]; lbxfont_select(2, 0, 4, 0xe); { int havelast, space, cost; char s1[3] = "\x1dX"; char s2[3] = "\x1dX"; char s3[3] = "\x1dX"; char s4[3] = "\x1dX"; char s5[3] = "\x1dX"; xpos = xpos2 = 0; for (int i = 0; i < SHIP_SPECIAL_NUM; ++i) { int w; w = lbxfont_calc_str_width(*tbl_shiptech_special[i].nameptr); SETMAX(xpos, w); w = lbxfont_calc_str_width(*tbl_shiptech_special[i].extratextptr); SETMAX(xpos2, w); } s1[1] = (char)(xpos + 4); xpos += xpos2 + 4; s2[1] = (char)(xpos + 3); s3[1] = (char)(xpos + 22); s4[1] = (char)(xpos + 28); s5[1] = (char)(xpos + 30); sd->special[sslot] = 0; game_design_update_engines(sd); space = game_design_calc_space(d->gd); cost = game_design_calc_cost(d->gd); havelast = game_design_build_tbl_fit_special(d->g, d->gd, havebuf, sslot); /* game_design_build_tbl_fit_special ensures that havelast < SHIP_SPECIAL_NUM. */ for (int i = 0; i <= havelast; ++i) { if (havebuf[i] >= 0) { int space2, cost2, power, sizei; ++numlines; sd->special[sslot] = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(d->gd); flag_tbl_enable[n] = (havebuf[i] > 0); if (i == actspec) { curspec = n; } tbl_special[n] = i; power = tbl_shiptech_special[i].power[sd->hull]; cost2 = game_design_calc_cost(d->gd) - cost; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_SPECIAL1, i); strbuild_catf(&line_builder, "%s%s%s%s", *tbl_shiptech_special[i].nameptr, s1, *tbl_shiptech_special[i].extratextptr, s2); strbuild_catf(&line_builder, "%i%s%i%s %i%s %i", cost2, s3, sizei, s4, power, s5, space2); lineptr[n++] = strbuild_finish(&line_builder); } } lineptr[n] = NULL; lib_sprintf(titlebuf, sizeof(titlebuf), "%s%s%s%s%s%s%s%s %s%s %s", game_str_sd_specname, s1, game_str_sd_descr, s2, game_str_sd_cost, s3, game_str_sd_size, s4, game_str_sd_power, s5, game_str_sd_space); } { int listi; struct xy_s xy; SETMIN(n, 18); xy = ui_design_draw_selbox(xpos, 150, 152, -54, n + 2, game_str_sd_specs); if (numlines < 18) { listi = uiobj_select_from_list1(xy.x + 14, xy.y + 20, xpos + 81, titlebuf, lineptr, &curspec, flag_tbl_enable, 1, 0x60, false); } else { listi = uiobj_select_from_list2(xy.x + 14, xy.y + 20, xpos + 81, titlebuf, lineptr, &curspec, flag_tbl_enable, 18, 312, 19, ui_data.gfx.design.popscrol_u, 313, 183, ui_data.gfx.design.popscrol_d, 1, 0x60, false); } if (listi < 0) { sd->special[sslot] = actspec; } else { sd->special[sslot] = tbl_special[listi]; } game_design_update_engines(sd); } } static void design_draw_sub_cb(void *vptr) { hw_video_copy_back_from_page2(); } static void ui_design_sub(struct ui_design_data_s *u, design_slot_t selmode) { struct design_data_s *d = u->d; uiobj_unset_callback(); if (ui_extra_enabled) { hw_video_copy_back_to_page3(); } uiobj_set_callback_and_delay(design_draw_sub_cb, 0, 1); switch (selmode) { case DESIGN_SLOT_COMP: ui_design_sel_comp(d); break; case DESIGN_SLOT_SHIELD: ui_design_sel_shield(d); break; case DESIGN_SLOT_JAMMER: ui_design_sel_jammer(d); break; case DESIGN_SLOT_ARMOR: ui_design_sel_armor(d); break; case DESIGN_SLOT_ENGINE: ui_design_sel_engine(d); break; case DESIGN_SLOT_MAN: ui_design_sel_man(d); break; case DESIGN_SLOT_WEAPON1: case DESIGN_SLOT_WEAPON2: case DESIGN_SLOT_WEAPON3: case DESIGN_SLOT_WEAPON4: ui_design_sel_weapon(d, selmode - DESIGN_SLOT_WEAPON1); break; case DESIGN_SLOT_SPECIAL1: case DESIGN_SLOT_SPECIAL2: case DESIGN_SLOT_SPECIAL3: ui_design_sel_special(d, selmode - DESIGN_SLOT_SPECIAL1); break; default: break; } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); uiobj_set_callback_and_delay(design_draw_cb, u, 1); design_init_ois(u); game_design_update_haveflags(d); uiobj_set_help_id(5); } bool ui_design_try_inc_weap_count(struct game_s *g, struct design_data_s *d, int i, int inc) { struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); bool ret = false; int space; if (sd->wpnn[i] + inc > 99) { inc = 99 - sd->wpnn[i]; } sd->wpnn[i] += inc; game_design_update_engines(sd); space = game_design_calc_space(gd); if (space >= 0) { sd->space = space; game_design_update_haveflags(d); ret = true; } else { sd->wpnn[i] -= inc; game_design_update_engines(sd); } return ret; } /* -------------------------------------------------------------------------- */ bool ui_design(struct game_s *g, struct game_design_s *gd, player_id_t active_player) { struct ui_design_data_s u; struct design_data_s d; shipdesign_t *sd = &(gd->sd); bool flag_done = false, flag_ret = false, flag_copy = false, flag_name = false; d.g = g; d.gd = gd; d.api = active_player; u.d = &d; design_clear_ois(&u); sd->look = gd->tbl_shiplook_hull[sd->hull]; uiobj_table_clear(); uiobj_set_xyoff(0, 0); design_init_ois(&u); game_design_init_maxtech_haveflags(&d); uiobj_set_help_id(5); uiobj_set_callback_and_delay(design_draw_cb, &u, 1); while (!flag_done) { int16_t oi; ui_delay_prepare(); u.scroll = 0; oi = uiobj_handle_input_cond(); if (oi == u.oi_name) { ui_sound_play_sfx_24(); util_trim_whitespace(sd->name, SHIP_NAME_LEN); if (sd->name[0] == '\0') { lib_strcpy(sd->name, gd->names[sd->hull], SHIP_NAME_LEN); } flag_name = true; } if (!flag_name) { lib_strcpy(sd->name, gd->names[sd->hull], SHIP_NAME_LEN); } if ((oi == u.oi_cancel) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; } else if (oi == u.oi_build) { ui_sound_play_sfx_24(); flag_done = true; flag_ret = true; } else if (oi == u.oi_clear) { ui_sound_play_sfx_24(); game_design_clear(gd); game_design_update_haveflags(&d); } for (ship_hull_t i = SHIP_HULL_SMALL; i < SHIP_HULL_NUM; ++i) { if ((oi == u.oi_tbl_hull[i]) && !d.flag_tbl_hull[i]) { ui_sound_play_sfx_24(); sd->hull = i; sd->look = gd->tbl_shiplook_hull[i]; game_design_update_haveflags(&d); } } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { if (1 && (sd->wpnn[i] < 99) && ((oi == u.oi_tbl_weap_up[i]) || ((oi == u.oi_tbl_weap_n_scroll[i]) && ((u.scroll > 0) != ui_mwi_counter))) ) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_ALT)) { if (!ui_design_try_inc_weap_count(g, &d, i, 99)) { while (ui_design_try_inc_weap_count(g, &d, i, 10)) {} while (ui_design_try_inc_weap_count(g, &d, i, 1)) {} } } else if (kbd_is_modifier(MOO_MOD_CTRL)) { if (!ui_design_try_inc_weap_count(g, &d, i, 10)) { while (ui_design_try_inc_weap_count(g, &d, i, 1)) {} } } else { ui_design_try_inc_weap_count(g, &d, i, 1); } break; } else if (1 && (sd->wpnn[i] > 0) && ((oi == u.oi_tbl_weap_dn[i]) || ((oi == u.oi_tbl_weap_n_scroll[i]) && ((u.scroll < 0) != ui_mwi_counter))) ) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_CTRL)) { if (sd->wpnn[i] < 10) { sd->wpnn[i] = 0; } else { sd->wpnn[i] -= 10; } } else if (kbd_is_modifier(MOO_MOD_ALT)) { sd->wpnn[i] = 0; } else { --sd->wpnn[i]; } game_design_update_haveflags(&d); d.flag_tbl_weap_dn[i] = (sd->wpnn[i] == 0); break; } else if (oi == u.oi_tbl_weap[i]) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_WEAPON1 + i); break; } } if ((oi == u.oi_iup) || (oi == u.oi_icon) || ((oi == u.oi_iscroll) && (u.scroll < 0))) { ui_sound_play_sfx_24(); game_design_look_next(gd); } else if ((oi == u.oi_idn) || ((oi == u.oi_iscroll) && (u.scroll > 0))) { ui_sound_play_sfx_24(); game_design_look_prev(gd); } else if (oi == u.oi_armor) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_ARMOR); } else if (oi == u.oi_shield) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_SHIELD); } else if (oi == u.oi_man) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_MAN); } else if (oi == u.oi_engine) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_ENGINE); } else if (oi == u.oi_comp) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_COMP); } else if (oi == u.oi_jammer) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_JAMMER); } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { if (oi == u.oi_tbl_spec[i]) { ui_sound_play_sfx_24(); ui_design_sub(&u, DESIGN_SLOT_SPECIAL1 + i); break; } } design_draw_cb(&u); ui_palette_set_n(); uiobj_finish_frame(); if (!flag_copy) { ui_draw_copy_buf(); flag_copy = true; } ui_delay_ticks_or_click(1); } game_design_compact_slots(sd); uiobj_table_clear(); uiobj_unset_callback(); uiobj_set_help_id(-1); return flag_ret; } 1oom-1.11.2/src/ui/classic/uidesign.h000066400000000000000000000003461476061725400172730ustar00rootroot00000000000000#ifndef INC_1OOM_UIDESIGN_H #define INC_1OOM_UIDESIGN_H #include "game_types.h" #include "types.h" struct game_s; struct game_design_s; extern bool ui_design(struct game_s *g, struct game_design_s *gd, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uidialog.c000066400000000000000000000117541476061725400172610ustar00rootroot00000000000000#include "config.h" #include "game_str.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidialog.h" #include "uidraw.h" #include "uiobj.h" #include "uisound.h" struct ui_dialog_data_s { struct game_s *g; player_id_t api; int x, y; int we; uint8_t *gfx_eco_chng2; uint8_t *gfx_eco_chng4; uint8_t *gfx_robo_but; uint8_t dialog_type; const char *str; int result; }; static void ui_dialog_load_data(struct ui_dialog_data_s *d) { d->gfx_eco_chng2 = lbxfile_item_get(LBXFILE_BACKGRND, 0x1f); d->gfx_eco_chng4 = lbxfile_item_get(LBXFILE_BACKGRND, 0x30); d->gfx_robo_but = lbxfile_item_get(LBXFILE_BACKGRND, 0x31); } static void ui_dialog_free_data(struct ui_dialog_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_eco_chng2); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_eco_chng4); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_robo_but); } static void ui_dialog_yesno_draw_cb(void *vptr) { struct ui_dialog_data_s *d = vptr; char buf[0x96]; int x = d->x, y = d->y; ui_draw_filled_rect(x, y, x + 135, y + 80, 0xf9, ui_scale); lbxgfx_draw_frame(x, y, d->gfx_eco_chng2, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(0, 0, 0, 0); lib_strcpy(buf, game_str_nt_doyou, sizeof(buf)); lib_strcat(buf, d->str, sizeof(buf)); lbxfont_print_str_split(x + 15 - (d->we / 2), y + 11, 110 + d->we, buf, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.scrapbut_yes); lbxgfx_set_frame_0(ui_data.gfx.starmap.scrapbut_no); lbxgfx_draw_frame(x + 83, y + 60, ui_data.gfx.starmap.scrapbut_yes, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(x + 18, y + 60, ui_data.gfx.starmap.scrapbut_no, UI_SCREEN_W, ui_scale); } static void ui_dialog_choose_draw_cb(void *vptr) { struct ui_dialog_data_s *d = vptr; char buf[0x96]; int x = d->x, y = d->y; ui_draw_filled_rect(x, y, x + 135, y + 80, 0xf9, ui_scale); lbxgfx_draw_frame(x, y, d->gfx_eco_chng4, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(0, 0, 0, 0); lib_strcpy(buf, game_str_nt_doyou, sizeof(buf)); lib_strcat(buf, d->str, sizeof(buf)); lbxfont_print_str_split(x + 15 - (d->we / 2), y + 16, 110 + d->we, buf, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } static void ui_dialog_do(struct ui_dialog_data_s *d) { int16_t oi_tbl[3], oi_y, oi_n; int x = d->x, y = d->y; bool flag_done = false; ui_cursor_setup_area(2, &ui_cursor_area_tbl[0]); uiobj_set_xyoff(0, 0); ui_dialog_load_data(d); uiobj_set_callback_and_delay((d->dialog_type == 0) ? ui_dialog_yesno_draw_cb : ui_dialog_choose_draw_cb, d, 1); uiobj_table_clear(); oi_y = UIOBJI_INVALID; oi_n = UIOBJI_INVALID; UIOBJI_SET_TBL_INVALID(oi_tbl); if (d->dialog_type == 0) { oi_y = uiobj_add_t0(x + 83, y + 60, "", ui_data.gfx.starmap.scrapbut_yes, MOO_KEY_y); oi_n = uiobj_add_t0(x + 18, y + 60, "", ui_data.gfx.starmap.scrapbut_no, MOO_KEY_n); } else { lbxfont_select(2, 6, 0, 0); oi_n = uiobj_add_t0(x + 10, y + 60, game_str_tbl_nt_adj[0], d->gfx_robo_but, MOO_KEY_n); oi_tbl[0] = uiobj_add_t0(x + 42, y + 60, game_str_tbl_nt_adj[1], d->gfx_robo_but, MOO_KEY_2); oi_tbl[1] = uiobj_add_t0(x + 74, y + 60, game_str_tbl_nt_adj[2], d->gfx_robo_but, MOO_KEY_5); oi_tbl[2] = uiobj_add_t0(x + 106, y + 60, game_str_tbl_nt_adj[3], d->gfx_robo_but, MOO_KEY_7); } while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_n)) { ui_sound_play_sfx_06(); d->result = 0; flag_done = true; } if (oi == oi_y) { ui_sound_play_sfx_24(); d->result = 1; flag_done = true; } for (int i = 0; i < 3; ++i) { if (oi == oi_tbl[i]) { ui_sound_play_sfx_24(); d->result = i + 1; flag_done = true; } } if (!flag_done) { if (d->dialog_type == 0) { ui_dialog_yesno_draw_cb(d); } else { ui_dialog_choose_draw_cb(d); } ui_draw_finish(); } ui_delay_ticks_or_click(1); } uiobj_table_clear(); ui_dialog_free_data(d); } int ui_dialog_yesno(struct game_s *g, int pi, const char *str, int x, int y, int we) { struct ui_dialog_data_s d; memset(&d, 0, sizeof(d)); d.g = g; d.api = pi; d.str = str; d.dialog_type = 0; d.x = x; d.y = y; d.we = we; ui_dialog_do(&d); return d.result; } int ui_dialog_choose(struct game_s *g, int pi, const char *str, int x, int y, int we) { struct ui_dialog_data_s d; memset(&d, 0, sizeof(d)); d.g = g; d.api = pi; d.str = str; d.dialog_type = 1; d.x = x; d.y = y; d.we = we; ui_dialog_do(&d); return d.result; } 1oom-1.11.2/src/ui/classic/uidialog.h000066400000000000000000000004141476061725400172550ustar00rootroot00000000000000#ifndef INC_1OOM_UIDIALOG_H #define INC_1OOM_UIDIALOG_H struct game_s; extern int ui_dialog_yesno(struct game_s *g, int pi, const char *str, int x, int y, int we); extern int ui_dialog_choose(struct game_s *g, int pi, const char *str, int x, int y, int we); #endif 1oom-1.11.2/src/ui/classic/uidraw.c000066400000000000000000000534311476061725400167550ustar00rootroot00000000000000#include "config.h" #include #include "uidraw.h" #include "comp.h" #include "gfxscale.h" #include "hw.h" #include "lbxfont.h" #include "mouse.h" #include "rnd.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uiobj.h" #include "uipal.h" /* -------------------------------------------------------------------------- */ int ui_draw_finish_mode = 0; const uint8_t tbl_banner_color[BANNER_NUM] = { 0xeb, 0x6f, 0xcd, 0x40, 0x06, 0x50 }; const uint8_t tbl_banner_color2[BANNER_NUM] = { 0xed, 0x71, 0xcd, 0x44, 0xb, 0xa3 }; const uint8_t tbl_banner_fontparam[BANNER_NUM] = { 1, 0xe, 0xc, 5, 0, 0xd }; /* -------------------------------------------------------------------------- */ static const uint8_t colortbl_textbox[5] = { 0x18, 0x17, 0x16, 0x15, 0x14 }; static const uint8_t tbl_color_grain[0x100] = { 0x29,0x24,0x3f,0x05,0x62,0x6d,0x57,0x2f,0x53,0x11,0x4a,0x72,0x72,0x3c,0x6a,0x6c, 0x33,0x27,0x5c,0x3d,0x08,0x0d,0x3f,0x1a,0x25,0x5f,0x0e,0x1d,0x07,0x38,0x48,0x5f, 0x33,0x13,0x4e,0x49,0x44,0x3c,0x0c,0x27,0x20,0x04,0x5b,0x7e,0x0a,0x39,0x26,0x20, 0x5d,0x55,0x4c,0x7d,0x17,0x76,0x46,0x3c,0x14,0x0e,0x0a,0x0b,0x1d,0x5c,0x2f,0x33, 0x20,0x1b,0x51,0x6f,0x41,0x79,0x37,0x7e,0x13,0x4a,0x33,0x77,0x1f,0x7e,0x4a,0x5d, 0x2d,0x50,0x15,0x73,0x45,0x41,0x67,0x51,0x6c,0x45,0x31,0x38,0x33,0x3c,0x22,0x23, 0x76,0x23,0x12,0x1e,0x62,0x0c,0x20,0x5b,0x31,0x4b,0x1a,0x03,0x3a,0x73,0x1e,0x4a, 0x2c,0x01,0x7f,0x46,0x1a,0x56,0x6a,0x00,0x33,0x6b,0x4a,0x4d,0x54,0x40,0x68,0x57, 0x3f,0x15,0x57,0x7f,0x2e,0x5d,0x0f,0x67,0x04,0x70,0x58,0x4a,0x62,0x7f,0x6a,0x10, 0x61,0x4e,0x52,0x1f,0x1e,0x1d,0x17,0x73,0x73,0x67,0x1e,0x71,0x05,0x50,0x4b,0x78, 0x02,0x58,0x69,0x3a,0x2d,0x54,0x4c,0x4a,0x13,0x1f,0x34,0x75,0x1f,0x0d,0x75,0x56, 0x54,0x20,0x55,0x25,0x5a,0x7f,0x36,0x50,0x33,0x23,0x75,0x4d,0x50,0x54,0x11,0x2e, 0x48,0x54,0x10,0x76,0x67,0x5a,0x1e,0x2b,0x66,0x41,0x78,0x2c,0x79,0x02,0x08,0x45, 0x0e,0x60,0x51,0x01,0x55,0x62,0x0e,0x3f,0x7c,0x06,0x16,0x08,0x3c,0x34,0x03,0x20, 0x18,0x71,0x13,0x5b,0x65,0x55,0x4f,0x32,0x06,0x3f,0x6a,0x16,0x79,0x47,0x6b,0x05, 0x16,0x74,0x0f,0x5a,0x17,0x30,0x68,0x69,0x55,0x78,0x4b,0x4b,0x51,0x58,0x69,0x77 }; /* -------------------------------------------------------------------------- */ static uint8_t ui_draw_box_fill_tbl[0x40]; static void ui_draw_box_fill_sub1(uint16_t num, const uint8_t *colorptr, uint8_t color0) { uint8_t *p = ui_draw_box_fill_tbl; int i; if (colorptr) { for (i = 0; i < num; ++i) { *p++ = colorptr[i]; } --i; do { *p++ = colorptr[i]; --i; } while (--num); } else { for (i = 0; i < num; ++i) { *p++ = color0++; } do { *p++ = --color0; } while (--num); } } static void ui_draw_line_limit_do(int x0, int y0, int x1, int y1, uint8_t color, const uint8_t *colortbl, int colornum, int colorpos, int scale) { if (x0 == x1) { if ((x0 < uiobj_minx) || (x0 > uiobj_maxx)) { return; } if (y1 < y0) { int t = y0; y0 = y1; y1 = t; colorpos = colornum - 1 - colorpos; } if ((y1 < uiobj_miny) || (y0 > uiobj_maxy)) { return; } SETMAX(y0, uiobj_miny); SETMIN(y1, uiobj_maxy); } else { int dx, dy; if (x1 < x0) { int t; t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; colorpos = colornum - 1 - colorpos; } dy = y1 - y0; dx = x1 - x0; if (x0 < uiobj_minx) { y0 += (dy * (uiobj_minx - x0)) / dx; x0 = uiobj_minx; } if (x0 > x1) { return; } if (x1 > uiobj_maxx) { y1 = y0 + (dy * (uiobj_maxx - x0)) / dx; x1 = uiobj_maxx; } if (x1 < x0) { return; } } if (y0 == y1) { if ((y0 < uiobj_miny) || (y0 > uiobj_maxy)) { return; } if (x1 < x0) { int t = x0; x0 = x1; x1 = t; } if ((x1 < uiobj_minx) || (x0 > uiobj_maxx)) { return; } SETMAX(x0, uiobj_minx); SETMIN(x1, uiobj_maxx); } else { int dx, dy; if (y1 < y0) { int t; t = x0; x0 = x1; x1 = t; t = y0; y0 = y1; y1 = t; } dx = x1 - x0; dy = y1 - y0; if (y0 < uiobj_miny) { x0 += (dx * (uiobj_miny - y0)) / dy; y0 = uiobj_miny; } if (y0 > y1) { return; } if (y1 > uiobj_maxy) { x1 = x0 + (dx * (uiobj_maxy - y0)) / dy; y1 = uiobj_maxy; } if (y1 < y0) { return; } } if (colortbl) { ui_draw_line_ctbl(x0, y0, x1, y1, colortbl, colornum, colorpos, scale); } else { ui_draw_line1(x0, y0, x1, y1, color, scale); } } static void ui_draw_copy_line(int x0, int y0, int x1, int y1) { int step, numpixels; /* ((x0 <= x1) && (y0 <= y1)) && (((x1 - x0) == 0) || ((y1 - y0) == 0)) */ { int dx, dy; dx = x1 - x0; dy = y1 - y0; if (dx < dy) { numpixels = dy + 1; step = UI_SCREEN_W; } else { numpixels = dx + 1; step = 1; } } { uint8_t *q = hw_video_get_buf() + y0 * UI_SCREEN_W + x0; uint8_t *p = hw_video_get_buf_front() + y0 * UI_SCREEN_W + x0; while (numpixels--) { *p = *q; p += step; q += step; } } } /* -------------------------------------------------------------------------- */ void ui_draw_erase_buf(void) { memset(hw_video_get_buf(), 0, UI_SCREEN_W * UI_SCREEN_H); } void ui_draw_copy_buf(void) { hw_video_copy_buf(); } void ui_draw_color_buf(uint8_t color) { memset(hw_video_get_buf(), color, UI_SCREEN_W * UI_SCREEN_H); } void ui_draw_pixel(int x, int y, uint8_t color, int scale) { uint8_t *p = hw_video_get_buf(); if (scale == 1) { p[y * UI_SCREEN_W + x] = color; } else { gfxscale_draw_pixel(p + (y * UI_SCREEN_W + x) * scale, color, UI_SCREEN_W, scale); } } void ui_draw_filled_rect(int x0, int y0, int x1, int y1, uint8_t color, int scale) { uint8_t *s = hw_video_get_buf(); int w; if (x1 < x0) { return; } w = (x1 - x0 + 1) * scale; x0 *= scale; y0 *= scale; y1 *= scale; y1 += scale - 1; s += y0 * UI_SCREEN_W + x0; for (; y0 <= y1; ++y0) { memset(s, color, w); s += UI_SCREEN_W; } } void ui_draw_line1(int x0, int y0, int x1, int y1, uint8_t color, int scale) { int xslope = 0, yslope = 0, yinc, numpixels; /* BUG? xslope and yslope not cleared by MOO1 */ if (x1 < x0) { int t; t = x1; x1 = x0; x0 = t; t = y1; y1 = y0; y0 = t; } { int dx, dy; dx = x1 - x0; dy = y1 - y0; yinc = UI_SCREEN_W * scale; if (dy < 0) { dy = -dy; yinc = -UI_SCREEN_W * scale; } if (dx < dy) { numpixels = dy + 1; yslope = 0x100; if (dy != 0) { xslope = (dx << 8) / dy; } } else { numpixels = dx + 1; if (dx != 0) { xslope = 0x100; yslope = (dy << 8) / dx; } } } { uint8_t *p = hw_video_get_buf() + (y0 * UI_SCREEN_W + x0) * scale; int xerr, yerr; xerr = 0x100 / 2; yerr = 0x100 / 2; while (numpixels--) { if (scale == 1) { *p = color; } else { gfxscale_draw_pixel(p, color, UI_SCREEN_W, scale); } xerr += xslope; if ((xerr & 0xff00) != 0) { xerr &= 0xff; p += scale; } yerr += yslope; if ((yerr & 0xff00) != 0) { yerr &= 0xff; p += yinc; } } } } void ui_draw_line_ctbl(int x0, int y0, int x1, int y1, const uint8_t *colortbl, int colornum, int pos, int scale) { int xslope = 0, yslope = 0, yinc, numpixels; /* BUG? xslope and yslope not cleared by MOO1 */ if (x1 < x0) { int t; t = x1; x1 = x0; x0 = t; t = y1; y1 = y0; y0 = t; } { int dx, dy; dx = x1 - x0; dy = y1 - y0; yinc = UI_SCREEN_W * scale; if (dy < 0) { dy = -dy; yinc = -UI_SCREEN_W * scale; } if (dx < dy) { numpixels = dy + 1; yslope = 0x100; if (dy != 0) { xslope = (dx << 8) / dy; } } else { numpixels = dx + 1; if (dx != 0) { xslope = 0x100; yslope = (dy << 8) / dx; } } } { uint8_t *p = hw_video_get_buf() + (y0 * UI_SCREEN_W + x0) * scale; int xerr, yerr; xerr = 0x100 / 2; yerr = 0x100 / 2; while (numpixels--) { uint8_t color; color = colortbl[pos++]; if (pos >= colornum) { pos = 0; } if (color != 0) { if (scale == 1) { *p = color; } else { gfxscale_draw_pixel(p, color, UI_SCREEN_W, scale); } } xerr += xslope; if ((xerr & 0xff00) != 0) { xerr &= 0xff; p += scale; } yerr += yslope; if ((yerr & 0xff00) != 0) { yerr &= 0xff; p += yinc; } } } } void ui_draw_line_limit(int x0, int y0, int x1, int y1, uint8_t color, int scale) { ui_draw_line_limit_do(x0, y0, x1, y1, color, NULL, 0, 0, scale); } void ui_draw_line_limit_ctbl(int x0, int y0, int x1, int y1, const uint8_t *colortbl, int colornum, int pos, int scale) { ui_draw_line_limit_do(x0, y0, x1, y1, 0, colortbl, colornum, pos, scale); } void ui_draw_slider(int x, int y, int w, int wdiv, int xoff, uint8_t color, int scale) { int y1, x1; x1 = x * scale + xoff + (w * scale) / wdiv; x *= scale; y *= scale; y1 = y + 2 * scale + scale - 1; if (x1 < x) { int t; t = x1; x1 = x; x = t; } ui_draw_filled_rect(x, y, x1, y1, color, 1); } void ui_draw_box1(int x0, int y0, int x1, int y1, uint8_t color1, uint8_t color2, int scale) { ui_draw_line1(x0, y0, x1, y0, color1, scale); ui_draw_line1(x0, y0, x0, y1, color1, scale); ui_draw_line1(x0 + 1, y1, x1, y1, color2, scale); ui_draw_line1(x1, y0 + 1, x1, y1, color2, scale); } void ui_draw_box2(int x0, int y0, int x1, int y1, uint8_t color1, uint8_t color2, uint8_t color3, uint8_t color4, int scale) { ui_draw_box1(x0, y0, x1, y1, color1, color3, scale); ++x0; ++y0; --x1; --y1; ui_draw_box1(x0, y0, x1, y1, color2, color4, scale); } void ui_draw_box_fill(int x0, int y0, int x1, int y1, const uint8_t *colorptr, uint8_t color0, uint16_t colorhalf, uint16_t ac, uint8_t colorpos, int scale) { uint8_t *s = hw_video_get_buf() + (y0 * UI_SCREEN_W + x0) * scale; uint16_t xstep, ystep, vx, vy, h, w, colornum; colornum = colorhalf << 1; /*v12 = colorpos & 0xff;*/ ui_draw_box_fill_sub1(colorhalf, colorptr, color0); w = x1 - x0 + 1; xstep = (colorhalf * 0x80 * ac) / w; h = y1 - y0 + 1; ystep = (colorhalf * 0x80 * ac) / h; vx = 0; do { uint8_t *p; vx = vy = vx + xstep; p = s; s += scale; for (int y = 0; y < h; ++y) { uint8_t c; vy += ystep; c = (((((uint16_t)tbl_color_grain[colorpos++]) << 1) + vy) >> 8) & 0x3f; while (c >= colornum) { c -= colornum; } c = ui_draw_box_fill_tbl[c]; if (scale == 1) { *p = c; p += UI_SCREEN_W; } else { p = gfxscale_draw_pixel(p, c, UI_SCREEN_W, scale); } } } while (--w); } void ui_draw_text_overlay(int x, int y, const char *str) { int x0, x1, y0, y1, w, h; lbxfont_select(0, 0, 0, 0); h = lbxfont_get_height(); w = lbxfont_calc_str_width(str); x0 = x - 3; SETMAX(x0, 0); y0 = y - 3; SETMAX(y0, 0); x1 = x + w + 4; SETMIN(x1, UI_VGA_W - 1); y1 = y + h + 5; SETMIN(y1, UI_VGA_H - 1); ui_draw_filled_rect(x0, y0, x1, y1, 0, ui_scale); lbxfont_print_str_normal(x + 1, y + 1, str, UI_SCREEN_W, ui_scale); } void ui_draw_box_grain(int x0, int y0, int x1, int y1, uint8_t color0, uint8_t color1, uint8_t ae, int scale) { if ((x0 / 4) == (x1 / 4)) { ui_draw_filled_rect(x0, y0, x1, y1, color0, scale); } else { const uint8_t vga_tbl_mask_x0[4] = { 0xf, 0xe, 0xc, 0x8 }; const uint8_t vga_tbl_mask_x1[4] = { 0x1, 0x3, 0x7, 0xf }; uint8_t *s = hw_video_get_buf() + (y0 * UI_SCREEN_W) * scale; uint8_t *p; uint16_t v6, h = y1 - y0 + 1; uint8_t ah, bl; v6 = rnd_bitfiddle(ae); p = s + (x0 & ~3) * scale; ah = vga_tbl_mask_x0[x0 & 3]; bl = v6 & 0xff; for (int y = 0; y < h; ++y) { uint8_t m; m = ah; for (int xa = 0; xa < 4; ++xa, m >>= 1) { if (m & 0x1) { if (scale == 1) { p[xa] = color0; } else { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { p[sy * UI_SCREEN_W + xa * scale + sx] = color0; } } } } } m = tbl_color_grain[bl] & ah; for (int xa = 0; xa < 4; ++xa, m >>= 1) { if (m & 0x1) { if (scale == 1) { p[xa] = color1; } else { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { p[sy * UI_SCREEN_W + xa * scale + sx] = color1; } } } } } ++bl; p += UI_SCREEN_W * scale; } v6 = rnd_bitfiddle(v6); p = s + (x1 & ~3) * scale; ah = vga_tbl_mask_x1[x1 & 3]; bl = v6 & 0xff; for (int y = 0; y < h; ++y) { uint8_t m; m = ah; for (int xa = 0; xa < 4; ++xa, m >>= 1) { if (m & 0x1) { if (scale == 1) { p[xa] = color0; } else { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { p[sy * UI_SCREEN_W + xa * scale + sx] = color0; } } } } } m = tbl_color_grain[bl] & ah; for (int xa = 0; xa < 4; ++xa, m >>= 1) { if (m & 0x1) { if (scale == 1) { p[xa] = color1; } else { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { p[sy * UI_SCREEN_W + xa * scale + sx] = color1; } } } } } ++bl; p += UI_SCREEN_W * scale; } v6 = rnd_bitfiddle(v6); uint16_t wp4 = (x1 / 4) - (x0 / 4) - 1; if (wp4 == 0) { return; } p = s + ((x0 & ~3) + 4/* skip x0..x0+3 */) * scale; for (int y = 0; y < h; ++y) { bl = v6 & 0xff; for (int xq = 0; xq < wp4; ++xq) { uint8_t m; if (scale == 1) { p[0] = color0; p[1] = color0; p[2] = color0; p[3] = color0; } else { for (int sy = 0; sy < scale; ++sy) { memset(&p[sy * UI_SCREEN_W], color0, 4 * scale); } } m = tbl_color_grain[bl] & 0xf; for (int xa = 0; xa < 4; ++xa, m >>= 1) { if (m & 0x1) { if (scale == 1) { p[xa] = color1; } else { for (int sy = 0; sy < scale; ++sy) { for (int sx = 0; sx < scale; ++sx) { p[sy * UI_SCREEN_W + xa * scale + sx] = color1; } } } } } ++bl; p += 4 * scale; } p += (UI_SCREEN_W - wp4 * 4) * scale; v6 = rnd_bitfiddle(v6); } } } static void ui_draw_finish_wipe_anim_do(int x, int y, int f) { int vx, vy; vx = x + 19; vy = y + 19; x += f; y += f; vx -= f; vy -= f; ui_draw_copy_line(x, y, vx, y); ui_draw_copy_line(x, y, x, vy); ui_draw_copy_line(vx, y, vx, vy); } static void ui_draw_finish_wipe_anim(void) { for (int f = 0; f < 10; ++f) { ui_delay_prepare(); for (int x = 0; x < UI_SCREEN_W; x += 20) { for (int y = 0; y < UI_SCREEN_H; y += 20) { ui_draw_finish_wipe_anim_do(x, y, f); } } hw_video_redraw_front(); ui_delay_us_or_click(MOO_TICKS_TO_US(1) / 2); } ui_cursor_store_bg0(moouse_x, moouse_y); hw_video_draw_buf(); ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); /* HACK enable cursor for -nextturn */ } void ui_draw_finish(void) { if (ui_draw_finish_mode == 0) { ui_palette_set_n(); uiobj_finish_frame(); } else if (ui_draw_finish_mode == 1) { ui_draw_finish_wipe_anim(); } else if (ui_draw_finish_mode == 2) { uiobj_finish_frame(); ui_palette_fadein_4b_19_1(); } ui_draw_finish_mode = 0; } void ui_draw_stars(int x, int y, int xoff1, int xoff2, int scale) { const int sx1[16] = { 2, 6, 30, 34, 48, 74, 88, 96, 99, 103, 119, 123, 136, 137, 152, 159 }; const int sy1[16] = { 15, 2, 16, 24, 19, 4, 11, 23, 22, 10, 21, 11, 4, 12, 22, 10 }; const int sx2[23] = { 0, 6, 11, 33, 36, 46, 52, 67, 84, 86, 91, 95, 98, 103, 107, 112, 123, 125, 139, 142, 148, 151, 159 }; const int sy2[23] = { 22, 8, 18, 19, 3, 18, 7, 24, 14, 17, 11, 1, 13, 15, 5, 6, 19, 1, 13, 10, 6, 23, 13 }; int xo1, xo2; xo1 = (ui_data.starmap.stars_xoff1 + xoff1) % (320 / 2); xo2 = (ui_data.starmap.stars_xoff2 + xoff1 * 2) % (320 / 2); if (((UI_SCREEN_W / 2) - xoff2) > xo1) { int tx = xo1 + xoff2; for (int i = 0; i < 16; ++i) { int sx = sx1[i]; if ((sx >= xo1) && (sx < tx)) { ui_draw_pixel(sx - xo1 + x, sy1[i] + y, 4, scale); } } } else { int tx; for (int i = 0; i < 16; ++i) { int sx = sx1[i]; if (sx >= xo1) { ui_draw_pixel(sx - xo1 + x, sy1[i] + y, 4, scale); } } tx = (xo1 + xoff2) % (320 / 2); for (int i = 0; i < 16; ++i) { int sx = sx1[i]; if (sx < tx) { ui_draw_pixel(sx - xo1 + x + 160, sy1[i] + y, 4, scale); } } } if (((320 / 2) - xoff2) > xo2) { int tx = xo2 + xoff2; for (int i = 0; i < 23; ++i) { int sx = sx2[i]; if ((sx >= xo2) && (sx < tx)) { ui_draw_pixel(sx - xo2 + x, sy2[i] + y, 6, scale); } } } else { int tx; for (int i = 0; i < 23; ++i) { int sx = sx2[i]; if (sx >= xo2) { ui_draw_pixel(sx - xo2 + x, sy2[i] + y, 6, scale); } } tx = (xo2 + xoff2) % (320 / 2); for (int i = 0; i < 23; ++i) { int sx = sx2[i]; if (sx < tx) { ui_draw_pixel(sx - xo2 + x + 160, sy2[i] + y, 6, scale); } } } } void ui_draw_set_stars_xoffs(bool flag_right) { int x1, x2; if (flag_right) { x1 = 159; x2 = 158; } else { x1 = 1; x2 = 2; } ui_data.starmap.stars_xoff1 = (ui_data.starmap.stars_xoff1 + x1) % (UI_SCREEN_W / 2); ui_data.starmap.stars_xoff2 = (ui_data.starmap.stars_xoff2 + x2) % (UI_SCREEN_W / 2); } void ui_draw_textbox_2str(const char *str1, const char *str2, int y0, int scale) { int x0 = 48, w = 132, x1 = x0 + w - 1, y1; lbxfont_select_set_12_1(0, 0, 0, 0); lbxfont_set_gap_h(3); lbxfont_set_14_24(0xb, 0xe); y1 = lbxfont_calc_split_str_h(w - 8, str2) + y0 + 7; if (*str1 != '\0') { y1 += lbxfont_get_height() + 4; } ui_draw_box_fill(x0 + 2, y0 + 2, x1 - 2, y1 - 2, colortbl_textbox, 0, 5, 1, (0x2737 & 0xffu), scale); ui_draw_box2(x0, y0, x1, y1, 0x7, 0x10, 0x13, 0x12, scale); ui_draw_pixel(x0, y0, 0x10, scale); ui_draw_pixel(x0 + 1, y0 + 1, 0xf, scale); ui_draw_pixel(x0 + 2, y0 + 1, 0xf, scale); ui_draw_pixel(x0 + 1, y0 + 2, 0xf, scale); ui_draw_pixel(x0 + 1, y0 + 3, 0xf, scale); ui_draw_line1(x0 + 1, y1 + 1, x1 + 1, y1 + 1, 0, scale); ui_draw_line1(x1 + 1, y0 + 1, x1 + 1, y1, 0, scale); if (*str1 != '\0') { lbxfont_select_subcolors_13not1(); lbxfont_print_str_center(x0 + w / 2, y0 + 4, str1, UI_SCREEN_W, scale); lbxfont_select_subcolors_0(); y0 += lbxfont_get_height() + 5; } lbxfont_print_str_split(x0 + 4, y0 + 4, w - 8, str2, 2, UI_SCREEN_W, UI_SCREEN_H, scale); } 1oom-1.11.2/src/ui/classic/uidraw.h000066400000000000000000000036071476061725400167620ustar00rootroot00000000000000#ifndef INC_1OOM_UIDRAW_H #define INC_1OOM_UIDRAW_H #include "game_types.h" #include "types.h" extern int ui_draw_finish_mode; extern const uint8_t tbl_banner_color[BANNER_NUM]; extern const uint8_t tbl_banner_color2[BANNER_NUM]; extern const uint8_t tbl_banner_fontparam[BANNER_NUM]; extern void ui_draw_erase_buf(void); extern void ui_draw_copy_buf(void); extern void ui_draw_color_buf(uint8_t color); extern void ui_draw_pixel(int x, int y, uint8_t color, int scale); extern void ui_draw_filled_rect(int x0, int y0, int x1, int y1, uint8_t color, int scale); extern void ui_draw_line1(int x0, int y0, int x1, int y1, uint8_t color, int scale); extern void ui_draw_line_ctbl(int x0, int y0, int x1, int y1, const uint8_t *colortbl, int colornum, int pos, int scale); extern void ui_draw_line_limit(int x0, int y0, int x1, int y1, uint8_t color, int scale); extern void ui_draw_line_limit_ctbl(int x0, int y0, int x1, int y1, const uint8_t *colortbl, int colornum, int pos, int scale); extern void ui_draw_slider(int x, int y, int w, int wdiv, int xoff, uint8_t color, int scale); extern void ui_draw_box1(int x0, int y0, int x1, int y1, uint8_t color1, uint8_t color2, int scale); extern void ui_draw_box2(int x0, int y0, int x1, int y1, uint8_t color1, uint8_t color2, uint8_t color3, uint8_t color4, int scale); extern void ui_draw_box_fill(int x0, int y0, int x1, int y1, const uint8_t *colorptr, uint8_t color0, uint16_t colorhalf, uint16_t ac, uint8_t colorpos, int scale); extern void ui_draw_box_grain(int x0, int y0, int x1, int y1, uint8_t color0, uint8_t color1, uint8_t ae, int scale); extern void ui_draw_text_overlay(int x, int y, const char *str); extern void ui_draw_finish(void); extern void ui_draw_stars(int x, int y, int xoff1, int xoff2, int scale); extern void ui_draw_set_stars_xoffs(bool flag_right); extern void ui_draw_textbox_2str(const char *str1, const char *str2, int y0, int scale); #endif 1oom-1.11.2/src/ui/classic/uielection.c000066400000000000000000000214001476061725400176110ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "comp.h" #include "game_election.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct election_data_s { struct election_s *el; uint8_t *gfx_cylinder; uint8_t *gfx_racem[4]; uint8_t *gfx_race[PLAYER_NUM]; bool flag_countdown; int count; }; /* -------------------------------------------------------------------------- */ static void election_load_data(struct election_data_s *d) { struct game_s *g = d->el->g; ui_draw_erase_buf(); for (int i = 0; i < 3; ++i) { const int item[3] = { 0x17, 0, 0x16 }; uint8_t *gfx; gfx = lbxfile_item_get(LBXFILE_COUNCIL, item[i]); lbxgfx_draw_frame(0, 0, gfx, UI_SCREEN_W, ui_scale); lbxfile_item_release(LBXFILE_COUNCIL, gfx); } hw_video_copy_back_to_page2(); d->gfx_cylinder = lbxfile_item_get(LBXFILE_COUNCIL, 1); { int num; num = d->el->num; SETRANGE(num, 1, 4); for (int i = 0; i < num; ++i) { d->gfx_racem[i] = lbxfile_item_get(LBXFILE_COUNCIL, 0xc + g->eto[d->el->tbl_ei[i]].race); } for (int i = num; i < 4; ++i) { d->gfx_racem[i] = 0; } num = d->el->num + 1; for (int i = 0; i < num; ++i) { d->gfx_race[i] = lbxfile_item_get(LBXFILE_COUNCIL, 0x2 + g->eto[d->el->tbl_ei[i]].race); } } } static void election_free_data(struct election_data_s *d) { lbxfile_item_release_file(LBXFILE_COUNCIL); } static void ui_election_draw_cb(void *vptr) { struct election_data_s *d = vptr; struct election_s *el = d->el; struct game_s *g = el->g; hw_video_copy_back_from_page2(); if ((el->cur_i != PLAYER_NONE) && (d->count == 0)) { uint8_t *gfx = d->gfx_race[el->cur_i]; int fn = lbxgfx_get_frame(gfx); lbxgfx_set_frame_0(gfx); for (int f = 0; f <= fn; ++f) { lbxgfx_draw_frame(125, 0, gfx, UI_SCREEN_W, ui_scale); } } lbxgfx_draw_frame(0, 0, d->gfx_cylinder, UI_SCREEN_W, ui_scale); for (int i = 0; i < MIN(el->num, 4); ++i) { const int lx0[4] = { 50, 200, 0, 275 }; const int lx1[4] = { 125, 275, 50, 319 }; lbxgfx_draw_frame_offs(0, 0, d->gfx_racem[i], lx0[i], 0, lx1[i], UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } if (el->str) { lbxfont_select_set_12_1(3, 0, 0, 0); lbxfont_set_gap_h(1); lbxfont_print_str_split(10, 169, 305, el->str, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } if (d->flag_countdown) { if (--d->count <= 0) { d->flag_countdown = false; d->count = 0; } } #if 0 /* unused, flag is always 0 or 1 */ if (d->flag_countdown == 2) { if (++d->count >= 10) { d->flag_countdown = false; d->count = 0; } } #endif if (el->flag_show_votes) { char buf[0x40]; char vbuf[0x20]; uint16_t n; lbxfont_select(3, 1, 0, 0); n = el->got_votes[0]; lib_sprintf(buf, sizeof(buf), "%s %s", game_election_print_votes(n, vbuf, sizeof(vbuf)), g->emperor_names[el->candidate[0]]); lbxfont_print_str_normal(10, 10, buf, UI_SCREEN_W, ui_scale); n = el->got_votes[1]; lib_sprintf(buf, sizeof(buf), "%s %s", game_election_print_votes(n, vbuf, sizeof(vbuf)), g->emperor_names[el->candidate[1]]); lbxfont_print_str_right(310, 10, buf, UI_SCREEN_W, ui_scale); n = el->total_votes; lib_sprintf(buf, sizeof(buf), "%s %s", game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_total); lbxfont_print_str_center(160, 10, buf, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ void ui_election_start(struct election_s *el) { static struct election_data_s d; /* HACK */ d.el = el; el->uictx = &d; ui_switch_all(el->g); hw_video_copy_back_from_page2(); hw_video_copy_back_to_page3(); if (ui_draw_finish_mode == 0) { ui_palette_fadeout_a_f_1(); } ui_draw_finish_mode = 2; ui_sound_stop_music(); ui_delay_1(); lbxpal_select(10, -1, 0); lbxpal_set_update_range(0, 255); lbxpal_build_colortables(); election_load_data(&d); ui_sound_play_music(0x27); uiobj_table_clear(); uiobj_set_callback_and_delay(ui_election_draw_cb, &d, 3); } void ui_election_show(struct election_s *el) { struct election_data_s *d = el->uictx; bool flag_done = false; d->count = 0; uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(1); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; break; } ui_election_draw_cb(d); ui_delay_ticks_or_click(el->ui_delay); ui_draw_finish(); } uiobj_table_clear(); } void ui_election_delay(struct election_s *el, int delay) { struct election_data_s *d = el->uictx; d->flag_countdown = true; d->count = delay; while (d->flag_countdown) { ui_delay_prepare(); ui_election_draw_cb(d); ui_delay_ticks_or_click(el->ui_delay); ui_draw_finish(); } } int ui_election_vote(struct election_s *el, int player_i) { struct election_data_s *d = el->uictx; struct game_s *g = el->g; char cnamebuf[3][0x20]; int16_t oi, oi_c1, oi_c2, choice = -1; bool flag_done = false; for (int i = 0; i < 2; ++i) { player_id_t pi; pi = el->candidate[i]; lib_sprintf(cnamebuf[i], 0x20, "%s %s", game_str_el_bull, (pi == player_i) ? game_str_el_self : g->emperor_names[pi]); } lib_sprintf(cnamebuf[2], 0x20, "%s %s", game_str_el_bull, game_str_el_abs); uiobj_table_clear(); lbxfont_select(3, 1, 0, 0); oi_c1 = uiobj_add_mousearea(150, 169, 190, 177, MOO_KEY_1); oi_c2 = uiobj_add_mousearea(150, 179, 190, 187, MOO_KEY_2); /*oi_ca =*/ uiobj_add_mousearea(150, 189, 190, 197, MOO_KEY_0); uiobj_add_ta(150, 169, 40, cnamebuf[0], false, &choice, 1, 0, 0, MOO_KEY_UNKNOWN); uiobj_add_ta(150, 179, 40, cnamebuf[1], false, &choice, 2, 0, 0, MOO_KEY_UNKNOWN); uiobj_add_ta(150, 189, 40, cnamebuf[2], false, &choice, 0, 0, 0, MOO_KEY_UNKNOWN); while (!flag_done) { ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; break; } ui_election_draw_cb(d); ui_delay_ticks_or_click(3); ui_draw_finish(); } uiobj_table_clear(); if (oi == oi_c1) { return 1; } if (oi == oi_c2) { return 2; } return 0; } bool ui_election_accept(struct election_s *el, int player_i) { struct election_data_s *d = el->uictx; char buf[2][0x20]; int16_t oi_y, oi_n, choice = -1, y = 169; bool flag_done = false, flag_accept = false; lib_sprintf(buf[0], 0x20, "%s %s", game_str_el_bull, game_str_el_yes); lib_sprintf(buf[1], 0x20, "%s %s", game_str_el_bull, game_str_el_no2); uiobj_table_clear(); lbxfont_select_set_12_1(3, 0, 0, 0); if (lbxfont_calc_str_width(el->str) >= (160 - 10)) { y += 10; } lbxfont_select(3, 1, 0, 0); oi_y = uiobj_add_mousearea(160, y, 200, y + 8, MOO_KEY_y); oi_n = uiobj_add_mousearea(160, y + 10, 200, y + 18, MOO_KEY_n); uiobj_add_ta(160, y, 40, buf[0], false, &choice, 1, 0, 0, MOO_KEY_UNKNOWN); uiobj_add_ta(160, y + 10, 40, buf[1], false, &choice, 0, 0, 0, MOO_KEY_UNKNOWN); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_y) || (oi == UIOBJI_ESC)) { flag_accept = true; } if (oi == oi_n) { flag_accept = false; } if (oi != 0) { ui_sound_play_sfx_24(); flag_done = true; } ui_election_draw_cb(d); ui_delay_ticks_or_click(3); ui_draw_finish(); } uiobj_table_clear(); return flag_accept; } void ui_election_end(struct election_s *el) { struct election_data_s *d = el->uictx; ui_sound_stop_music(); ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; hw_video_copy_back_from_page3(); hw_video_copy_back_to_page2(); lbxpal_select(0, -1, 0); lbxpal_set_update_range(0, 255); lbxpal_build_colortables(); uiobj_unset_callback(); uiobj_table_clear(); election_free_data(d); } 1oom-1.11.2/src/ui/classic/uiempirereport.c000066400000000000000000000144321476061725400205330ustar00rootroot00000000000000#include "config.h" #include #include "uiempirereport.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_stat.h" #include "game_str.h" #include "game_tech.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" /* -------------------------------------------------------------------------- */ struct empirereport_data_s { struct game_s *g; uint8_t *gfx; player_id_t api; player_id_t pi; }; static void empirereport_data_load(struct empirereport_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 3); } static void empirereport_data_free(struct empirereport_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void empirereport_draw_cb(void *vptr) { struct empirereport_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->pi]); const shipresearch_t *srd = &(g->srd[d->pi]); char buf[0x40]; ui_draw_color_buf(0x3e); lbxgfx_draw_frame(0, 0, d->gfx, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(21, 15, 60, 48, 0, ui_scale); lbxgfx_draw_frame(21, 15, ui_data.gfx.planets.race[e->race], UI_SCREEN_W, ui_scale); ui_draw_filled_rect(17, 58, 64, 68, tbl_banner_color2[e->banner], ui_scale); lbxfont_select(5, 6, 0, 0); { const char *str = ui_extra_enabled ? g->emperor_names[d->pi] : game_str_tbl_races[e->race]; lbxfont_print_str_center(40, 60, str, UI_SCREEN_W, ui_scale); } lbxfont_select(0, 6, 0, 0); lbxfont_print_str_center(40, 74, game_str_tbl_trait1[e->trait1], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(40, 81, game_str_tbl_trait2[e->trait2], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(40, 101, game_str_re_reportis, UI_SCREEN_W, ui_scale); { int reportage = g->year - g->eto[d->api].spyreportyear[d->pi] - 1; if (reportage < 2) { lib_sprintf(buf, sizeof(buf), "%s", game_str_re_current); } else { lib_sprintf(buf, sizeof(buf), "%i %s", reportage, game_str_re_yearsold); } lbxfont_print_str_center(40, 108, buf, UI_SCREEN_W, ui_scale); } lbxfont_select(3, 0, 0, 0); lbxfont_set_color_c_n(0x26, 6); lbxfont_print_str_center(41, 128, game_str_re_alliance, UI_SCREEN_W, ui_scale); ui_draw_line1(9, 136, 72, 136, 0x26, ui_scale); lbxfont_select(0, 6, 0, 0); { int n = 0; for (int i = 0; (i < g->players) && (n < 3); ++i) { if ((i != d->pi) && (e->treaty[i] == TREATY_ALLIANCE) && IS_ALIVE(g, i)) { ui_draw_pixel(9, 140 + 6 * n, 0, ui_scale); ui_draw_pixel(9, 141 + 6 * n, 0, ui_scale); ui_draw_pixel(10, 140 + 6 * n, 0, ui_scale); ui_draw_pixel(10, 141 + 6 * n, 0, ui_scale); lbxfont_print_str_normal(13, 139 + 6 * n, game_str_tbl_races[g->eto[i].race], UI_SCREEN_W, ui_scale); ++n; } } } lbxfont_select(3, 0, 0, 0); lbxfont_set_color_c_n(0x26, 6); lbxfont_print_str_center(41, 165, game_str_re_wars, UI_SCREEN_W, ui_scale); ui_draw_line1(9, 173, 72, 173, 0x26, ui_scale); lbxfont_select(0, 6, 0, 0); { int n = 0; for (int i = 0; (i < g->players) && (n < 3); ++i) { if ((i != d->pi) && (e->treaty[i] >= TREATY_WAR) && IS_ALIVE(g, i)) { ui_draw_pixel(9, 177 + 6 * n, 0, ui_scale); ui_draw_pixel(9, 178 + 6 * n, 0, ui_scale); ui_draw_pixel(10, 177 + 6 * n, 0, ui_scale); ui_draw_pixel(10, 178 + 6 * n, 0, ui_scale); lbxfont_print_str_normal(13, 176 + 6 * n, game_str_tbl_races[g->eto[i].race], UI_SCREEN_W, ui_scale); ++n; } } } for (int f = 0; f < TECH_FIELD_NUM; ++f) { const uint8_t *rct = &(srd->researchcompleted[f][0]); uint16_t tc; uint8_t first, num, rf; tc = e->tech.completed[f]; rf = g->eto[d->api].spyreportfield[d->pi][f]; num = 0; for (int i = 0; i < tc; ++i) { uint8_t rc; rc = rct[i]; if (rc <= rf) { num = i + 1; } } if (num > 8) { first = num - 8; num = 8; } else { first = 0; } for (int i = 0; i < num; ++i) { uint8_t rc; rc = rct[first + i]; game_tech_get_name(g->gaux, f, rc, buf, sizeof(buf)); lbxfont_select(2, game_tech_player_has_tech(g, f, rc, d->api) ? 0xa : 0, 0, 0); if ((rc <= 50) && (game_tech_get_tier(g->gaux, f, rc) == TECH_GROUP_CONTROLLED_ENVIRONMENT)) { int j, pos_space; j = 0; pos_space = 0; while (buf[j] != 0) { if (buf[j] == ' ') { pos_space = j; } ++j; } lib_sprintf(&buf[pos_space], sizeof(buf) - pos_space, " %s", game_str_re_environ); } lbxfont_print_str_normal(85 + (f & 1) * 120, 16 + (f / 2) * 65 + i * 6, buf, UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ void ui_empirereport(struct game_s *g, player_id_t active_player, player_id_t pi) { struct empirereport_data_s d; bool flag_done = false; empirereport_data_load(&d); d.g = g; d.api = active_player; d.pi = pi; game_update_production(g); game_update_empire_contact(g); game_update_maint_costs(g); uiobj_table_clear(); uiobj_set_help_id(39); uiobj_set_callback_and_delay(empirereport_draw_cb, &d, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if (oi != UIOBJI_NONE) { flag_done = true; } if (!flag_done) { empirereport_draw_cb(&d); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); uiobj_set_help_id(-1); empirereport_data_free(&d); } 1oom-1.11.2/src/ui/classic/uiempirereport.h000066400000000000000000000003201476061725400205270ustar00rootroot00000000000000#ifndef INC_1OOM_UIEMPIREREPORT_H #define INC_1OOM_UIEMPIREREPORT_H #include "game_types.h" struct game_s; extern void ui_empirereport(struct game_s *g, player_id_t active_player, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiempirestatus.c000066400000000000000000000057511476061725400205470ustar00rootroot00000000000000#include "config.h" #include #include "uiempirestatus.h" #include "game.h" #include "game_stat.h" #include "game_str.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" /* -------------------------------------------------------------------------- */ struct empirestatus_data_s { struct game_s *g; uint8_t *gfx; struct game_stats_s st; }; static void empirestatus_data_load(struct empirestatus_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 2); } static void empirestatus_data_free(struct empirestatus_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void empirestatus_draw_cb(void *vptr) { struct empirestatus_data_s *d = vptr; const struct game_s *g = d->g; const struct game_stats_s *st = &(d->st); ui_draw_color_buf(0x3a); lbxgfx_draw_frame(0, 0, d->gfx, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(4, 0xf, 0, 0); lbxfont_print_str_center(160, 9, game_str_ra_stats, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, 5, 0, 0); lbxfont_print_str_normal(15, 11, game_str_year, UI_SCREEN_W, ui_scale); lbxfont_print_num_normal(42, 11, g->year + YEAR_BASE, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); for (int s = 0; s < 6; ++s) { for (int i = 0; i < st->num; ++i) { player_id_t pi; const empiretechorbit_t *e; int x, y; uint8_t v; x = (s / 3) * 156 + 11; y = (s % 3) * 57 + i * 7 + 38; pi = st->p[i]; e = (&g->eto[pi]); lbxfont_print_str_normal(x, y, game_str_tbl_race[e->race], UI_SCREEN_W, ui_scale); v = st->v[s][i]; if (v) { ui_draw_filled_rect(x + 35, y + 1, x + 34 + v, y + 2, tbl_banner_color2[e->banner], ui_scale); if (v > 1) { ui_draw_line1(x + 35, y + 3, x + 33 + v, y + 3, 0, ui_scale); } } } } } /* -------------------------------------------------------------------------- */ void ui_empirestatus(struct game_s *g, player_id_t api) { struct empirestatus_data_s d; bool flag_done = false; empirestatus_data_load(&d); d.g = g; game_stats_all(g, api, &(d.st)); uiobj_table_clear(); uiobj_set_help_id(15); uiobj_set_callback_and_delay(empirestatus_draw_cb, &d, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if (oi != UIOBJI_NONE) { flag_done = true; } if (!flag_done) { empirestatus_draw_cb(&d); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); uiobj_set_help_id(-1); empirestatus_data_free(&d); } 1oom-1.11.2/src/ui/classic/uiempirestatus.h000066400000000000000000000002651476061725400205470ustar00rootroot00000000000000#ifndef INC_1OOM_UIEMPIRESTATUS_H #define INC_1OOM_UIEMPIRESTATUS_H #include "game_types.h" struct game_s; extern void ui_empirestatus(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiending.c000066400000000000000000000367701476061725400172730ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game_str.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uinews.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct anim_winlose_1_s { int frame; uint8_t *gfx_stars; uint8_t *gfx_planets; uint8_t *gfx_ships; const char *name; }; struct anim_winlose_2_s { int frame; uint8_t *gfx_winning2; }; struct anim_winlose_3_s { int frame; uint8_t *gfx_winlast; uint8_t *gfx_winface; const char *str1; const char *str2; const char *str3; const char *str4; const char *name; bool flag_good; }; struct anim_winlose_exile_s { int frame; uint8_t *gfx_ships; uint8_t *gfx_stars; const char *name; }; struct anim_winlose_funeral_s { int frame; uint8_t *gfx_lose; uint8_t *gfx_flag; uint8_t *gfx_coffin; uint8_t *gfx_march; }; /* -------------------------------------------------------------------------- */ static bool check_lbx_file(void) { if (!lbxfile_exists(LBXFILE_WINLOSE)) { log_warning("skipping ending due to missing %s\n", lbxfile_name(LBXFILE_WINLOSE)); uiobj_table_clear(); uiobj_unset_callback(); ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); return false; } return true; } static void ui_play_winlose_cb1(void *vptr) { struct anim_winlose_1_s *p = vptr; int f = p->frame; ui_draw_erase_buf(); lbxgfx_draw_frame_offs(0 - f, 0, p->gfx_stars, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(UI_VGA_W - f, 0, p->gfx_stars, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); if (f > 0x32) { lbxgfx_draw_frame(0, 0, p->gfx_ships, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(UI_VGA_W - 1 - ((f - 0x32) * 3) / 2, 0, p->gfx_planets, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } lbxfont_select(4, 0, 0, 0); if ((f > 0xa) && (f < 0x14)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0x64 - (f - 0xa) * 0xa); } if ((f > 0x3c) && (f < 0x46)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n((f - 0x3c) * 0xa); } if (f == 0x14) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0); } if ((f > 0xa) && (f < 0x46)) { char buf[100]; lib_strcpy(buf, game_str_wl_won_1, sizeof(buf)); lib_strcat(buf, p->name, sizeof(buf)); lbxfont_print_str_normal(5, 10, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(5, 0x19, game_str_wl_won_2, UI_SCREEN_W, ui_scale); } if ((f > 0x50) && (f < 0x5a)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0x64 - (f - 0x50) * 0xa); } if (f == 0x5a) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0); } if ((f > 0x82) && (f < 0x8c)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n((f - 0x82) * 0xa); } if ((f > 0x50) && (f < 0x8c)) { lbxfont_print_str_normal(10, 10, game_str_wl_won_3, UI_SCREEN_W, ui_scale); } p->frame = ++f; } static void ui_play_winlose_cb2(void *vptr) { struct anim_winlose_2_s *p = vptr; int f = p->frame; if (f == 0) { ui_draw_erase_buf(); lbxgfx_draw_frame_pal(0, 0, p->gfx_winning2, UI_SCREEN_W, ui_scale); lbxpal_set_update_range(0, 255); } else { hw_video_copy_buf(); lbxgfx_draw_frame_pal(0, 0, p->gfx_winning2, UI_SCREEN_W, ui_scale); } p->frame = ++f; } static void ui_play_winlose_cb3(void *vptr) { struct anim_winlose_3_s *p = vptr; int fa = lbxgfx_get_frame(p->gfx_winlast); int fb = lbxgfx_get_frame(p->gfx_winface); int fc = p->frame; int ff = (fc >= 0xa) ? fb : 0; int f; if ((fa == 0) || (fa == 8)) { ui_draw_erase_buf(); } else { hw_video_copy_buf(); } lbxgfx_draw_frame_pal(0, 0, p->gfx_winlast, UI_SCREEN_W, ui_scale); lbxgfx_set_frame_0(p->gfx_winface); for (f = 0; f <= ff; ++f) { lbxgfx_draw_frame(0x82, 0x32, p->gfx_winface, UI_SCREEN_W, ui_scale); } f = ++fc; lbxfont_select(4, 0, 0, 0); if ((f > 0xa) && (f < 0x14)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0x64 - (f - 0xa) * 0xa); } if ((f > 0x3c) && (f < 0x46)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n((f - 0x3c) * 0xa); } if (f == 0x14) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0); } if ((f > 0x0a) && (f < 0x46)) { lbxfont_print_str_normal(10, 10, p->str1, UI_SCREEN_W, ui_scale); if (p->flag_good) { lbxfont_print_str_normal(10, 0x19, p->str2, UI_SCREEN_W, ui_scale); } else { char buf[0x48]; lib_strcpy(buf, p->str2, sizeof(buf)); lib_strcat(buf, p->name, sizeof(buf)); lib_strcat(buf, p->str3, sizeof(buf)); lbxfont_print_str_normal(10, 0x19, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(10, 0x28, p->str4, UI_SCREEN_W, ui_scale); } } p->frame = f; } static void ui_play_ending_good_or_tyrant(int race, const char *name, bool flag_good) { int16_t oi_skip; bool flag_skip = false; struct anim_winlose_1_s wld1; struct anim_winlose_2_s wld2; struct anim_winlose_3_s wld3; if (ui_draw_finish_mode == 0) { ui_palette_fadeout_4_3_1(); } if (!check_lbx_file()) { return; } if (flag_good) { wld3.str1 = game_str_wl_3_good_1; wld3.str2 = game_str_wl_3_good_2; wld3.str3 = 0; wld3.str4 = 0; } else { wld3.str1 = game_str_wl_3_tyrant_1; wld3.str2 = game_str_wl_3_tyrant_2; wld3.str3 = game_str_wl_3_tyrant_3; wld3.str4 = game_str_wl_3_tyrant_4; } wld3.flag_good = flag_good; wld3.name = name; lbxpal_select(8, -1, 0); wld1.name = name; wld1.gfx_planets = lbxfile_item_get(LBXFILE_WINLOSE, 0x13); wld1.gfx_stars = lbxfile_item_get(LBXFILE_WINLOSE, 0x14); wld3.gfx_winface = lbxfile_item_get(LBXFILE_WINLOSE, 0x15 + race); wld1.gfx_ships = lbxfile_item_get(LBXFILE_WINLOSE, 0x20); ui_sound_play_music(2); uiobj_table_clear(); oi_skip = uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(3); uiobj_set_callback_and_delay(ui_play_winlose_cb1, &wld1, 3); wld1.frame = 0; while ((wld1.frame < 150) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (wld1.frame == 0) { ui_draw_erase_buf(); } ui_play_winlose_cb1(&wld1); uiobj_finish_frame(); if (wld1.frame == 1) { ui_palette_fadein_60_3_1(); } ui_delay_ticks_or_click(3); } } ui_palette_fadeout_5_5_1(); lbxfile_item_release(LBXFILE_WINLOSE, wld1.gfx_planets); lbxfile_item_release(LBXFILE_WINLOSE, wld1.gfx_ships); lbxfile_item_release(LBXFILE_WINLOSE, wld1.gfx_stars); if (!flag_skip) { wld2.gfx_winning2 = lbxfile_item_get(LBXFILE_WINLOSE, 0x1f); wld2.frame = 0; uiobj_set_callback_and_delay(ui_play_winlose_cb2, &wld2, 3); while ((wld2.frame < 0x14) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { ui_play_winlose_cb2(&wld2); uiobj_finish_frame(); if (wld2.frame == 1) { ui_palette_fadein_5f_5_1(); } ui_delay_ticks_or_click(3); } } ui_palette_fadeout_5_5_1(); lbxfile_item_release(LBXFILE_WINLOSE, wld2.gfx_winning2); } if (!flag_skip) { wld3.gfx_winlast = lbxfile_item_get(LBXFILE_WINLOSE, 0x21); wld3.frame = 0; uiobj_set_callback_and_delay(ui_play_winlose_cb3, &wld3, 3); lbxpal_select(8, -1, 0); lbxpal_set_update_range(0, 255); while ((wld3.frame < 0x50) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { ui_play_winlose_cb3(&wld3); uiobj_finish_frame(); if (wld3.frame == 1) { ui_palette_fadein_4b_19_1(); } ui_delay_ticks_or_click(3); } } ui_palette_fadeout_5_5_1(); lbxfile_item_release(LBXFILE_WINLOSE, wld3.gfx_winlast); } lbxfile_item_release(LBXFILE_WINLOSE, wld3.gfx_winface); ui_sound_stop_music(); if (!flag_skip) { ui_news_won(flag_good); ui_palette_fadeout_4_3_1(); } hw_audio_music_fadeout(); ui_delay_1e(); ui_sound_stop_music(); ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); } static void ui_play_winlose_exile_cb(void *vptr) { struct anim_winlose_exile_s *p = vptr; int f = p->frame; ui_draw_erase_buf(); lbxgfx_draw_frame_offs(0 - f, 0, p->gfx_stars, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(UI_VGA_W - f, 0, p->gfx_stars, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(UI_VGA_W * 2- f, 0, p->gfx_stars, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(f * 3 - 0xf0, 0, p->gfx_ships, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxfont_select(4, 0, 0, 0); if ((f > 0x14) && (f < 0x28)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0x64 - (f - 0x14) * 5); } if ((f > 0x78) && (f < 0x8c)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n((f - 0x78) * 5); } if (f == 0x28) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0); } if ((f > 0x14) && (f < 0x8c)) { char buf[100]; lib_strcpy(buf, game_str_wl_exile_1, sizeof(buf)); lib_strcat(buf, p->name, sizeof(buf)); lbxfont_print_str_normal(0, 0xa, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(0, 0x19, game_str_wl_exile_2, UI_SCREEN_W, ui_scale); } lbxfont_select(4, 0, 0, 0); if ((f > 0xa0) && (f < 0xb4)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0x64 - (f - 0xa0) * 5); } if ((f > 0x104) && (f < 0x118)) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n((f - 0x104) * 5); } if (f == 0xb4) { lbxpal_set_update_range(2, 0x20); ui_palette_fade_n(0); } if ((f > 0xa0) && (f < 0x118)) { lbxfont_print_str_normal(0xa, 0xa, game_str_wl_exile_3, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(0xa, 0x19, game_str_wl_exile_4, UI_SCREEN_W, ui_scale); } p->frame = ++f; } static void ui_play_winlose_funeral_cb(void *vptr) { struct anim_winlose_funeral_s *p = vptr; int fa, f = p->frame; ui_draw_erase_buf(); fa = lbxgfx_get_frame(p->gfx_lose); lbxgfx_set_frame_0(p->gfx_lose); for (int i = 0; i <= fa; ++i) { lbxgfx_draw_frame(0, 0, p->gfx_lose, UI_SCREEN_W, ui_scale); } if ((f > 0x14) && (f < 0xa6)) { int x, y; x = 0xf9 - ((f - 0x14) * 0x17b) / 0x92; y = ((f - 0x14) * 0xe3) / 0x92 - 0x4a; lbxgfx_draw_frame_offs(x, y, p->gfx_coffin, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(x, y, p->gfx_march, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame(0, 0, p->gfx_flag, UI_SCREEN_W, ui_scale); p->frame = ++f; } /* -------------------------------------------------------------------------- */ void ui_play_ending_good(int race, const char *name) { ui_play_ending_good_or_tyrant(race, name, true); } void ui_play_ending_tyrant(int race, const char *name) { ui_play_ending_good_or_tyrant(race, name, false); } void ui_play_ending_funeral(int banner_live, int banner_dead) { int16_t oi_skip; struct anim_winlose_funeral_s wld; ui_draw_finish_mode = 2; ui_palette_fadeout_4_3_1(); if (!check_lbx_file()) { return; } wld.gfx_lose = lbxfile_item_get(LBXFILE_WINLOSE, 0); wld.gfx_flag = lbxfile_item_get(LBXFILE_WINLOSE, 1 + banner_live); wld.gfx_coffin = lbxfile_item_get(LBXFILE_WINLOSE, 7 + banner_dead); wld.gfx_march = lbxfile_item_get(LBXFILE_WINLOSE, 0xd + banner_live); ui_sound_play_music(3); lbxgfx_apply_palette(wld.gfx_lose); /* FIXME should not be needed */ ui_cursor_setup_area(1, &ui_cursor_area_all_i0); uiobj_table_clear(); oi_skip = uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(3); uiobj_set_callback_and_delay(ui_play_winlose_funeral_cb, &wld, 4); wld.frame = 0; while (wld.frame < 0xba) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); ui_play_winlose_funeral_cb(&wld); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { wld.frame = 0x2710; } ++wld.frame; ui_delay_ticks_or_click(4); ui_draw_finish(); ui_palette_set_n(); } hw_audio_music_fadeout(); ui_palette_fadeout_14_14_2(); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_lose); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_flag); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_coffin); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_march); ui_draw_erase_buf(); ui_draw_finish_mode = 1; uiobj_finish_frame(); ui_draw_erase_buf(); ui_sound_stop_music(); } void ui_play_ending_exile(const char *name) { int16_t oi_skip; bool flag_skip = false; struct anim_winlose_exile_s wld; if (ui_draw_finish_mode == 0) { ui_palette_fadeout_4_3_1(); } if (!check_lbx_file()) { return; } lbxpal_select(8, -1, 0); wld.name = name; wld.gfx_ships = lbxfile_item_get(LBXFILE_WINLOSE, 0x22); wld.gfx_stars = lbxfile_item_get(LBXFILE_WINLOSE, 0x23); ui_sound_play_music(3); uiobj_table_clear(); oi_skip = uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(3); uiobj_set_callback_and_delay(ui_play_winlose_exile_cb, &wld, 3); wld.frame = 0; while ((wld.frame < 0x17c) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { ui_play_winlose_exile_cb(&wld); uiobj_finish_frame(); if (wld.frame == 1) { ui_palette_fadein_60_3_1(); } ui_delay_ticks_or_click(2); } } hw_audio_music_fadeout(); ui_palette_fadeout_14_14_2(); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_ships); lbxfile_item_release(LBXFILE_WINLOSE, wld.gfx_stars); ui_draw_erase_buf(); ui_draw_finish_mode = 1; uiobj_finish_frame(); ui_draw_erase_buf(); ui_sound_stop_music(); } 1oom-1.11.2/src/ui/classic/uiexplore.c000066400000000000000000000157631476061725400175040ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uigmap.h" #include "uilanding.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct explore_data_s { struct game_s *g; player_id_t api; uint8_t planet; bool by_scanner; bool colony_ship; uint8_t *gfx_explobac; uint8_t *gfx_contbutt; uint8_t *gfx_yn_back; uint8_t *gfx_colony; void *gmap; }; static void explore_load_data(struct explore_data_s *d) { const planet_t *p = &(d->g->planet[d->planet]); d->gfx_explobac = lbxfile_item_get(LBXFILE_BACKGRND, 0xf); d->gfx_contbutt = lbxfile_item_get(LBXFILE_BACKGRND, 0xc); d->gfx_yn_back = lbxfile_item_get(LBXFILE_BACKGRND, 0x18); d->gfx_colony = lbxfile_item_get(LBXFILE_COLONIES, p->type * 2 + ((p->owner != PLAYER_NONE) ? 1 : 0)); } static void explore_free_data(struct explore_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_explobac); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_contbutt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_yn_back); lbxfile_item_release(LBXFILE_COLONIES, d->gfx_colony); } static void explore_draw_planetinfo(const struct game_s *g, uint8_t planet) { const planet_t *p = &(g->planet[planet]); int y = 0; if (p->type != PLANET_TYPE_NOT_HABITABLE) { if (p->growth != PLANET_GROWTH_NORMAL) { int i = p->growth; if (i > PLANET_GROWTH_NORMAL) { --i; } y = 33; lbxfont_select_set_12_4(3, 0, 0, 0); lbxfont_print_str_center(267, 92, game_str_ex_pg1[i], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 101, game_str_ex_pg2[i], UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(2, 0xa, 0, 0); lbxfont_print_str_center(267, 111, game_str_ex_popgr, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 118, game_str_ex_pg3[i], UI_SCREEN_W, ui_scale); } if (p->special != PLANET_SPECIAL_NORMAL) { const char *s1, *s2, *s3; int i = p->special; if (i > PLANET_SPECIAL_NORMAL) { if (i == PLANET_SPECIAL_4XTECH) { i = PLANET_SPECIAL_ARTIFACTS; } --i; } lbxfont_select_set_12_4(3, 0, 0, 0); lbxfont_print_str_center(267, 96 + y, game_str_ex_ps1[i], UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(2, 0xa, 0, 0); if ((p->special != PLANET_SPECIAL_ARTIFACTS) && (p->special != PLANET_SPECIAL_4XTECH)) { i = p->special; if (i > PLANET_SPECIAL_NORMAL) { i -= 2; } s3 = game_str_ex_ps2[i]; s1 = game_str_ex_resopnt; s2 = game_str_ex_fromind; } else { s1 = game_str_ex_techpnt; s2 = game_str_ex_fromres; s3 = (p->special == PLANET_SPECIAL_ARTIFACTS) ? game_str_ex_aredbl : game_str_ex_arequad; } lbxfont_print_str_center(267, 106 + y, s1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 113 + y, s2, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 120 + y, s3, UI_SCREEN_W, ui_scale); } } } static void explore_draw_cb(void *vptr) { struct explore_data_s *d = vptr; const struct game_s *g = d->g; hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_explobac, UI_SCREEN_W, ui_scale); ui_starmap_draw_planetinfo_2(g, d->api, PLAYER_NUM, d->planet); lbxgfx_draw_frame(227, 58, d->gfx_colony, UI_SCREEN_W, ui_scale); ui_draw_line1(227, 57, 227, 160, 0, ui_scale); ui_draw_line1(227, 57, 310, 57, 0, ui_scale); ui_draw_line1(310, 57, 310, 160, 0, ui_scale); /*game_update_visibility();*/ ui_gmap_basic_draw_frame(d->gmap, d->api); ui_gmap_draw_planet_border(g, d->planet); lbxfont_select_set_12_1(3, 0xa, 0, 0); if (!d->colony_ship) { if (d->by_scanner) { lbxfont_print_str_center(267, 58, game_str_ex_planeta, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 66, game_str_ex_scanner, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 74, game_str_ex_explore, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 82, game_str_ex_starsys, UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_center(267, 60, game_str_ex_scout, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 69, game_str_ex_explore, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 78, game_str_ex_starsys, UI_SCREEN_W, ui_scale); } } else { lbxfont_print_str_center(267, 60, game_str_ex_build, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 69, game_str_ex_colony, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(224, 159, d->gfx_yn_back, UI_SCREEN_W, ui_scale); } explore_draw_planetinfo(g, d->planet); } /* -------------------------------------------------------------------------- */ bool ui_explore(struct game_s *g, int pi, uint8_t planet_i, bool by_scanner, bool flag_colony_ship) { struct explore_data_s d; int16_t oi_cont, oi_y, oi_n; bool flag_done = false; ui_switch_1(g, pi); d.g = g; d.api = pi; d.planet = planet_i; d.by_scanner = by_scanner; d.colony_ship = flag_colony_ship; d.gmap = ui_gmap_basic_init(g, true); explore_load_data(&d); uiobj_set_callback_and_delay(explore_draw_cb, &d, 4); uiobj_table_clear(); if (!flag_colony_ship) { oi_cont = uiobj_add_t0(227, 164, "", d.gfx_contbutt, MOO_KEY_c); oi_n = uiobj_add_inputkey(MOO_KEY_SPACE); oi_y = UIOBJI_INVALID; } else { oi_cont = UIOBJI_INVALID; oi_n = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.scrapbut_no, MOO_KEY_n); oi_y = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.scrapbut_yes, MOO_KEY_y); } while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_cont) || (oi == oi_n)) { ui_sound_play_sfx_24(); flag_done = true; flag_colony_ship = false; } if (oi == oi_y) { ui_sound_play_sfx_24(); flag_done = true; ui_landing(g, pi, planet_i); } if (!flag_done) { explore_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } } uiobj_unset_callback(); uiobj_table_clear(); explore_free_data(&d); return flag_colony_ship; } 1oom-1.11.2/src/ui/classic/uifleet.c000066400000000000000000000423051476061725400171150ustar00rootroot00000000000000#include "config.h" #include #include #include "uifleet.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ #define FLEET_LINES 5 #define FLEET_VALUE(_i_) ui_data.sorted.value[ui_data.sorted.index[(_i_)]] #define FLEET_IS_ENROUTE(_i_) ((FLEET_VALUE(_i_) & 0x100) != 0) #define FLEET_GET_ENROUTE(_i_) (FLEET_VALUE(_i_) >> 9) #define FLEET_GET_PLANET(_i_) (FLEET_VALUE(_i_) & 0xff) #define FLEETS_IS_ENROUTE(_i_) ((ui_data.sorted.value[_i_] & 0x100) != 0) #define FLEETS_GET_ENROUTE(_i_) (ui_data.sorted.value[_i_] >> 9) #define FLEETS_GET_PLANET(_i_) (ui_data.sorted.value[_i_] & 0xff) struct fleet_data_s { struct game_s *g; player_id_t api; int selected; int pos; int num; int lines; int order_i; uint8_t *gfx_fleetbrb; }; static void load_fl_data(struct fleet_data_s *d) { d->gfx_fleetbrb = lbxfile_item_get(LBXFILE_BACKGRND, 0); } static void free_fl_data(struct fleet_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_fleetbrb); } static void fleet_draw_cb(void *vptr) { struct fleet_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->api]); const shipdesign_t *sd = &(g->srd[d->api].design[0]); int num; ui_draw_color_buf(0x3a); ui_draw_filled_rect(5, 15, 40, 190, 0, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_fleetbrb, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.starmap.fleetbut_scrap, 1); lbxgfx_draw_frame(224, 181, ui_data.gfx.starmap.fleetbut_scrap, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.starmap.fleetbut_up, 1); lbxgfx_set_new_frame(ui_data.gfx.starmap.fleetbut_down, 1); lbxgfx_draw_frame(307, 24, ui_data.gfx.starmap.fleetbut_up, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(307, 156, ui_data.gfx.starmap.fleetbut_down, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(0, 0, 0, 0); lbxfont_print_str_normal(7, 6, game_str_fl_station, UI_SCREEN_W, ui_scale); num = d->num - d->pos; SETMIN(num, 5); for (int i = 0; i < e->shipdesigns_num; ++i) { int x0; x0 = 44 * i + 48; lbxfont_select(2, 0xd, 0, 0); lbxfont_print_str_center(x0 + 19, 6, sd[i].name, UI_SCREEN_W, ui_scale); } for (int i = 0; i < num; ++i) { const planet_t *p; const shipcount_t *s; int x0 = 5, y0, pi, fi; y0 = 33 * i + 17; fi = i + d->pos; pi = FLEET_GET_PLANET(fi); p = &(g->planet[pi]); if (BOOLVEC_IS1(p->explored, d->api)) { player_id_t seenowner; uint8_t a2; lbxgfx_draw_frame(x0 + 1, y0, ui_data.gfx.planets.planet[p->infogfx], UI_SCREEN_W, ui_scale); seenowner = g->seen[d->api][pi].owner; if (seenowner != PLAYER_NONE) { a2 = tbl_banner_fontparam[g->eto[seenowner].banner]; } else { a2 = 4; } lbxfont_select(2, a2, 0, 0); lbxfont_print_str_center(x0 + 19, y0 + 12, FLEET_IS_ENROUTE(fi) ? game_str_fl_moving : game_str_fl_inorbit, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(x0 + 19, y0 + 19, p->name, UI_SCREEN_W, ui_scale); } else { lbxfont_select_set_12_4(2, 0xe, 0, 0); lbxfont_print_str_center(x0 + 19, y0 + 7, game_str_fl_unknown, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(x0 + 19, y0 + 14, game_str_fl_system, UI_SCREEN_W, ui_scale); } if (FLEET_IS_ENROUTE(fi)) { s = g->enroute[FLEET_GET_ENROUTE(fi)].ships; } else { s = e->orbit[pi].ships; } for (int j = 0; j < e->shipdesigns_num; ++j) { int ships; ships = s[j]; if (ships) { uint8_t *gfx_ship; x0 = 44 * j + 48; ui_draw_filled_rect(x0, y0, x0 + 36, y0 + 25, 0, ui_scale); if (!FLEET_IS_ENROUTE(fi)) { int tmp_xoff1 = ui_data.starmap.stars_xoff1; int tmp_xoff2 = ui_data.starmap.stars_xoff2; ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; ui_draw_stars(x0, y0 + 1, j * 10, 37, ui_scale); ui_data.starmap.stars_xoff1 = tmp_xoff1; ui_data.starmap.stars_xoff2 = tmp_xoff2; } else { ui_draw_stars(x0, y0 + 1, j * 5, 37, ui_scale); } gfx_ship = ui_data.gfx.ships[sd[j].look]; lbxgfx_set_frame_0(gfx_ship); if (!FLEET_IS_ENROUTE(fi)) { lbxgfx_draw_frame(x0, y0 + 1, gfx_ship, UI_SCREEN_W, ui_scale); } else { for (int f = 0; f <= ui_data.starmap.frame_ship; ++f) { lbxgfx_draw_frame(x0, y0 + 1, gfx_ship, UI_SCREEN_W, ui_scale); } } lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(x0 + 31, y0 + 19, ships, UI_SCREEN_W, ui_scale); } } } for (int i = num; i < FLEET_LINES; ++i) { ui_draw_filled_rect(7, i * 33 + 17, 40, i * 33 + 42, 0x3a, ui_scale); } ui_data.starmap.frame_ship = (ui_data.starmap.frame_ship + 1) % 5; ui_draw_set_stars_xoffs(false); lbxfont_select(2, 6, 0, 0); lbxfont_print_num_right(137, 185, e->ship_maint_bc, UI_SCREEN_W, ui_scale); } static void ui_fleet_sub(struct fleet_data_s *d) { const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->api]); int num = 0, sd_num = e->shipdesigns_num; for (int i = 0; i < g->galaxy_stars; ++i) { const fleet_orbit_t *r = &(e->orbit[i]); for (int j = 0; j < sd_num; ++j) { if (r->ships[j] != 0) { ui_data.sorted.index[num] = num; ui_data.sorted.value[num] = i; ++num; break; } } } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (r->owner == d->api) { for (int j = 0; j < sd_num; ++j) { if (r->ships[j] != 0) { ui_data.sorted.index[num] = num; ui_data.sorted.value[num] = (i << 9) | 0x100 | r->dest; ++num; break; } } } } d->num = num; } /* -------------------------------------------------------------------------- */ enum { UI_SORT_INDEX = 0, UI_SORT_STATION, UI_SORT_SHIP0, UI_SORT_SHIP1, UI_SORT_SHIP2, UI_SORT_SHIP3, UI_SORT_SHIP4, UI_SORT_SHIP5, UI_SORT_NUM }; #define UI_SORT_SETUP() \ const struct game_s *g = ui_data.sorted.g; \ uint16_t i0 = *((uint16_t const *)ptr0); \ uint16_t i1 = *((uint16_t const *)ptr1); \ uint8_t pli0 = ui_data.sorted.value[i0]; \ uint8_t pli1 = ui_data.sorted.value[i1]; \ const planet_t *p0 = &(g->planet[pli0]); \ const planet_t *p1 = &(g->planet[pli1]) #define UI_SORT_CMP_VALUE(_v0_, _v1_) (((_v0_) != (_v1_)) ? ((_v0_) - (_v1_)) : (i0 - i1)) #define UI_SORT_CMP_VARIABLE(_var_) UI_SORT_CMP_VALUE(p0->_var_, p1->_var_) static int fleet_sort_inc_index(const void *ptr0, const void *ptr1) { uint16_t i0 = *((uint16_t const *)ptr0); uint16_t i1 = *((uint16_t const *)ptr1); return i0 - i1; } static int fleet_sort_dec_index(const void *ptr0, const void *ptr1) { return fleet_sort_inc_index(ptr1, ptr0); } static int fleet_sort_inc_station(const void *ptr0, const void *ptr1) { const struct game_s *g = ui_data.sorted.g; uint16_t i0 = *((uint16_t const *)ptr0); uint16_t i1 = *((uint16_t const *)ptr1); uint8_t pli0 = FLEETS_GET_PLANET(i0); uint8_t pli1 = FLEETS_GET_PLANET(i1); const planet_t *p0 = &(g->planet[pli0]); const planet_t *p1 = &(g->planet[pli1]); int d; if (BOOLVEC_IS0(p0->explored, g->active_player) && BOOLVEC_IS0(p1->explored, g->active_player)) { d = i0 - i1; } else if (BOOLVEC_IS0(p0->explored, g->active_player)) { d = -1; } else if (BOOLVEC_IS0(p1->explored, g->active_player)) { d = 1; } else { d = strcmp(p0->name, p1->name); } return d; } static int fleet_sort_dec_station(const void *ptr0, const void *ptr1) { return fleet_sort_inc_station(ptr1, ptr0); } static int fleet_sort_ship(const void *ptr0, const void *ptr1, int si) { const struct game_s *g = ui_data.sorted.g; const empiretechorbit_t *e = &(g->eto[g->active_player]); uint16_t i0 = *((uint16_t const *)ptr0); uint16_t i1 = *((uint16_t const *)ptr1); uint8_t pli0 = FLEETS_GET_PLANET(i0); uint8_t pli1 = FLEETS_GET_PLANET(i1); const shipcount_t *s0 = FLEETS_IS_ENROUTE(i0) ? g->enroute[FLEETS_GET_ENROUTE(i0)].ships : e->orbit[pli0].ships; const shipcount_t *s1 = FLEETS_IS_ENROUTE(i1) ? g->enroute[FLEETS_GET_ENROUTE(i1)].ships : e->orbit[pli1].ships; int d = 0; if (s0[si] != s1[si]) { d = s0[si] - s1[si]; } else { for (int j = 1; j < e->shipdesigns_num; ++j) { int i; i = (si + j) % e->shipdesigns_num; if (s0[i] != s1[i]) { d = s0[i] - s1[i]; break; } } } if (d == 0) { d = pli0 - pli1; } if (d == 0) { d = i0 - i1; } return d; } #define UI_SORT_DEFINE_SHIP(_n_) \ static int fleet_sort_inc_ship##_n_(const void *ptr0, const void *ptr1) \ { \ return fleet_sort_ship(ptr0, ptr1, _n_); \ } \ static int fleet_sort_dec_ship##_n_(const void *ptr0, const void *ptr1) \ { \ return fleet_sort_ship(ptr1, ptr0, _n_); \ } UI_SORT_DEFINE_SHIP(0) UI_SORT_DEFINE_SHIP(1) UI_SORT_DEFINE_SHIP(2) UI_SORT_DEFINE_SHIP(3) UI_SORT_DEFINE_SHIP(4) UI_SORT_DEFINE_SHIP(5) typedef int sort_cb_t(const void *, const void *); static sort_cb_t * const sort_cb_tbl[UI_SORT_NUM * 2] = { fleet_sort_inc_index, fleet_sort_dec_index, fleet_sort_inc_station, fleet_sort_dec_station, fleet_sort_dec_ship0, fleet_sort_inc_ship0, fleet_sort_dec_ship1, fleet_sort_inc_ship1, fleet_sort_dec_ship2, fleet_sort_inc_ship2, fleet_sort_dec_ship3, fleet_sort_inc_ship3, fleet_sort_dec_ship4, fleet_sort_inc_ship4, fleet_sort_dec_ship5, fleet_sort_inc_ship5 }; static void ui_fleet_sort(struct fleet_data_s *d) { qsort(ui_data.sorted.index, d->num, sizeof(ui_data.sorted.index[0]), sort_cb_tbl[d->order_i]); ui_data.sorted.fleet_order[d->api] = d->order_i; } /* -------------------------------------------------------------------------- */ int ui_fleet(struct game_s *g, player_id_t active_player) { struct fleet_data_s d; bool flag_done = false, flag_scrap = false; int16_t oi_up, oi_down, oi_wheel, oi_ok, oi_scrap, oi_view, oi_tbl_ship[NUM_SHIPDESIGNS], oi_tbl_line[FLEET_LINES]; int16_t oi_sort[UI_SORT_NUM]; int ret = -1; int16_t scroll = 0; load_fl_data(&d); d.g = g; ui_data.sorted.g = g; d.api = active_player; d.pos = 0; d.num = 0; d.order_i = 0; game_update_maint_costs(g); ui_fleet_sub(&d); ui_data.starmap.frame_ship = 0; d.lines = 0; if (ui_extra_enabled) { d.order_i = ui_data.sorted.fleet_order[active_player]; ui_fleet_sort(&d); } uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ oi_up = UIOBJI_INVALID; \ oi_down = UIOBJI_INVALID; \ oi_wheel = UIOBJI_INVALID; \ oi_ok = UIOBJI_INVALID; \ oi_view = UIOBJI_INVALID; \ oi_scrap = UIOBJI_INVALID; \ UIOBJI_SET_TBL_INVALID(oi_tbl_line); \ UIOBJI_SET_TBL_INVALID(oi_tbl_ship); \ UIOBJI_SET_TBL_INVALID(oi_sort); \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(8); uiobj_set_callback_and_delay(fleet_draw_cb, &d, 3); while (!flag_done) { int16_t oi; ui_cursor_setup_area(1, &ui_cursor_area_tbl[flag_scrap ? 0xa : 0]); oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ok) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi == oi_view) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_SPECS; } else if (oi == oi_scrap) { ui_sound_play_sfx_24(); flag_scrap = true; } for (int i = 0; i < g->eto[active_player].shipdesigns_num; ++i) { if (oi == oi_tbl_ship[i]) { ui_sound_play_sfx_24(); ret = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_MUSTSCRAP; ui_data.ui_main_loop_action_prev = UI_MAIN_LOOP_FLEET; ui_data.ui_main_loop_action_next = UI_MAIN_LOOP_FLEET; flag_done = true; break; } } if (oi == oi_up) { ui_sound_play_sfx_24(); d.pos -= FLEET_LINES; SETMAX(d.pos, 0); } else if (oi == oi_down) { ui_sound_play_sfx_24(); d.pos += FLEET_LINES; if ((d.pos + FLEET_LINES) > d.num) { d.pos = d.num - FLEET_LINES; } SETMAX(d.pos, 0); } else if (oi == oi_wheel) { d.pos += scroll; scroll = 0; SETRANGE(d.pos, 0, d.num - FLEET_LINES); } for (int i = 0; i < d.lines; ++i) { if (oi == oi_tbl_line[i]) { ui_sound_play_sfx_24(); if (!FLEET_IS_ENROUTE(d.pos + i)) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_ORBIT_OWN_SEL; g->planet_focus_i[active_player] = FLEET_GET_PLANET(d.pos + i); } else { ui_data.ui_main_loop_action = UI_MAIN_LOOP_ENROUTE_SEL; ui_data.starmap.fleet_selected = FLEET_GET_ENROUTE(d.pos + i); } flag_done = true; break; } } for (int i = 0; i < UI_SORT_NUM; ++i) { if (oi == oi_sort[i]) { int v; v = i * 2; if (v == d.order_i) { ++v; } d.order_i = v; ui_fleet_sort(&d); } } if (!flag_done) { if ((d.pos + FLEET_LINES) > d.num) { d.pos = d.num - FLEET_LINES; } SETMAX(d.pos, 0); d.lines = d.num - d.pos; SETMIN(d.lines, FLEET_LINES); fleet_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); oi_ok = uiobj_add_t0(268, 181, "", ui_data.gfx.starmap.fleetbut_ok, MOO_KEY_SPACE); oi_view = uiobj_add_t0(180, 181, "", ui_data.gfx.starmap.fleetbut_view, (ui_illogical_hotkey_fix ? MOO_KEY_s : MOO_KEY_v)); if (d.pos > 0) { oi_up = uiobj_add_t0(307, 24, "", ui_data.gfx.starmap.fleetbut_up, MOO_KEY_COMMA); } if ((d.num - 5) > d.pos) { oi_down = uiobj_add_t0(307, 156, "", ui_data.gfx.starmap.fleetbut_down, MOO_KEY_PERIOD); } if ((g->eto[active_player].shipdesigns_num > 1) && !flag_scrap) { oi_scrap = uiobj_add_t0(224, 181, "", ui_data.gfx.starmap.fleetbut_scrap, (ui_illogical_hotkey_fix ? MOO_KEY_c : MOO_KEY_s)); } else { lbxgfx_set_new_frame(ui_data.gfx.starmap.fleetbut_scrap, 1); lbxgfx_draw_frame(224, 181, ui_data.gfx.starmap.fleetbut_scrap, UI_SCREEN_W, ui_scale); } if (flag_scrap) { for (int i = 0; i < g->eto[active_player].shipdesigns_num; ++i) { int x0; x0 = 44 * i + 48; oi_tbl_ship[i] = uiobj_add_mousearea(x0, 0, x0 + 38, 180, MOO_KEY_UNKNOWN); } } else if (ui_extra_enabled) { const int x0[UI_SORT_NUM] = { 0, 10, 47, 91, 134, 178, 222, 267 }; const int x1[UI_SORT_NUM] = { 9, 41, 87, 131, 174, 218, 262, 307 }; const int y0 = 5, y1 = 12; int n; n = UI_SORT_SHIP0 + g->eto[active_player].shipdesigns_num; for (int i = 0; i < n; ++i) { oi_sort[i] = uiobj_add_mousearea(x0[i], y0, x1[i], y1, MOO_KEY_UNKNOWN); } } for (int i = 0; i < d.lines; ++i) { oi_tbl_line[i] = uiobj_add_mousearea(5, 15 + i * 33, 288, 44 + i * 33, MOO_KEY_UNKNOWN); } if (d.num >= FLEET_LINES) { oi_wheel = uiobj_add_mousewheel(0, 0, 319, 199, &scroll); } ui_draw_finish(); ui_delay_ticks_or_click(3); } } uiobj_unset_callback(); uiobj_set_help_id(-1); free_fl_data(&d); return ret; } 1oom-1.11.2/src/ui/classic/uifleet.h000066400000000000000000000002621476061725400171160ustar00rootroot00000000000000#ifndef INC_1OOM_UIFLEET_H #define INC_1OOM_UIFLEET_H #include "game_types.h" #include "types.h" struct game_s; extern int ui_fleet(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uigame.c000066400000000000000000000303531476061725400167270ustar00rootroot00000000000000#include "config.h" #include "ui.h" #include "game.h" #include "game_audience.h" #include "game_design.h" #include "game_aux.h" #include "game_misc.h" #include "game_turn_start.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uibasescrap.h" #include "uicaught.h" #include "uicursor.h" #include "uidefs.h" #include "uidesign.h" #include "uidraw.h" #include "uiempirereport.h" #include "uiempirestatus.h" #include "uifleet.h" #include "uigmap.h" #include "uigameopts.h" #include "uiobj.h" #include "uipal.h" #include "uiplanets.h" #include "uiraces.h" #include "uisearch.h" #include "uispecs.h" #include "uistarmap.h" #include "uistarview.h" #include "uiswitch.h" #include "uitech.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ ui_turn_action_t ui_game_turn(struct game_s *g, int *load_game_i_ptr, int pi) { int scrapi = -1; int opponi = -1; if (g->gaux->local_players > 1) { while (ui_switch_1_opts(g, pi)) { switch (ui_gameopts(g, load_game_i_ptr)) { case GAMEOPTS_DONE: break; case GAMEOPTS_LOAD: return UI_TURN_ACT_LOAD_GAME; case GAMEOPTS_QUIT: return UI_TURN_ACT_QUIT_GAME; } } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; ui_starmap_set_pos_focus(g, pi); } ui_data.start_planet_focus_i = g->planet_focus_i[pi]; game_turn_start_messages(g, pi); BOOLVEC_CLEAR(ui_data.starmap.select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_CLEAR(ui_data.starmap.select_prio_trans, TRANSPORT_MAX); while (1) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_data.starmap.xhold = 0; ui_data.starmap.yhold = 0; if (g->evn.build_finished_num[pi] > 0) { uint8_t pli; for (pli = 0; pli < g->galaxy_stars; ++pli) { if (g->planet[pli].finished[0] & (~(1 << FINISHED_SHIP))) { break; } } if (pli < g->galaxy_stars) { g->planet_focus_i[pi] = pli; } else { g->evn.build_finished_num[pi] = 0; if (ui_extra_enabled) { g->planet_focus_i[pi] = ui_data.start_planet_focus_i; } } if (ui_data.ui_main_loop_action != UI_MAIN_LOOP_PLANET_SHIPS) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } ui_starmap_set_pos_focus(g, pi); } ui_data.flag_scrap_for_new_design = false; switch (ui_data.ui_main_loop_action) { case UI_MAIN_LOOP_STARMAP: ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_do(g, pi); break; case UI_MAIN_LOOP_RELOC: ui_cursor_setup_area(2, &ui_cursor_area_tbl[1]); ui_starmap_reloc(g, pi); break; case UI_MAIN_LOOP_PLANET_SHIPS: ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_ships(g, pi); break; case UI_MAIN_LOOP_TRANS: ui_cursor_setup_area(2, &ui_cursor_area_tbl[1]); ui_starmap_trans(g, pi); break; case UI_MAIN_LOOP_ORBIT_OWN_SEL: BOOLVEC_CLEAR(ui_data.starmap.select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_CLEAR(ui_data.starmap.select_prio_trans, TRANSPORT_MAX); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_orbit_own(g, pi); break; case UI_MAIN_LOOP_ORBIT_EN_SEL: BOOLVEC_CLEAR(ui_data.starmap.select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_CLEAR(ui_data.starmap.select_prio_trans, TRANSPORT_MAX); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_orbit_en(g, pi); break; case UI_MAIN_LOOP_TRANSPORT_SEL: if (BOOLVEC_IS1(ui_data.starmap.select_prio_trans, ui_data.starmap.fleet_selected)) { BOOLVEC_CLEAR(ui_data.starmap.select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_CLEAR(ui_data.starmap.select_prio_trans, TRANSPORT_MAX); } BOOLVEC_SET1(ui_data.starmap.select_prio_trans, ui_data.starmap.fleet_selected); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_transport(g, pi); break; case UI_MAIN_LOOP_ENROUTE_SEL: if (BOOLVEC_IS1(ui_data.starmap.select_prio_fleet, ui_data.starmap.fleet_selected)) { BOOLVEC_CLEAR(ui_data.starmap.select_prio_fleet, FLEET_ENROUTE_MAX); BOOLVEC_CLEAR(ui_data.starmap.select_prio_trans, TRANSPORT_MAX); } BOOLVEC_SET1(ui_data.starmap.select_prio_fleet, ui_data.starmap.fleet_selected); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); ui_starmap_enroute(g, pi); break; case UI_MAIN_LOOP_GAMEOPTS: switch (ui_gameopts(g, load_game_i_ptr)) { case GAMEOPTS_DONE: ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case GAMEOPTS_LOAD: return UI_TURN_ACT_LOAD_GAME; case GAMEOPTS_QUIT: return UI_TURN_ACT_QUIT_GAME; } break; case UI_MAIN_LOOP_DESIGN: { struct game_design_s gd; bool ok; int sd_num; sd_num = g->eto[pi].shipdesigns_num; game_design_prepare(g, &gd, pi, &g->current_design[pi]); ok = ui_design(g, &gd, pi); if (ok && (sd_num == NUM_SHIPDESIGNS)) { ui_specs_before(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_SPECS; ui_data.ui_main_loop_action_next = UI_MAIN_LOOP_SPECS; ui_data.ui_main_loop_action_prev = UI_MAIN_LOOP_DESIGN; ui_data.flag_scrap_for_new_design = true; scrapi = ui_specs(g, pi, false); sd_num = g->eto[pi].shipdesigns_num; ok = (sd_num < NUM_SHIPDESIGNS); if (ok) { game_design_look_fix(g, pi, &gd.sd); } } if (ok) { game_design_add(g, pi, &gd.sd, true); } g->current_design[pi] = gd.sd; } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_SPECS: scrapi = ui_specs(g, pi, false); break; case UI_MAIN_LOOP_MUSTSCRAP: if (scrapi >= 0) { ui_specs_mustscrap(g, pi, scrapi); } else { LOG_DEBUG((3, "%s: invalid scrapi %i on MUSTSCRAP\n", __func__, scrapi)); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } break; case UI_MAIN_LOOP_PLANETS: ui_planets(g, pi); ui_starmap_set_pos_focus(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_FLEET: scrapi = ui_fleet(g, pi); if (ui_data.ui_main_loop_action == UI_MAIN_LOOP_ORBIT_OWN_SEL) { ui_starmap_set_pos_focus(g, pi); } else if (ui_data.ui_main_loop_action == UI_MAIN_LOOP_ENROUTE_SEL) { fleet_enroute_t *r; r = &(g->enroute[ui_data.starmap.fleet_selected]); ui_starmap_set_pos(g, r->x, r->y); } break; case UI_MAIN_LOOP_MAP: if (ui_gmap(g, pi)) { ui_starmap_set_pos_focus(g, pi); } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_RACES: opponi = ui_races(g, pi); break; case UI_MAIN_LOOP_EMPIRESTATUS: ui_empirestatus(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_RACES; break; case UI_MAIN_LOOP_EMPIREREPORT: if (IS_PLAYER(g, opponi) && (opponi != pi)) { ui_empirereport(g, pi, opponi); } else { LOG_DEBUG((3, "%s: invalid opponi %i for %i on EMPIREREPORT\n", __func__, opponi, pi)); } ui_data.ui_main_loop_action = UI_MAIN_LOOP_RACES; break; case UI_MAIN_LOOP_AUDIENCE: if (IS_PLAYER(g, opponi) && (opponi != pi)) { game_audience(g, pi, opponi); } else { LOG_DEBUG((3, "%s: invalid opponi %i for %i on AUDIENCE\n", __func__, opponi, pi)); } ui_data.ui_main_loop_action = UI_MAIN_LOOP_RACES; break; case UI_MAIN_LOOP_STARVIEW: ui_starview(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_TECH: ui_tech(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_SCRAP_BASES: ui_basescrap(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_SPIES_CAUGHT: ui_caught(g, pi); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; case UI_MAIN_LOOP_NEXT_TURN: ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; ui_data.news.flag_also = false; return UI_TURN_ACT_NEXT_TURN; default: LOG_DEBUG((0, "BUG: %s: invalid action 0x%x\n", __func__, ui_data.ui_main_loop_action)); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; break; } } return UI_TURN_ACT_QUIT_GAME; } void ui_game_start(struct game_s *g) { for (int i = 0; i < g->nebula_num; ++i) { ui_data.gfx.starmap.nebula[i] = lbxfile_item_get(LBXFILE_STARMAP, 0xf + g->nebula_type[i]); ui_data.gfx.starmap.smnebula[i] = ui_data.gfx.starmap.smneb[g->nebula_type[i] + g->galaxy_size * 10]; } ui_data.gfx.starmap.bmap = lbxfile_item_get(LBXFILE_V11, 1 + g->galaxy_size); /* HACK remove visual glitch on load game */ ui_draw_erase_buf(); hw_video_draw_buf(); hw_video_copy_buf(); lbxpal_select(0, -1, 0); lbxpal_build_colortables(); /* HACK Fix wrong palette after new game via main menu. MOO1 goes from orion.exe to starmap.exe in between and the palette is initialized before coming here. We only need to set the update flags of this range. */ lbxpal_set_update_range(248, 255); ui_palette_set_n(); ui_draw_finish_mode = 1; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; for (int i = 0; i < g->players; ++i) { if (IS_HUMAN(g, i)) { ui_starmap_set_pos_focus(g, i); break; } } BOOLVEC_CLEAR(ui_data.players_viewing, PLAYER_NUM); for (int pli = 0; pli < g->galaxy_stars; ++pli) { ui_data.star_frame[pli] = g->planet[pli].frame; } ui_data.seed = g->seed; } void ui_game_end(struct game_s *g) { for (int i = 0; i < NEBULA_MAX; ++i) { if (ui_data.gfx.starmap.nebula[i]) { lbxfile_item_release(LBXFILE_STARMAP, ui_data.gfx.starmap.nebula[i]); ui_data.gfx.starmap.nebula[i] = NULL; ui_data.gfx.starmap.smnebula[i] = NULL; } } lbxfile_item_release(LBXFILE_V11, ui_data.gfx.starmap.bmap); ui_data.gfx.starmap.bmap = NULL; } 1oom-1.11.2/src/ui/classic/uigameopts.c000066400000000000000000000102451476061725400176330ustar00rootroot00000000000000#include "config.h" #include "uigameopts.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "options.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiload.h" #include "uiobj.h" #include "uipal.h" #include "uisave.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct gameopts_data_s { int selected; uint8_t *gfx_game; uint8_t *gfx_save; uint8_t *gfx_load; uint8_t *gfx_quit; uint8_t *gfx_silent; uint8_t *gfx_fx; uint8_t *gfx_music; }; static void load_go_data(struct gameopts_data_s *d) { d->gfx_game = lbxfile_item_get(LBXFILE_VORTEX, 0x1c); d->gfx_save = lbxfile_item_get(LBXFILE_VORTEX, 0x1d); d->gfx_load = lbxfile_item_get(LBXFILE_VORTEX, 0x1e); d->gfx_quit = lbxfile_item_get(LBXFILE_VORTEX, 0x1f); d->gfx_silent = lbxfile_item_get(LBXFILE_VORTEX, 0x20); d->gfx_fx = lbxfile_item_get(LBXFILE_VORTEX, 0x21); d->gfx_music = lbxfile_item_get(LBXFILE_VORTEX, 0x22); } static void free_go_data(struct gameopts_data_s *d) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_game); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_save); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_load); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_quit); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_silent); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_fx); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_music); } static void gameopts_draw_cb(void *vptr) { struct gameopts_data_s *d = vptr; ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, d->gfx_game, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ gameopts_act_t ui_gameopts(struct game_s *g, int *load_game_i_ptr) { struct gameopts_data_s d; bool flag_done = false; gameopts_act_t ret = GAMEOPTS_DONE; int16_t oi_quit, oi_done, oi_load, oi_save, oi_silent, oi_fx, oi_music; int16_t fxmusic = opt_music_enabled ? 2 : (opt_sfx_enabled ? 1 : 0); load_go_data(&d); ui_palette_fadeout_19_19_1(); lbxpal_select(2, -1, 0); ui_draw_finish_mode = 2; uiobj_table_clear(); oi_load = uiobj_add_t0(115, 81, "", d.gfx_load, MOO_KEY_l); oi_save = uiobj_add_t0(115, 56, "", d.gfx_save, MOO_KEY_s); oi_quit = uiobj_add_t0(115, 106, "", d.gfx_quit, MOO_KEY_q); oi_silent = uiobj_add_t3(210, 56, "", d.gfx_silent, &fxmusic, 0, MOO_KEY_i); oi_fx = uiobj_add_t3(210, 81, "", d.gfx_fx, &fxmusic, 1, MOO_KEY_f); oi_music = uiobj_add_t3(210, 106, "", d.gfx_music, &fxmusic, 2, MOO_KEY_m); oi_done = uiobj_add_mousearea(173, 134, 226, 150, MOO_KEY_SPACE); uiobj_set_downcount(1); uiobj_set_callback_and_delay(gameopts_draw_cb, &d, 2); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == UIOBJI_ESC) || (oi == oi_done)) { ui_sound_play_sfx_24(); flag_done = true; } else if ((oi == oi_silent) || (oi == oi_fx) || (oi == oi_music)) { opt_music_enabled = (fxmusic == 2); opt_sfx_enabled = (fxmusic >= 1); ui_sound_play_sfx_24(); } else if (oi == oi_load) { int loadi; ui_sound_play_sfx_24(); loadi = ui_load_game(); if (loadi >= 0) { *load_game_i_ptr = loadi; ret = GAMEOPTS_LOAD; } flag_done = true; } else if (oi == oi_save) { ui_sound_play_sfx_24(); ui_save_game(g); flag_done = true; } else if (oi == oi_quit) { ret = GAMEOPTS_QUIT; ui_sound_play_sfx_24(); flag_done = true; } if (!flag_done) { gameopts_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(2); } } if (ret != GAMEOPTS_QUIT) { ui_palette_fadeout_a_f_1(); lbxpal_select(0, -1, 0); } ui_draw_finish_mode = 2; uiobj_unset_callback(); free_go_data(&d); return ret; } 1oom-1.11.2/src/ui/classic/uigameopts.h000066400000000000000000000003721476061725400176400ustar00rootroot00000000000000#ifndef INC_1OOM_UIGAMEOPTS_H #define INC_1OOM_UIGAMEOPTS_H struct game_s; typedef enum { GAMEOPTS_DONE, GAMEOPTS_QUIT, GAMEOPTS_LOAD } gameopts_act_t; extern gameopts_act_t ui_gameopts(struct game_s *g, int *load_game_i_ptr); #endif 1oom-1.11.2/src/ui/classic/uigmap.c000066400000000000000000000574361476061725400167550ustar00rootroot00000000000000#include "config.h" #include #include "uigmap.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "mouse.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uistarmap.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ #define GMAP_LIMITS 7, 7, 230, 191 #define GMAP_SCALED_LIMITS 7 * ui_scale, 7 * ui_scale, 230 * ui_scale, 191 * ui_scale struct gmap_blink_data_s { struct game_s *g; uint8_t planet_i; int countdown; }; struct gmap_data_s { const struct game_s *g; struct gmap_blink_data_s b; player_id_t api; int16_t mode; uint8_t *gfx_mapview; uint8_t *gfx_but_col; uint8_t *gfx_but_env; uint8_t *gfx_but_min; uint8_t *gfx_but_ok; }; struct gmap_basic_data_s { struct game_s *g; struct gmap_blink_data_s b; bool show_switch; }; static void gmap_load_data(struct gmap_data_s *d) { d->gfx_mapview = lbxfile_item_get(LBXFILE_STARMAP, 0x30); d->gfx_but_col = lbxfile_item_get(LBXFILE_STARMAP, 0x31); d->gfx_but_env = lbxfile_item_get(LBXFILE_STARMAP, 0x32); d->gfx_but_min = lbxfile_item_get(LBXFILE_STARMAP, 0x33); d->gfx_but_ok = lbxfile_item_get(LBXFILE_STARMAP, 0x34); } static void gmap_free_data(struct gmap_data_s *d) { lbxfile_item_release(LBXFILE_STARMAP, d->gfx_mapview); lbxfile_item_release(LBXFILE_STARMAP, d->gfx_but_col); lbxfile_item_release(LBXFILE_STARMAP, d->gfx_but_env); lbxfile_item_release(LBXFILE_STARMAP, d->gfx_but_min); lbxfile_item_release(LBXFILE_STARMAP, d->gfx_but_ok); } static void gmap_blink_step(struct gmap_blink_data_s *b) { if (b->countdown < 0) { struct game_s *g = b->g; b->planet_i = rnd_0_nm1(g->galaxy_stars, &ui_data.seed); b->countdown = 3; } else { --b->countdown; } } static void gmap_draw_cb(void *vptr) { struct gmap_data_s *d = vptr; const struct game_s *g = d->g; player_id_t tbl_races[PLAYER_NUM]; int racesnum = 1; tbl_races[0] = d->api; for (player_id_t i = PLAYER_0; i < g->players; ++i) { if ((i != d->api) && IS_ALIVE(g, i)) { tbl_races[racesnum++] = i; } } uiobj_set_limits(GMAP_LIMITS); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, ui_data.gfx.starmap.sky, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx_mapview, UI_SCREEN_W, ui_scale); for (int i = 0; i < g->nebula_num; ++i) { int x, y; x = (g->nebula_x[i] * 224) / g->galaxy_maxx + 7; y = (g->nebula_y[i] * 185) / g->galaxy_maxy + 7; lbxgfx_draw_frame_offs(x, y, ui_data.gfx.starmap.smnebula[i], GMAP_LIMITS, UI_SCREEN_W, ui_scale); } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (BOOLVEC_IS1(r->visible, d->api)) { uint8_t *gfx; int x, y; x = (r->x * 224) / g->galaxy_maxx + 7; y = (r->y * 185) / g->galaxy_maxy + 7; gfx = ui_data.gfx.starmap.tinyship[g->eto[r->owner].banner]; lbxgfx_draw_frame_offs(x, y, gfx, GMAP_LIMITS, UI_SCREEN_W, ui_scale); } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (BOOLVEC_IS1(r->visible, d->api)) { uint8_t *gfx; int x, y; x = (r->x * 224) / g->galaxy_maxx + 7; y = (r->y * 185) / g->galaxy_maxy + 7; gfx = ui_data.gfx.starmap.tinytran[g->eto[r->owner].banner]; lbxgfx_draw_frame_offs(x, y, gfx, GMAP_LIMITS, UI_SCREEN_W, ui_scale); } } if (ui_extra_enabled) { char buf[32]; lib_sprintf(buf, sizeof(buf), "Year %i", g->year+2299); lbxfont_select(0, 6, 0, 0); lbxfont_set_color_c_n(0, 5); lbxfont_print_str_normal(9, 9, buf, UI_SCREEN_W, ui_scale); lbxfont_set_color_c_n(194, 5); lbxfont_print_str_normal(8, 8, buf, UI_SCREEN_W, ui_scale); } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (BOOLVEC_IS1(p->within_srange, d->api)) { player_id_t tbl_have_orbit_owner[PLAYER_NUM]; int have_orbit_num; have_orbit_num = 0; for (player_id_t j = PLAYER_0; j < g->players; ++j) { const fleet_orbit_t *r = &(g->eto[j].orbit[i]); for (int k = 0; k < g->eto[j].shipdesigns_num; ++k) { if (r->ships[k] != 0) { tbl_have_orbit_owner[have_orbit_num++] = j; break; } } } for (int j = 0; j < have_orbit_num; ++j) { uint8_t *gfx; int x, y; /* FIXME all drawn to same position? */ x = (p->x * 224) / g->galaxy_maxx + 14; y = (p->y * 185) / g->galaxy_maxy + 8; gfx = ui_data.gfx.starmap.tinyship[g->eto[tbl_have_orbit_owner[j]].banner]; lbxgfx_draw_frame_offs(x, y, gfx, GMAP_LIMITS, UI_SCREEN_W, ui_scale); } } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); uint8_t *gfx; int x, y; x = (p->x * 224) / g->galaxy_maxx + 7; y = (p->y * 185) / g->galaxy_maxy + 7; if (BOOLVEC_IS1(p->explored, d->api) || (d->mode == 0)) { gfx = ui_data.gfx.starmap.smstars[p->star_type]; if ((d->b.planet_i == i) && (d->b.countdown > 0)) { lbxgfx_set_new_frame(gfx, d->b.countdown); } else { lbxgfx_set_frame_0(gfx); } lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); } else { gfx = ui_data.gfx.starmap.smallstr; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x + 1, y + 1, gfx, UI_SCREEN_W, ui_scale); } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); uint8_t *gfx; player_id_t owner; int x, y; x = (p->x * 224) / g->galaxy_maxx + 7; y = (p->y * 185) / g->galaxy_maxy + 7; owner = (BOOLVEC_IS1(p->within_srange, d->api)) ? p->owner : g->seen[d->api][i].owner; if (owner != PLAYER_NONE) { gfx = ui_data.gfx.starmap.smalflag[g->eto[owner].banner]; lbxgfx_draw_frame(x + 2, y - 3, gfx, UI_SCREEN_W, ui_scale); } switch (d->mode) { case 1: if (BOOLVEC_IS1(p->explored, d->api)) { char buf[2] = { 0, 0 }; int pt; lbxfont_select_set_12_1(2, (p->type < g->eto[PLAYER_0].have_colony_for) ? 5 : 0xe, 0, 0); pt = (PLANET_TYPE_TERRAN - p->type); SETMAX(pt, 0); buf[0] = game_str_gm_tchar[pt]; lbxfont_print_str_normal_limit(x + 7, y, buf, GMAP_SCALED_LIMITS, UI_SCREEN_W, ui_scale); } break; case 2: if (BOOLVEC_IS1(p->explored, d->api) && (p->special != PLANET_SPECIAL_NORMAL)) { if (p->special > PLANET_SPECIAL_ARTIFACTS) { lbxfont_select(2, 1, 0, 0); } else { lbxfont_select_set_12_1(2, (p->special != PLANET_SPECIAL_ARTIFACTS) ? 5 : 0xe, 0, 0); } if (p->special == PLANET_SPECIAL_4XTECH) { lbxfont_select(2, 0xe, 0, 0); } lbxfont_print_str_center_limit(x + 2, y + 7, game_str_tbl_gm_spec[p->special], GMAP_SCALED_LIMITS, UI_SCREEN_W, ui_scale); } break; default: break; } } switch (d->mode) { case 0: lbxfont_select(0, 6, 0, 0); for (int i = 0; i < racesnum; ++i) { const empiretechorbit_t *e; e = &(g->eto[tbl_races[i]]); lbxgfx_draw_frame(245, 105 + 10 * i, ui_data.gfx.starmap.smalflag[e->banner], UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(260, 105 + 10 * i, game_str_tbl_race[e->race], UI_SCREEN_W, ui_scale); } break; case 1: for (int i = 0; i < 7; ++i) { char buf[2] = { 0, 0 }; buf[0] = game_str_gm_tchar[i]; lbxfont_select(2, ((PLANET_TYPE_TERRAN - i) < g->eto[d->api].have_colony_for) ? 5 : 0xe, 0, 0); lbxfont_print_str_normal(241, 105 + 7 * i, buf, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_normal(247, 105 + 7 * i, game_str_tbl_sm_pltype[13 - i], UI_SCREEN_W, ui_scale); } for (int i = 7; i < 14; ++i) { char buf[2] = { 0, 0 }; const char *str; buf[0] = game_str_gm_tchar[i]; lbxfont_select(2, ((PLANET_TYPE_TERRAN - i) < g->eto[d->api].have_colony_for) ? 5 : 0xe, 0, 0); lbxfont_print_str_normal(276, 105 + 7 * (i - 7), buf, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); if (i == 13) { str = game_str_st_none2; } else { str = game_str_tbl_sm_pltype[13 - i]; } lbxfont_print_str_normal(282, 105 + 7 * (i - 7), str, UI_SCREEN_W, ui_scale); } lbxfont_print_str_normal(247, 160, game_str_gm_unable, UI_SCREEN_W, ui_scale); ui_draw_pixel(241, 161, 0x44, ui_scale); ui_draw_pixel(241, 162, 0x44, ui_scale); ui_draw_pixel(241, 163, 0x44, ui_scale); ui_draw_pixel(242, 161, 0x44, ui_scale); ui_draw_pixel(242, 162, 0x44, ui_scale); ui_draw_pixel(242, 163, 0x44, ui_scale); ui_draw_pixel(243, 161, 0x44, ui_scale); ui_draw_pixel(243, 162, 0x44, ui_scale); ui_draw_pixel(243, 163, 0x44, ui_scale); break; case 2: lbxfont_select_set_12_1(2, 5, 0, 0); lbxfont_print_str_normal(240, 103, game_str_tbl_sm_pspecial[0], UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(240, 111, game_str_tbl_sm_pspecial[1], UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(2, 1, 0, 0); lbxfont_print_str_normal(240, 119, game_str_tbl_sm_pspecial[4], UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(240, 127, game_str_tbl_sm_pspecial[5], UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(2, 0xe, 0, 0); lbxfont_print_str_normal(240, 135, game_str_tbl_sm_pspecial[3], UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(240, 143, game_str_tbl_gm_spec[6], UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_normal(295, 103, game_str_gm_prod, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 111, game_str_gm_prod, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 119, game_str_gm_prod, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 127, game_str_gm_prod, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 135, game_str_gm_tech, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 143, game_str_gm_tech, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 103, game_str_gm_1_3, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 111, game_str_gm_1_2, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 119, game_str_gm_2x, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 127, game_str_gm_3x, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 135, game_str_gm_2x, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(291, 143, game_str_gm_4x, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(275, 152, game_str_gm_prodb1, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(275, 159, game_str_gm_prodb2, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(275, 166, game_str_gm_prodb3, UI_SCREEN_W, ui_scale); break; default: break; } lbxfont_set_temp_color(0x2b); lbxfont_select_set_12_4(4, 0xf, 0, 0); lbxfont_print_str_normal(242, 8, game_str_gm_gmap, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(250, 88, game_str_gm_mapkey, UI_SCREEN_W, ui_scale); lbxfont_set_temp_color(0x00); gmap_blink_step(&(d->b)); if (ui_scale > 1) { const uint8_t ctblf[5] = { 0xbd, 0xbc, 0xbb, 0xba, 0xb9 }; const uint8_t ctblb[5] = { 0xba, 0xbb, 0xbc, 0xbd, 0xb9 }; int x0, y0, x1, y1, pos; x0 = (ui_data.starmap.x * 224) / g->galaxy_maxx + 7; SETMAX(x0, 7); y0 = (ui_data.starmap.y * 185) / g->galaxy_maxy + 7; SETMAX(y0, 7); x1 = ((ui_data.starmap.x + ((108 * ui_scale) / starmap_scale)) * 224) / g->galaxy_maxx + 7; SETMIN(x1, 230); y1 = ((ui_data.starmap.y + ((86 * ui_scale) / starmap_scale)) * 185) / g->galaxy_maxy + 7; SETMIN(y1, 192); pos = d->b.countdown + 1; ui_draw_line_ctbl(x0, y0, x0 + 4, y0, ctblf, 5, pos, ui_scale); ui_draw_line_ctbl(x0, y0, x0, y0 + 4, ctblf, 5, pos, ui_scale); ui_draw_line_ctbl(x1 - 1, y0, x1 - 4, y0, ctblb, 5, 4 - pos, ui_scale); ui_draw_line_ctbl(x1, y0, x1, y0 + 4, ctblf, 5, pos, ui_scale); ui_draw_line_ctbl(x0, y1, x0 + 4, y1, ctblf, 5, pos, ui_scale); ui_draw_line_ctbl(x0, y1, x0, y1 - 4, ctblf, 5, pos, ui_scale); ui_draw_line_ctbl(x1 - 1, y1, x1 - 4, y1, ctblb, 5, 4 - pos, ui_scale); ui_draw_line_ctbl(x1, y1, x1, y1 - 4, ctblf, 5, pos, ui_scale); } else { int x, y; x = (ui_data.starmap.x * 224) / g->galaxy_maxx + 7; y = (ui_data.starmap.y * 185) / g->galaxy_maxy + 7; if (ui_sm_expanded_scroll) { lbxgfx_draw_frame_offs(x, y, ui_data.gfx.starmap.bmap, GMAP_LIMITS, UI_SCREEN_W, ui_scale); } else { lbxgfx_draw_frame(x, y, ui_data.gfx.starmap.bmap, UI_SCREEN_W, ui_scale); } } } static void ui_gmap_basic_draw_galaxy(struct gmap_basic_data_s *d) { const struct game_s *g = d->g; ui_draw_filled_rect(6, 6, 221, 177, 0, ui_scale); /*uiobj_set_limits(6, 6, 221, 177);*/ lbxgfx_draw_frame_offs(0, 0, ui_data.gfx.starmap.sky, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); for (int i = 0; i < g->nebula_num; ++i) { int x, y; x = (g->nebula_x[i] * 215) / g->galaxy_maxx + 6; y = (g->nebula_y[i] * 171) / g->galaxy_maxy + 6; lbxgfx_draw_frame_offs(x, y, ui_data.gfx.starmap.smnebula[i], 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); uint8_t *gfx; int x, y; x = (p->x * 215) / g->galaxy_maxx + 6; y = (p->y * 171) / g->galaxy_maxy + 6; gfx = ui_data.gfx.starmap.smstars[p->star_type]; if ((d->b.planet_i == i) && (d->b.countdown > 0)) { lbxgfx_set_new_frame(gfx, d->b.countdown); } else { lbxgfx_set_frame_0(gfx); } lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ bool ui_gmap(struct game_s *g, player_id_t active_player) { struct gmap_data_s d; bool flag_done = false, flag_do_focus = false; int16_t /*oi_col, oi_env, oi_min,*/ oi_ok, oi_tbl_planet[PLANETS_MAX]; int16_t oi_map = UIOBJI_INVALID; gmap_load_data(&d); d.g = g; d.api = active_player; d.mode = 0; d.b.g = g; d.b.countdown = -1; d.b.planet_i = 0; uiobj_table_clear(); oi_ok = uiobj_add_t0(246, 181, "", d.gfx_but_ok, MOO_KEY_SPACE); /*oi_col =*/ uiobj_add_t3(246, 27, "", d.gfx_but_col, &(d.mode), 0, MOO_KEY_c); /*oi_env =*/ uiobj_add_t3(246, 47, "", d.gfx_but_env, &(d.mode), 1, MOO_KEY_e); /*oi_min =*/ uiobj_add_t3(246, 67, "", d.gfx_but_min, &(d.mode), 2, MOO_KEY_m); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); int x, y; x = (p->x * 224) / g->galaxy_maxx + 7; y = (p->y * 185) / g->galaxy_maxy + 7; /* FIXME limits not set! ... but no need to limit anyway */ oi_tbl_planet[i] = uiobj_add_mousearea/*_limited*/(x, y, x + 4, y + 4, MOO_KEY_UNKNOWN); } if (ui_extra_enabled) { oi_map = uiobj_add_mousearea(GMAP_LIMITS, MOO_KEY_UNKNOWN); } uiobj_set_help_id(9); uiobj_set_callback_and_delay(gmap_draw_cb, &d, 4); uiobj_set_downcount(1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ok) || (oi == UIOBJI_ESC)) { flag_done = true; } if (oi != 0) { ui_sound_play_sfx_24(); } for (int i = 0; i < g->galaxy_stars; ++i) { if (oi == oi_tbl_planet[i]) { g->planet_focus_i[active_player] = i; flag_do_focus = true; flag_done = true; break; } } if (ui_extra_enabled && (oi == oi_map)) { int x, y; x = ((moouse_x / ui_scale - 7) * g->galaxy_maxx) / 224; y = ((moouse_y / ui_scale - 7) * g->galaxy_maxy) / 185; ui_starmap_set_pos(g, x, y); flag_done = true; } if (!flag_done) { gmap_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } } uiobj_unset_callback(); uiobj_set_help_id(-1); gmap_free_data(&d); return flag_do_focus; } void *ui_gmap_basic_init(struct game_s *g, bool show_player_switch) { static struct gmap_basic_data_s ctx; /* HACK */ ctx.g = g; ctx.b.g = g; ctx.b.countdown = -1; ctx.b.planet_i = 0; ctx.show_switch = show_player_switch; if (!show_player_switch) { ui_draw_copy_buf(); ui_starmap_draw_button_text(0/*unused*/, false); hw_video_copy_back_to_page2(); } return &ctx; } void ui_gmap_basic_shutdown(void *ctx) { } void ui_gmap_basic_start_player(void *ctx, int pi) { struct gmap_basic_data_s *d = ctx; if (d->show_switch) { ui_switch_1(d->g, pi); ui_draw_copy_buf(); hw_video_copy_back_to_page2(); } } void ui_gmap_basic_start_frame(void *ctx, int pi) { /*struct gmap_basic_data_s *d = ctx;*/ ui_delay_prepare(); hw_video_copy_back_from_page2(); } void ui_gmap_basic_draw_frame(void *ctx, int pi/*player_i*/) { struct gmap_basic_data_s *d = ctx; const struct game_s *g = d->g; ui_gmap_basic_draw_galaxy(d); if (pi >= 0) { for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (BOOLVEC_IS1(r->visible, pi)) { uint8_t *gfx; int x, y; x = (r->x * 215) / g->galaxy_maxx + 6; y = (r->y * 171) / g->galaxy_maxy + 6; gfx = ui_data.gfx.starmap.tinyship[g->eto[r->owner].banner]; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (BOOLVEC_IS1(r->visible, pi)) { uint8_t *gfx; int x, y; x = (r->x * 215) / g->galaxy_maxx + 6; y = (r->y * 171) / g->galaxy_maxy + 6; gfx = ui_data.gfx.starmap.tinytran[g->eto[r->owner].banner]; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (BOOLVEC_IS1(p->within_srange, pi)) { player_id_t tbl_have_orbit_owner[PLAYER_NUM]; int have_orbit_num; have_orbit_num = 0; for (player_id_t j = PLAYER_0; j < g->players; ++j) { const fleet_orbit_t *r = &(g->eto[j].orbit[i]); for (int k = 0; k < g->eto[j].shipdesigns_num; ++k) { if (r->ships[k] != 0) { tbl_have_orbit_owner[have_orbit_num++] = j; break; } } } for (int j = 0; j < have_orbit_num; ++j) { uint8_t *gfx; int x, y; /* FIXME all drawn to same position? */ x = (p->x * 215) / g->galaxy_maxx + 13; y = (p->y * 171) / g->galaxy_maxy + 7; gfx = ui_data.gfx.starmap.tinyship[g->eto[tbl_have_orbit_owner[j]].banner]; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } } } for (int i = 0; i < 2; ++i) { const monster_t *r; r = (i == 0) ? &(g->evn.crystal) : &(g->evn.amoeba); if (r->exists && (r->killer == PLAYER_NONE)) { uint8_t *gfx; int x, y; x = (r->x * 215) / g->galaxy_maxx + 6; y = (r->y * 171) / g->galaxy_maxy + 6; gfx = ui_data.gfx.planets.tmonster; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } } } gmap_blink_step(&(d->b)); } void ui_gmap_basic_draw_only(void *ctx, int pi/*planet_i*/) { struct gmap_basic_data_s *d = ctx; const struct game_s *g = d->g; ui_gmap_basic_draw_galaxy(d); { const planet_t *p = &(g->planet[pi]); player_id_t tbl_have_orbit_owner[PLAYER_NUM]; int have_orbit_num; have_orbit_num = 0; for (player_id_t j = PLAYER_0; j < g->players; ++j) { const fleet_orbit_t *r = &(g->eto[j].orbit[pi]); for (int k = 0; k < g->eto[j].shipdesigns_num; ++k) { if (r->ships[k] != 0) { tbl_have_orbit_owner[have_orbit_num++] = j; break; } } } for (int j = 0; j < have_orbit_num; ++j) { uint8_t *gfx; int x, y; /* FIXME all drawn to same position? */ x = (p->x * 215) / g->galaxy_maxx + 13; y = (p->y * 171) / g->galaxy_maxy + 7; gfx = ui_data.gfx.starmap.tinyship[g->eto[tbl_have_orbit_owner[j]].banner]; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } for (int i = 0; i < 2; ++i) { const monster_t *r; r = (i == 0) ? &(g->evn.crystal) : &(g->evn.amoeba); if (r->exists && (r->killer == PLAYER_NONE) && (r->x == p->x) && (r->y == p->y)) { uint8_t *gfx; int x, y; x = (r->x * 215) / g->galaxy_maxx + 6; y = (r->y * 171) / g->galaxy_maxy + 6; gfx = ui_data.gfx.planets.tmonster; lbxgfx_draw_frame_offs(x, y, gfx, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } } } gmap_blink_step(&(d->b)); } void ui_gmap_basic_finish_frame(void *ctx, int pi) { /*struct gmap_basic_data_s *d = ctx;*/ ui_draw_finish(); ui_delay_ticks_or_click(2); } void ui_gmap_draw_planet_border(const struct game_s *g, uint8_t planet_i) { const planet_t *p = &(g->planet[planet_i]); int x, y; x = (p->x * 215) / g->galaxy_maxx + 5; y = (p->y * 171) / g->galaxy_maxy + 5; lbxgfx_draw_frame_offs(x, y, ui_data.gfx.starmap.slanbord, 6, 6, 221, 177, UI_SCREEN_W, ui_scale); } 1oom-1.11.2/src/ui/classic/uigmap.h000066400000000000000000000004721476061725400167460ustar00rootroot00000000000000#ifndef INC_1OOM_UIGMAP_H #define INC_1OOM_UIGMAP_H #include "game_types.h" #include "types.h" struct game_s; extern bool ui_gmap(struct game_s *g, player_id_t pi); extern void ui_gmap_basic_draw_only(void *ctx, int pi); extern void ui_gmap_draw_planet_border(const struct game_s *g, uint8_t planet_i); #endif 1oom-1.11.2/src/ui/classic/uiground.c000066400000000000000000000253641476061725400173220ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_ground.h" #include "game_spy.h" #include "game_str.h" #include "game_tech.h" #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uilanding.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" #include "util.h" /* -------------------------------------------------------------------------- */ struct ground_data_s { const struct game_s *g; const struct ground_s *gr; struct landing_data_s l; uint8_t *gfx_s[2]; uint8_t *gfx_death; bool flag_over; }; static void ground_prepare(struct ground_data_s *d) { const struct game_s *g = d->g; hw_video_copy_back_from_page3(); lbxgfx_set_new_frame(d->l.gfx_transprt, 39); gfx_aux_draw_frame_to(d->l.gfx_transprt, &ui_data.aux.screen); gfx_aux_draw_frame_from_limit(0, 100, &ui_data.aux.screen, 0, 0, UI_SCREEN_W - 1, UI_SCREEN_H - 1, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page3(); ui_delay_1(); ui_sound_stop_music(); for (int i = 0; i < 2; ++i) { d->gfx_s[i] = lbxfile_item_get(LBXFILE_LANDING, 0x1b + g->eto[d->gr->s[i].player].race); } d->gfx_death = lbxfile_item_get(LBXFILE_LANDING, 0x14); } static void ground_free_data(struct ground_data_s *d) { ui_landing_free_data(&d->l); lbxfile_item_release(LBXFILE_LANDING, d->gfx_s[0]); lbxfile_item_release(LBXFILE_LANDING, d->gfx_s[1]); lbxfile_item_release(LBXFILE_LANDING, d->gfx_death); } static void ground_draw_item(int popi, int popnum, uint8_t *gfx, bool is_right, int xoff) { int x, y, totalrows, x0, y0, col, row; totalrows = (popnum / 15) + ((popnum % 15) != 0); x0 = 10 - xoff; y0 = 120 - (totalrows * 6); row = popi / 15; col = popi % 15; x = x0 + (col * 8) + (row & 1) * 4; y = y0 + (col & 1) * 2 + (row & 1) * 6 + (row / 2) * 12; gfx_aux_draw_frame_to(gfx, &ui_data.aux.btemp); if (is_right) { gfx_aux_flipx(&ui_data.aux.btemp); x = 295 - x - xoff; } gfx_aux_draw_frame_from(x, y, &ui_data.aux.btemp, UI_SCREEN_W, ui_scale); } static void ground_draw_cb1(void *vptr) { struct ground_data_s *d = vptr; const struct game_s *g = d->g; const struct ground_s *gr = d->gr; const char *strrace[2]; char buf[0x80]; for (int i = 0; i < 2; ++i) { strrace[i] = game_str_tbl_race[g->eto[gr->s[i].player].race]; } hw_video_copy_back_from_page3(); if (d->l.frame < 50) { int y; y = d->l.frame * 4 - 100; gfx_aux_draw_frame_to(d->l.gfx_transprt, &ui_data.aux.screen); gfx_aux_draw_frame_from_limit(0, y, &ui_data.aux.screen, 0, 0, UI_SCREEN_W - 1, UI_SCREEN_H - 1, UI_SCREEN_W, ui_scale); if (!gr->flag_rebel) { lib_sprintf(buf, sizeof(buf), "%i %s %i %s %s", gr->inbound, game_str_gr_outof, gr->total_inbound, strrace[gr->flag_swap ? 1 : 0], game_str_gr_transs); } else { /*7b9a8*/ lib_sprintf(buf, sizeof(buf), "%i %s", gr->inbound, game_str_gr_reclaim); } /*7b9bf*/ lbxfont_select_set_12_4(4, 0x5, 0, 0); lbxfont_print_str_center(160, 5, buf, UI_SCREEN_W, ui_scale); if (!gr->flag_rebel) { lib_sprintf(buf, sizeof(buf), "%s %s %s", game_str_gr_penetr, strrace[gr->flag_swap ? 0 : 1], game_str_gr_defenss); lbxfont_print_str_center(160, 17, buf, UI_SCREEN_W, ui_scale); } } else { /*7ba55*/ lbxfont_select_set_12_4(4, 0x5, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %s", strrace[1], game_str_gr_troops); lbxfont_print_str_normal(30, 146, buf, UI_SCREEN_W, ui_scale); lbxfont_print_num_normal(10, 146, gr->s[1].pop1, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(164, 155, 281, 157, 0, ui_scale); ui_draw_line1(165, 156, 280, 156, 4, ui_scale); lbxfont_select_set_12_4(0, 0x1, 0, 0); for (int i = 0; i < gr->s[1].strnum; ++i) { lbxfont_print_str_normal(10, 160 + 10 * i, gr->s[1].str[i], UI_SCREEN_W, ui_scale); } for (int i = 0; i < gr->s[1].pop1; ++i) { ground_draw_item(i, gr->s[1].pop2, d->gfx_s[1], false, 0); } lbxfont_select_set_12_4(4, 0x5, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %s", gr->flag_rebel ? game_str_gr_rebel : strrace[0], game_str_gr_troops); lbxfont_print_str_normal(190, 146, buf, UI_SCREEN_W, ui_scale); lbxfont_print_num_normal(170, 146, gr->s[0].pop1, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(4, 155, 121, 157, 0, ui_scale); ui_draw_line1(5, 156, 120, 156, 4, ui_scale); lbxfont_select_set_12_4(0, 0x1, 0, 0); for (int i = 0; i < gr->s[0].strnum; ++i) { lbxfont_print_str_normal(170, 160 + 10 * i, gr->s[0].str[i], UI_SCREEN_W, ui_scale); } for (int i = 0; i < gr->s[0].pop1; ++i) { ground_draw_item(i, gr->s[0].pop2, d->gfx_s[0], true, 0); } lbxfont_select_set_12_4(4, 0x5, 0, 0); if ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { lib_sprintf(buf, sizeof(buf), "%s %s", game_str_gr_gcon, g->planet[gr->planet_i].name); lbxfont_print_str_center(160, 5, buf, UI_SCREEN_W, ui_scale); } else if (d->flag_over) { /*7bccd*/ int pop = gr->s[gr->flag_swap ? 1 : 0].pop1; struct strbuild_s strbuild = strbuild_init(buf, sizeof(buf)); if (pop != 0) { if (!gr->flag_swap) { strbuild_catf(&strbuild, "%s%s ", strrace[0], game_str_gr_scapt); } else { if (gr->flag_rebel) { strbuild_catf(&strbuild, "%s ", game_str_gr_itroops); } else { strbuild_catf(&strbuild, "%s%s ", strrace[1], game_str_gr_scapt); } } } else { /*7bd5d*/ const char *s; if (!gr->flag_swap) { s = strrace[1]; } else { if (gr->flag_rebel) { s = game_str_gr_rebel; } else { s = strrace[0]; } } /*7bdb1*/ strbuild_catf(&strbuild, "%s%s ", s, game_str_gr_succd); } /*7bdc0*/ strbuild_catf(&strbuild, "%s", g->planet[gr->planet_i].name); lbxfont_print_str_center(160, 5, buf, UI_SCREEN_W, ui_scale); if ((pop > 0) && (!gr->flag_rebel)) { /*7be16*/ if (gr->fact > 0) { lib_sprintf(buf, sizeof(buf), "%i %s", gr->fact, game_str_gr_fcapt); lbxfont_print_str_center(160, 25, buf, UI_SCREEN_W, ui_scale); } /*7be54*/ if (gr->techchance > 0) { if (gr->flag_swap == gr->s[0].human) { lbxfont_print_str_center(160, 40, game_str_gr_tsteal, UI_SCREEN_W, ui_scale); for (int i = 0; i < gr->techchance; ++i) { game_tech_get_name(g->gaux, gr->got[i].field, gr->got[i].tech, buf, sizeof(buf)); lbxfont_print_str_center(160, 60 + 15 * i, buf, UI_SCREEN_W, ui_scale); } } else { lbxfont_print_str_center(160, 38, game_str_gr_tnew, UI_SCREEN_W, ui_scale); } } } } /*7bf47*/ if ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0) && (gr->death != -1)) { int side = gr->death; ground_draw_item(gr->s[side].pop1, gr->s[side].pop2, d->gfx_death, side == 0, 5); } } if (++d->l.frame == (60 + 100)) { d->l.frame = 61; } } /* -------------------------------------------------------------------------- */ void ui_ground(struct game_s *g, struct ground_s *gr) { struct ground_data_s d; bool flag_done = false; int downcount = 4; ui_switch_2(g, gr->s[0].player, gr->s[1].player); memset(&d, 0, sizeof(d)); d.g = g; d.gr = gr; d.l.g = g; d.l.api = PLAYER_0; /* for gfx_walk banner which is unused here */ d.l.planet = gr->planet_i; d.l.colonize = false; d.flag_over = false; if (ui_draw_finish_mode != 2) { ui_palette_fadeout_a_f_1(); } lbxpal_select(6, -1, 0); ui_landing_prepare(&d.l); ui_sound_play_music(d.l.music_i); lbxpal_build_colortables(); ui_draw_finish_mode = 2; uiobj_set_callback_and_delay(ground_draw_cb1, &d, 2); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(3); while ((!flag_done) && (d.l.frame < 50)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { d.l.frame = 50; flag_done = true; } if (!flag_done) { ground_draw_cb1(&d); ui_draw_finish(); } ui_delay_ticks_or_click(2); } ground_prepare(&d); /*7b442*/ uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); ui_sound_play_music(0x26); flag_done = false; while ((!flag_done) && (gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { int16_t oi; if (d.l.frame < 60) { gr->death = -1; } else { game_ground_kill(gr); } ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { d.l.frame = 50; flag_done = true; } if (!flag_done) { if (--downcount == 0) { ui_sound_play_sfx(0x02); downcount = rnd_0_nm1(3, &ui_data.seed) + 2; } ground_draw_cb1(&d); ui_draw_finish(); } ui_delay_ticks_or_click(2); } while ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { game_ground_kill(gr); } ui_sound_play_music((gr->s[0].pop1 != 0) ? 0xc : 0xb); d.flag_over = true; flag_done = false; while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } if (!flag_done) { ground_draw_cb1(&d); ui_draw_finish(); } ui_delay_ticks_or_click(2); } ui_sound_stop_music(); ui_palette_fadeout_a_f_1(); lbxpal_select(0, -1, 0); lbxpal_build_colortables(); ui_draw_finish_mode = 2; uiobj_unset_callback(); uiobj_table_clear(); ground_free_data(&d); } 1oom-1.11.2/src/ui/classic/uihelp.c000066400000000000000000000176251476061725400167550ustar00rootroot00000000000000#include "config.h" #include #include "uihelp.h" #include "bits.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxpal.h" #include "log.h" #include "uidraw.h" #include "uidefs.h" #include "uiobj.h" /* -------------------------------------------------------------------------- */ #define DEBUGLEVEL_HELPUI 4 #define HELP_OFFS_10 0x10 #define HELP_OFFS_XTBL 0x2c #define HELP_OFFS_YTBL 0x44 #define HELP_OFFS_WTBL 0x5c #define HELP_OFFS_LXTBL 0x74 #define HELP_OFFS_LYTBL 0x8c #define HELP_OFFS_LTTBL 0xa4 #define HELP_OFFS_STR0 0xbc #define HELP_OFFS_STR1 0xe4 #define HELP_OFFS_STR2 0x21e #define HELP_OFFS_STR3 0x246 #define HELP_OFFS_STBL 0x380 #define HELP_OFFS_NEXT 0x5f6 #define HELP_ITEM_SIZE 0x5f8 #define HELP_STBL_SIZE 70 /* -------------------------------------------------------------------------- */ static void ui_help_draw(const char *str0, const char *str1, int x, int y, int w, int ltype, int lx1, int ly1, const uint8_t *ctbl, uint8_t c0, uint8_t c1, uint8_t c2, uint8_t c3, uint8_t c4, uint8_t c5, uint8_t c6, uint8_t colorpos) { int x1, y1; LOG_DEBUG((DEBUGLEVEL_HELPUI, "%s: cp:%i (%i,%i) w:%i lt:%i lx:%i ly:%i '%s' '%s'\n", __func__, colorpos, x, y, w, ltype, lx1, ly1, str0, str1)); if (str1[0] == '\0') { return; } x1 = x + w - 1; y1 = lbxfont_calc_split_str_h(w - 12, str1) + y + 11; if (str0[0] != '\0') { y1 += lbxfont_get_height() + 4; } ui_draw_box_fill(x, y, x1, y1, ctbl, 0, 5, 1, colorpos, ui_scale); if (ltype != 0) { if ((lx1 >= x) && (lx1 <= x1)) { int lx0, ly0; lx0 = (x + x1) / 2; ly0 = (ly1 < y) ? (y - 1) : (y1 + 1); ui_draw_line1(lx0, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(lx0, ly0, lx1, ly1 + 1, c6, ui_scale); } else { int lx0, ly0; ly0 = (y + y1) / 2; if (lx1 < x) { if (ltype == 1) { lx0 = x - 1; ui_draw_line1(lx0, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(lx0, ly0, lx1, ly1 + 1, c6, ui_scale); } else { int v; v = lx1 + abs(ly1 - ly0); if (v > x) { lx0 = x - 1; ui_draw_line1(lx0, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(lx0, ly0, lx1, ly1 + 1, c6, ui_scale); } else { ui_draw_line1(v, ly0 + 1, x - 1, ly0 + 1, 0, ui_scale); ui_draw_line1(lx1, ly1 + 1, v, ly0 + 1, 0, ui_scale); ui_draw_line1(v, ly0, x - 1, ly0, c6, ui_scale); ui_draw_line1(lx1, ly1, v, ly0, c6, ui_scale); } } } else { if (ltype == 1) { lx0 = x1 + 1; ui_draw_line1(lx0, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(lx0, ly0, lx1, ly1 + 1, c6, ui_scale); } else { int v; v = lx1 - abs(ly1 - ly0); if (v < x1) { lx0 = x1 + 1; ui_draw_line1(lx0, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(lx0, ly0, lx1, ly1 + 1, c6, ui_scale); } else { ui_draw_line1(x1 + 1, ly0 + 1, v, ly0 + 1, 0, ui_scale); ui_draw_line1(v, ly0 + 1, lx1, ly1 + 1, 0, ui_scale); ui_draw_line1(x1 + 1, ly0, v, ly0, c6, ui_scale); ui_draw_line1(v, ly0, lx1, ly1, c6, ui_scale); } } } } } /*2e3d4*/ ui_draw_box2(x, y, x1, y1, c0, c1, c2, c3, ui_scale); ui_draw_pixel(x, y, c4, ui_scale); ui_draw_pixel(x + 1, y + 1, c5, ui_scale); ui_draw_pixel(x + 2, y + 1, c5, ui_scale); ui_draw_pixel(x + 1, y + 2, c5, ui_scale); ui_draw_pixel(x + 1, y + 3, c5, ui_scale); ui_draw_line1(x + 1, y1 + 1, x1 + 1, y1 + 1, 0, ui_scale); ui_draw_line1(x1 + 1, y + 1, x1 + 1, y1, 0, ui_scale); if (str0[0] != '\0') { lbxfont_select_subcolors_13not1(); lbxfont_print_str_center(x + w / 2, y + 6, str0, UI_SCREEN_W, ui_scale); lbxfont_select_subcolors_0(); y += lbxfont_get_height() + 5; } /*2e4ff*/ lbxfont_print_str_split(x + 6, y + 6, w - 12, str1, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_help(int help_index) { uint8_t ctbl[5], c0, c1, c3, c4, c5, c8; uint8_t *helplbx; LOG_DEBUG((DEBUGLEVEL_HELPUI, "%s: %i\n", __func__, help_index)); if ((help_index < 0) || (!ui_data.have_help)) { return; } for (int i = 0; i < 5; ++i) { ctbl[i] = lbxpal_find_closest(i * 3 + 7, i * 3 + 7, i * 4 + 15); } c0 = lbxpal_find_closest(0x3f, 0x3f, 0x3f); c1 = lbxpal_find_closest(0x31, 0x31, 0x31); /*c2 = c0 = lbxpal_find_closest(0x3f, 0x3f, 0x3f);*/ c3 = lbxpal_find_closest(0x1d, 0x1d, 0x27); c4 = lbxpal_find_closest(0x27, 0x27, 0x2f); c5 = lbxpal_find_closest(0x19, 0x19, 0x23); /*c6 = c3 = lbxpal_find_closest(0x1d, 0x1d, 0x27);*/ /*c7 = c4 = lbxpal_find_closest(0x27, 0x27, 0x2f);*/ c8 = lbxpal_find_closest(0x2d, 0x2d, 0x33); uiobj_table_num_store(); hw_video_copy_buf(); hw_video_copy_back_to_page3(); helplbx = lbxfile_item_get(LBXFILE_HELP, 0); do { const uint8_t *p; uint8_t old_fontnum, old_fonta2; old_fontnum = lbxfont_get_current_fontnum(); old_fonta2 = lbxfont_get_current_fonta2(); /* old_vgabuf_seg = vgabuf_seg; */ lbxfont_select(0, 0, 0, 0); lbxfont_set_gap_h(3); lbxfont_set_14_24(c1, c0); p = &(helplbx[4 + HELP_ITEM_SIZE * help_index]); ui_help_draw((const char *)&p[HELP_OFFS_STR0], (const char *)&p[HELP_OFFS_STR1], GET_LE_16(&p[HELP_OFFS_XTBL]), GET_LE_16(&p[HELP_OFFS_YTBL]), GET_LE_16(&p[HELP_OFFS_WTBL]), GET_LE_16(&p[HELP_OFFS_LTTBL]), GET_LE_16(&p[HELP_OFFS_LXTBL]), GET_LE_16(&p[HELP_OFFS_LYTBL]), ctbl, c3, c4, c5, c3, c4, c8, c0, 1 ); if (GET_LE_16(&p[HELP_OFFS_10]) < 3) { for (int i = 0; i < 9; ++i) { ui_help_draw("", (const char *)&p[HELP_OFFS_STBL + i * HELP_STBL_SIZE], GET_LE_16(&p[HELP_OFFS_XTBL + i * 2 + 4]), GET_LE_16(&p[HELP_OFFS_YTBL + i * 2 + 4]), GET_LE_16(&p[HELP_OFFS_WTBL + i * 2 + 4]), GET_LE_16(&p[HELP_OFFS_LTTBL + i * 2 + 4]), GET_LE_16(&p[HELP_OFFS_LXTBL + i * 2 + 4]), GET_LE_16(&p[HELP_OFFS_LYTBL + i * 2 + 4]), ctbl, c3, c4, c5, c3, c4, c8, c0, (i + 10040) & 0xff ); } } else { ui_help_draw((const char *)&p[HELP_OFFS_STR2], (const char *)&p[HELP_OFFS_STR3], GET_LE_16(&p[HELP_OFFS_XTBL + 2]), GET_LE_16(&p[HELP_OFFS_YTBL + 2]), GET_LE_16(&p[HELP_OFFS_WTBL + 2]), GET_LE_16(&p[HELP_OFFS_LTTBL + 2]), GET_LE_16(&p[HELP_OFFS_LXTBL + 2]), GET_LE_16(&p[HELP_OFFS_LYTBL + 2]), ctbl, c3, c4, c5, c3, c4, c8, c0, 10040 & 0xff ); } lbxfont_select(old_fontnum, old_fonta2, 0, 0); /* vgabuf_seg = old_vgabuf_seg; */ uiobj_finish_frame(); ui_draw_copy_buf(); uiobj_input_wait(); hw_video_copy_back_from_page3(); help_index = GET_LE_16(&p[HELP_OFFS_NEXT]); } while (help_index != 0); uiobj_table_num_restore(); lbxfile_item_release(LBXFILE_HELP, helplbx); } 1oom-1.11.2/src/ui/classic/uihelp.h000066400000000000000000000001421476061725400167440ustar00rootroot00000000000000#ifndef INC_1OOM_UIHELP_H #define INC_1OOM_UIHELP_H extern void ui_help(int help_index); #endif 1oom-1.11.2/src/ui/classic/uiintro.c000066400000000000000000000315361476061725400171550ustar00rootroot00000000000000#include "config.h" #include "ui.h" #include "game_str.h" #include "hw.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ #define SFX_ID_1 (NUM_SOUNDS + 0) #define SFX_ID_3 (NUM_SOUNDS + 1) #define SFX_ID_5 (NUM_SOUNDS + 2) /* -------------------------------------------------------------------------- */ static bool check_intro_files(void) { const lbxfile_e tbl[3] = { LBXFILE_INTRO, LBXFILE_INTRO2, LBXFILE_INTROSND }; for (int i = 0; i < 3; ++i) { if (!lbxfile_exists(tbl[i])) { log_warning("skipping intro due to missing %s\n", lbxfile_name(tbl[i])); return false; } } return true; } /* -------------------------------------------------------------------------- */ void ui_play_intro(void) { int16_t oi_skip; uint16_t frame = 0; bool flag_skip, flag_fadein = false; uint8_t *intro_sfx1; uint8_t *intro_sfx3; uint8_t *intro_sfx5; uint8_t *intro_gfx = 0, *old_gfx = 0; if (!check_intro_files()) { return; } ui_palette_fadeout_14_14_2(); lbxpal_select(0, -1, 0); ui_draw_erase_buf(); lbxfont_select(5, 1, 0, 0); lbxfont_print_str_normal(0, 0, game_str_in_loading, UI_SCREEN_W, ui_scale); ui_cursor_setup_area(1, &ui_cursor_area_all_i0); uiobj_table_clear(); uiobj_finish_frame(); ui_palette_fadein_60_3_1(); ui_palette_fadeout_4_3_1(); /* uisound.c is not used as these are only used once */ { uint32_t len; hw_audio_sfx_batch_start(SFX_ID_5); intro_sfx5 = lbxfile_item_get_with_len(LBXFILE_INTROSND, 5, &len); hw_audio_sfx_init(SFX_ID_5, intro_sfx5, len); intro_sfx3 = lbxfile_item_get_with_len(LBXFILE_INTROSND, 3, &len); hw_audio_sfx_init(SFX_ID_3, intro_sfx3, len); intro_sfx1 = lbxfile_item_get_with_len(LBXFILE_INTROSND, 1, &len); hw_audio_sfx_init(SFX_ID_1, intro_sfx1, len); hw_audio_sfx_batch_end(); } ui_sound_play_music(0); ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); lbxpal_select(1, -1, 0); uiobj_table_clear(); uiobj_set_skip_delay(true); oi_skip = uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); flag_skip = 0; uiobj_set_downcount(2); if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO, 0); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); } while ((frame < 0x73) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ui_delay_ticks_or_click(3); ++frame; } } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO, 1); lbxfile_item_release(LBXFILE_INTRO, old_gfx); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0x1e) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } if (1/*sound_enabled && sfx_enabled*/) { if (frame == 9) { hw_audio_sfx_play(SFX_ID_5); } else if (frame == 0xe) { hw_audio_sfx_play(SFX_ID_5); /*seg2*/ } else if (frame == 0x13) { hw_audio_sfx_play(SFX_ID_5); /*seg3*/ } } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_60_3_1(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click(((frame > 0xe) && (frame < 0x1a)) ? 1 : 3); } } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO, 2); lbxfile_item_release(LBXFILE_INTRO, old_gfx); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0x46) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } if (1/*sound_enabled && sfx_enabled*/) { switch (frame) { case 0x32: case 0x37: case 0x3c: case 0x41: hw_audio_sfx_play(SFX_ID_3); break; default: break; } } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click((frame < 0x32) ? 3 : 1); } } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO, 3); lbxfile_item_release(LBXFILE_INTRO, old_gfx); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0x45) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } if (1/*sound_enabled && sfx_enabled*/) { if ((frame == 0x14) || (frame == 0x28)) { hw_audio_sfx_play(SFX_ID_1); } } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click(3); } } if (old_gfx) { lbxfile_item_release(LBXFILE_INTRO, old_gfx); old_gfx = 0; } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO2, 0); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0x28) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } if (1/*sound_enabled && sfx_enabled*/) { if (frame == 0x14) { hw_audio_sfx_play(SFX_ID_1); } } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click(3); } } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO2, 1); lbxfile_item_release(LBXFILE_INTRO2, old_gfx); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0x1e) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click(3); } } if (!flag_skip) { intro_gfx = lbxfile_item_get(LBXFILE_INTRO2, 2); lbxfile_item_release(LBXFILE_INTRO2, old_gfx); old_gfx = intro_gfx; ui_palette_fadeout_14_14_2(); frame = 0; flag_fadein = false; } while ((frame < 0xb4) && (!flag_skip)) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == oi_skip) || (oi == UIOBJI_ESC)) { flag_skip = true; break; } else { if (frame == 0) { ui_draw_erase_buf(); } else { if (frame == 1) { ui_draw_erase_buf(); } if (frame == 0xb2) { hw_audio_music_fadeout(); } lbxgfx_set_frame(intro_gfx, frame - 1); lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame_pal(0, 0, intro_gfx, UI_SCREEN_W, ui_scale); if (!flag_fadein) { uiobj_finish_frame(); ui_palette_fadein_50_14_2(); flag_fadein = true; } else { ui_palette_set_n(); uiobj_finish_frame(); } ++frame; ui_delay_ticks_or_click(4); } } if (old_gfx) { lbxfile_item_release(LBXFILE_INTRO2, old_gfx); old_gfx = 0; } ui_palette_fadeout_14_14_2(); ui_draw_erase_buf(); uiobj_finish_frame(); ui_draw_erase_buf(); ui_palette_fadeout_14_14_2(); uiobj_set_skip_delay(false); ui_sound_stop_music(); hw_audio_sfx_release(SFX_ID_1); hw_audio_sfx_release(SFX_ID_3); hw_audio_sfx_release(SFX_ID_5); lbxfile_item_release(LBXFILE_INTROSND, intro_sfx1); lbxfile_item_release(LBXFILE_INTROSND, intro_sfx3); lbxfile_item_release(LBXFILE_INTROSND, intro_sfx5); } 1oom-1.11.2/src/ui/classic/uilanding.c000066400000000000000000000114121476061725400174250ustar00rootroot00000000000000#include "config.h" #include #include #include "uilanding.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void landing_draw_cb1(void *vptr) { struct landing_data_s *d = vptr; const struct game_s *g = d->g; int y = 100; bool do_walk = false; char buf[0x80]; hw_video_copy_back_from_page3(); if (d->frame < 0x32) { y = d->frame * 4 - 100; } else { lbxgfx_set_new_frame(d->gfx_transprt, 0x27); if (d->frame >= 0x37) { do_walk = true; } } gfx_aux_draw_frame_to(d->gfx_transprt, &ui_data.aux.screen); gfx_aux_draw_frame_from_limit(0, y, &ui_data.aux.screen, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); if (do_walk) { lbxgfx_draw_frame(0, 0, d->gfx_walk, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(115, 81, 204, 109, 0xa, ui_scale); ui_draw_box1(115, 81, 204, 109, 0x34, 0x34, ui_scale); ui_draw_box1(121, 95, 195, 106, 0x34, 0x34, ui_scale); lbxfont_select(5, 0xf, 0, 0); lbxfont_print_str_normal(124, 84, game_str_la_colony, UI_SCREEN_W, ui_scale); /*uiobj_handle_ta_sub1(120, 80, 180, 90, 0); does nothing */ } lib_sprintf(buf, sizeof(buf), "%s %i %s %s%s", game_str_la_inyear, g->year + YEAR_BASE, game_str_la_the, game_str_tbl_race[g->eto[d->api].race], game_str_la_formnew); lbxfont_select_set_12_4(4, 0x5, 0, 0); lbxfont_print_str_center(160, 5, buf, UI_SCREEN_W, ui_scale); if (++d->frame == (0x41 + 100)) { d->frame = 0x41; } } /* -------------------------------------------------------------------------- */ void ui_landing_prepare(struct landing_data_s *d) { const struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet]); ui_delay_prepare(); ui_draw_erase_buf(); ui_delay_ticks_or_click(1); ui_sound_stop_music(); { uint8_t *gfx; int i = p->type; i += d->colonize ? 6 : 0x24; gfx = lbxfile_item_get(LBXFILE_LANDING, i); lbxgfx_draw_frame(0, 0, gfx, UI_SCREEN_W, ui_scale); lbxgfx_apply_palette(gfx); lbxfile_item_release(LBXFILE_LANDING, gfx); } hw_video_copy_back_to_page3(); d->gfx_transprt = lbxfile_item_get(LBXFILE_LANDING, 0x0); d->gfx_walk = lbxfile_item_get(LBXFILE_LANDING, 0x15 + g->eto[d->api].banner); lbxgfx_set_frame_0(d->gfx_walk); d->music_i = d->colonize ? 0xa : 8; } void ui_landing_free_data(struct landing_data_s *d) { lbxfile_item_release(LBXFILE_LANDING, d->gfx_transprt); lbxfile_item_release(LBXFILE_LANDING, d->gfx_walk); } void ui_landing(struct game_s *g, int pi, uint8_t planet_i) { struct landing_data_s d; bool flag_done = false; ui_switch_1(g, pi); memset(&d, 0, sizeof(d)); d.g = g; d.api = pi; d.planet = planet_i; d.frame = 0; d.colonize = (g->planet[planet_i].owner == PLAYER_NONE); if (ui_draw_finish_mode != 2) { ui_palette_fadeout_a_f_1(); } lbxpal_select(6, -1, 0); ui_landing_prepare(&d); ui_sound_play_music(d.music_i); lbxpal_build_colortables(); ui_draw_finish_mode = 2; uiobj_set_callback_and_delay(landing_draw_cb1, &d, 2); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(3); while (d.frame < 0x41) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { d.frame = 0x41; flag_done = true; } if (!flag_done) { landing_draw_cb1(&d); ui_draw_finish(); ui_delay_ticks_or_click(2); } } if (d.planet != g->evn.planet_orion_i) { const uint8_t ctbl[8] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; char buf[PLANET_NAME_LEN]; lib_strcpy(buf, g->planet[planet_i].name, sizeof(buf)); lbxfont_select(5, 0xf, 0xf, 0); if (uiobj_read_str(125, 97, 65, buf, PLANET_NAME_LEN - 1, 0, false, ctbl)) { util_trim_whitespace(buf, sizeof(buf)); if (buf[0] != 0) { lib_strcpy(g->planet[planet_i].name, buf, PLANET_NAME_LEN); } } } ui_sound_stop_music(); ui_palette_fadeout_a_f_1(); lbxpal_select(0, -1, 0); lbxpal_build_colortables(); ui_draw_finish_mode = 2; uiobj_unset_callback(); uiobj_table_clear(); ui_landing_free_data(&d); } 1oom-1.11.2/src/ui/classic/uilanding.h000066400000000000000000000006651476061725400174420ustar00rootroot00000000000000#ifndef INC_1OOM_UILANDING_H #define INC_1OOM_UILANDING_H #include "game_types.h" #include "types.h" struct game_s; struct landing_data_s { struct game_s *g; player_id_t api; uint8_t planet; int frame; int music_i; bool colonize; uint8_t *gfx_transprt; uint8_t *gfx_walk; }; extern void ui_landing_prepare(struct landing_data_s *d); extern void ui_landing_free_data(struct landing_data_s *d); #endif 1oom-1.11.2/src/ui/classic/uiload.c000066400000000000000000000105771476061725400167430ustar00rootroot00000000000000#include "config.h" #include "ui.h" #include "game_save.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiload.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct load_game_data_s { int selected; int savenum; int tbl_savei[NUM_ALL_SAVES]; uint8_t *gfx_loadgame; uint8_t *gfx_lg_gray; uint8_t *gfx_lg_green; bool flag_moo13; }; static void load_lg_data(struct load_game_data_s *d) { d->gfx_loadgame = lbxfile_item_get(LBXFILE_VORTEX, 3); d->gfx_lg_gray = lbxfile_item_get(LBXFILE_VORTEX, 7); d->gfx_lg_green = lbxfile_item_get(LBXFILE_VORTEX, 8); } static void free_lg_data(struct load_game_data_s *d) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_loadgame); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_lg_gray); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_lg_green); } static void load_game_draw_cb(void *vptr) { struct load_game_data_s *d = vptr; hw_video_copy_back_from_page2(); lbxgfx_draw_frame(0, 0, d->gfx_loadgame, UI_SCREEN_W, ui_scale); for (int i = 0; i < d->savenum; ++i) { int si, y; si = d->tbl_savei[i]; y = (si < NUM_SAVES) ? (33 + 18 * si) : (110 + 10 * si); lbxgfx_draw_frame(134, y, (d->selected == i) ? d->gfx_lg_green : d->gfx_lg_gray, UI_SCREEN_W, ui_scale); lbxfont_select(0, (d->selected == i) ? 2 : 1, 0, 0); if (d->flag_moo13) { char fname[12] = "SAVEX.GAM"; fname[4] = si + '0' + 1; lbxfont_print_str_normal(149, y + 2, fname, UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_normal(149, y + 2, game_save_tbl_name[si], UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ static int ui_load_game_do(bool flag_moo13) { struct load_game_data_s d; bool flag_done = false, flag_fadein = false; int16_t oi_cancel, oi_ok, oi_save[NUM_ALL_SAVES]; d.flag_moo13 = flag_moo13; d.savenum = 0; for (int i = 0; i < (ui_load_opts_extra ? NUM_ALL_SAVES : NUM_SAVES); ++i) { if (game_save_tbl_have_save[i]) { d.tbl_savei[d.savenum++] = i; } } if (d.flag_moo13) { /* FIXME */ d.savenum = 7; for (int i = 0; i < d.savenum; ++i) { d.tbl_savei[i] = i; } } if (d.savenum == 0) { return -1; } load_lg_data(&d); ui_palette_fadeout_19_19_1(); lbxpal_select(2, -1, 0); uiobj_table_clear(); oi_cancel = uiobj_add_mousearea(138, 145, 192, 161, MOO_KEY_ESCAPE); oi_ok = uiobj_add_mousearea(202, 145, 256, 161, MOO_KEY_SPACE); uiobj_set_focus(oi_ok); for (int i = 0; i < d.savenum; ++i) { int si, x0, x1, y0, y1; si = d.tbl_savei[i]; y0 = (si < NUM_SAVES) ? (31 + 18 * si) : (110 + 10 * si); y1 = y0 + ((si < NUM_SAVES) ? 14 : 8); x0 = 130; x1 = x0 + ((si < NUM_SAVES) ? 134 : 70); oi_save[i] = uiobj_add_mousearea(x0, y0, x1, y1, MOO_KEY_1 + si); } d.selected = 0; ui_draw_erase_buf(); hw_video_copy_back_to_page2(); uiobj_set_callback_and_delay(load_game_draw_cb, &d, 2); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); for (int i = 0; i < d.savenum; ++i) { if (oi == oi_save[i]) { d.selected = i; ui_sound_play_sfx_24(); } } if ((oi == oi_cancel) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); d.selected = -1; flag_done = true; } if (oi == oi_ok) { ui_sound_play_sfx_24(); flag_done = true; } load_game_draw_cb(&d); uiobj_finish_frame(); if (!flag_fadein) { ui_palette_fadein_4b_19_1(); flag_fadein = true; } ui_delay_ticks_or_click(2); } uiobj_unset_callback(); free_lg_data(&d); return (d.selected >= 0) ? d.tbl_savei[d.selected] : -1; } int ui_load_game(void) { return ui_load_game_do(false); } int ui_load_game_moo13(void) { return ui_load_game_do(true); } 1oom-1.11.2/src/ui/classic/uiload.h000066400000000000000000000002611476061725400167350ustar00rootroot00000000000000#ifndef INC_1OOM_UILOAD_H #define INC_1OOM_UILOAD_H /* returns -1 on cancel or 0..5 on load game */ extern int ui_load_game(void); extern int ui_load_game_moo13(void); #endif 1oom-1.11.2/src/ui/classic/uimainmenu.c000066400000000000000000001130451476061725400176270ustar00rootroot00000000000000#include "config.h" #include "ui.h" #include "comp.h" #include "game.h" #include "game_ai.h" #include "game_event.h" #include "game_new.h" #include "game_num.h" #include "game_nump.h" #include "game_save.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "menu.h" #include "rnd.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiload.h" #include "uinewgame.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "version.h" /* -------------------------------------------------------------------------- */ static bool force_restart = false; static bool main_menu_game_active(void) { return !force_restart; } static bool main_menu_have_save_continue(void) { return game_save_tbl_have_save[GAME_SAVE_I_CONTINUE]; } static bool main_menu_have_save_any(void) { const int num_saves = ui_extra_enabled ? NUM_ALL_SAVES : NUM_ALL_SAVES; for (int i = 0; i < num_saves; ++i) { if (game_save_tbl_have_save[i]) { return true; } } return false; } static bool main_menu_toggle_kbd_repeat(void) { ui_kbd_repeat = !ui_kbd_repeat; hw_kbd_set_repeat(ui_kbd_repeat); return true; } static bool main_menu_toggle_music(void) { if (opt_music_enabled) { ui_sound_stop_music(); opt_music_enabled = false; } else { opt_music_enabled = true; ui_sound_play_music(1); } return true; } static bool main_menu_update_music_volume(void) { hw_audio_music_volume(opt_music_volume); return true; } static bool main_menu_update_sfx_volume(void) { hw_audio_sfx_volume(opt_sfx_volume); return true; } static const char* mm_get_custom_difficulty_value(uint32_t i) { return game_str_tbl_diffic[i]; } static const char* mm_get_custom_galaxy_size_value(uint32_t i) { return game_str_tbl_gsize[i]; } static const char* mm_get_custom_ai_id_value(uint32_t i) { return game_ais[i]->name; } static const char* mm_get_custom_galaxy_seed_str(void) { static char buf[64]; if (game_opt_custom.galaxy_seed == 0) { lib_sprintf(buf, 64, "Off"); } else { lib_sprintf(buf, 64, "%d", game_opt_custom.galaxy_seed); } return buf; } static bool mm_gen_custom_galaxy_seed(void) { game_opt_custom.galaxy_seed = game_opt_custom.galaxy_seed ? 0 : rnd_get_new_seed(); return true; } const char *game_str_tbl_sm_pspecial_mm[PLANET_SPECIAL_NUM] = { "Ultra Poor", "Poor", "Normal", "Artifacts", "Rich", "Ultra Rich", "4x Tech" }; static const char* mm_get_custom_special_value(uint32_t i) { return game_str_tbl_sm_pspecial_mm[i]; } static bool mm_enable_preset_classic(void) { ui_extra_toggle_preset(false); return true; } static bool mm_enable_preset_1oom(void) { ui_extra_toggle_preset(true); return true; } /* -------------------------------------------------------------------------- */ #define MM_PAGE_STACK_SIZE 4 typedef enum { MAIN_MENU_PAGE_MAIN, MAIN_MENU_PAGE_GAME, MAIN_MENU_PAGE_GAME_CUSTOM, MAIN_MENU_PAGE_GAME_CUSTOM_GALAXY, MAIN_MENU_PAGE_GAME_CUSTOM_HOMEWORLDS, MAIN_MENU_PAGE_OPTIONS, MAIN_MENU_PAGE_OPTIONS_INPUT, MAIN_MENU_PAGE_OPTIONS_SOUND, MAIN_MENU_PAGE_OPTIONS_VIDEO, MAIN_MENU_PAGE_OPTIONS_ADDONS, MAIN_MENU_PAGE_OPTIONS_ADDONS_MESSAGE_FILTER, MAIN_MENU_PAGE_OPTIONS_MISC, MAIN_MENU_PAGE_OPTIONS_STARMAP, MAIN_MENU_PAGE_OPTIONS_RULES, MAIN_MENU_PAGE_OPTIONS_RULES_AI, MAIN_MENU_PAGE_OPTIONS_RULES_BATTLE, MAIN_MENU_PAGE_OPTIONS_RULES_DIFFICULTY, MAIN_MENU_PAGE_OPTIONS_RULES_FLEET_BEHAVIOR, MAIN_MENU_PAGE_OPTIONS_RULES_MONSTER, MAIN_MENU_PAGE_OPTIONS_RULES_ORBITAL_BOMBARDMENT, MAIN_MENU_PAGE_OPTIONS_RULES_PLANETARY_DEVELOPMENT, MAIN_MENU_PAGE_OPTIONS_RULES_SLIDER_BEHAVIOR, MAIN_MENU_PAGE_OPTIONS_RULES_OTHER, MAIN_MENU_PAGE_PRESET, MAIN_MENU_PAGE_NUM, } main_menu_page_id_t; struct main_menu_item_s { struct menu_item_data_s data; uint16_t font_i; uint16_t x; uint16_t y; uint16_t w; uint16_t h; int16_t oi; int16_t oi_shift; int16_t oi_wheel; bool active; }; struct main_menu_data_s { void (*set_item_dimensions)(struct main_menu_data_s *, int i); main_menu_page_id_t page_stack[MM_PAGE_STACK_SIZE]; int page_stack_i; int current_page_i; struct main_menu_item_s items[MENU_MAX_ITEMS_PER_PAGE]; uint8_t item_count; int16_t oi_plus, oi_minus, oi_equals; int16_t scrollmisc; int frame; bool refresh; main_menu_action_t ret; bool flag_done; int clicked_i; int shift_i; int wheel_i; int highlight; uint8_t *gfx_vortex; uint8_t *gfx_title; }; static void load_mainmenu_data(struct main_menu_data_s *d) { d->gfx_vortex = lbxfile_item_get(LBXFILE_VORTEX, 0); d->gfx_title = lbxfile_item_get(LBXFILE_V11, 0); } static void free_mainmenu_data(struct main_menu_data_s *d) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_vortex); lbxfile_item_release(LBXFILE_V11, d->gfx_title); } /* -------------------------------------------------------------------------- */ static void main_menu_get_item_string(const struct main_menu_item_s *it, char *buf, int len) { if (it->data.type == MENU_ITEM_TYPE_BOOL) { bool *v = it->data.value_ptr; lib_sprintf(buf, len, "%s %s", it->data.text, *v ? "On" : "Off"); } else if (it->data.type == MENU_ITEM_TYPE_INT) { int *v = it->data.value_ptr; lib_sprintf(buf, len, "%s %d", it->data.text, *v); } else if (it->data.type == MENU_ITEM_TYPE_ENUM) { int *v = it->data.value_ptr; lib_sprintf(buf, len, "%s %s", it->data.text, it->data.get_text_value(*v)); } else if (it->data.type == MENU_ITEM_TYPE_STR) { const char *(*f)(void) = it->data.get_text_value2; lib_sprintf(buf, len, "%s %s", it->data.text, f()); } else { lib_sprintf(buf, len, "%s", it->data.text); } } static void main_menu_draw_cb(void *vptr) { struct main_menu_data_s *d = vptr; char buf[64]; ui_draw_erase_buf(); if (d->refresh) { lbxgfx_set_frame_0(d->gfx_vortex); d->refresh = false; } else { hw_video_copy_back_from_page2(); } lbxgfx_draw_frame(0, 0, d->gfx_vortex, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame_offs(0, 0, d->gfx_title, 0, 0, UI_VGA_W - 1, 191, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); lbxfont_select(2, 7, 0, 0); lbxfont_print_str_right(315, 193, PACKAGE_NAME " " VERSION_STR, UI_SCREEN_W, ui_scale); if (force_restart) { lbxfont_select(2, 2, 0, 0); lbxfont_print_str_center(160, 60, "Application restart required", UI_SCREEN_W, ui_scale); } for (int i = 0; i < d->item_count; ++i) { struct main_menu_item_s *it = &d->items[i]; if (it->active) { lbxfont_select(it->font_i, (d->highlight == i) ? 3 : 2, 0, 0); } else { lbxfont_select(it->font_i, 7, 0, 0); } main_menu_get_item_string(it, buf, sizeof(buf)); lbxfont_print_str_center(it->x, it->y, buf, UI_SCREEN_W, ui_scale); } d->frame = (d->frame + 1) % 0x30; } /* -------------------------------------------------------------------------- */ static void main_menu_set_item_wh(struct main_menu_data_s *d, struct main_menu_item_s *it) { char buf[64]; lbxfont_select(it->font_i, 7, 0, 0); main_menu_get_item_string(it, buf, sizeof(buf)); it->w = lbxfont_calc_str_width(buf); it->h = lbxfont_get_height(); } static void main_menu_set_item_dimensions(struct main_menu_data_s *d, int i) { struct main_menu_item_s *it = &d->items[i]; uint16_t step_y; it->font_i = 4; main_menu_set_item_wh(d, it); step_y = 0x40 / d->item_count; it->x = 0xa0; it->y = 0x7f + step_y * i; } static void mm_game_set_item_dimensions(struct main_menu_data_s *d, int i) { struct main_menu_item_s *it = &d->items[i]; uint16_t step_y; it->font_i = 4; main_menu_set_item_wh(d, it); step_y = 0x40 / ((d->item_count + 1) / 2); it->x = i%2 ? 0xd0 : 0x70; if (i%2 == 0 && i == d->item_count - 1) { it->x = 0xa0; } it->y = 0x7f + step_y * (i/2); } static void mm_options_set_item_dimensions(struct main_menu_data_s *d, int i) { struct main_menu_item_s *it = &d->items[i]; uint16_t step_y; it->font_i = 5; main_menu_set_item_wh(d, it); if (d->item_count <= 6) { step_y = 0x48 / d->item_count; it->x = 0xa0; it->y = 0x77 + step_y * i; } else { step_y = 0x48 / ((d->item_count + 1) / 2); it->x = i%2 ? 0xe0 : 0x60; if (i%2 == 0 && i == d->item_count - 1) { it->x = 0xa0; } it->y = 0x77 + step_y * (i/2); } } static void mm_custom_set_item_dimensions(struct main_menu_data_s *d, int i) { struct main_menu_item_s *it = &d->items[i]; uint16_t step_y; it->font_i = 5; main_menu_set_item_wh(d, it); step_y = 0x40 / ((d->item_count + 1) / 2); it->x = i%2 ? 0xe0 : 0x60; it->y = 0x7f + step_y * (i/2); if (i == d->item_count - 1) { it->x = 0xe0; it->y = 0x7f + 0x30; } if (i == d->item_count - 2) { it->x = 0x60; it->y = 0x7f + 0x30; } } static void main_menu_make_main_page(struct main_menu_data_s *d) { d->set_item_dimensions = main_menu_set_item_dimensions; menu_make_page_conditional(menu_allocate_item(), "Game", MAIN_MENU_PAGE_GAME, main_menu_game_active, MOO_KEY_g); menu_make_page(menu_allocate_item(), "Rules", MAIN_MENU_PAGE_OPTIONS_RULES, MOO_KEY_r); menu_make_page(menu_allocate_item(), "UI Options", MAIN_MENU_PAGE_OPTIONS, MOO_KEY_o); menu_make_action(menu_allocate_item(), "Quit to OS", MAIN_MENU_ACT_QUIT_GAME, MOO_KEY_q); } static void main_menu_make_game_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_game_set_item_dimensions; menu_make_action(menu_allocate_item(), "Tutor", MAIN_MENU_ACT_TUTOR, MOO_KEY_t); menu_make_action_conditional(menu_allocate_item(), "Continue", MAIN_MENU_ACT_CONTINUE_GAME, main_menu_have_save_continue, MOO_KEY_c); menu_make_action_conditional(menu_allocate_item(), "Load Game", MAIN_MENU_ACT_LOAD_GAME, main_menu_have_save_any, MOO_KEY_l); menu_make_action(menu_allocate_item(), "Load Game MOO", MAIN_MENU_ACT_LOAD_GAME_MOO13, MOO_KEY_m); menu_make_action(menu_allocate_item(), "New Game", MAIN_MENU_ACT_NEW_GAME, MOO_KEY_n); menu_make_page(menu_allocate_item(), "Custom Game", MAIN_MENU_PAGE_GAME_CUSTOM, MOO_KEY_u); menu_make_action(menu_allocate_item(), "Challenge", MAIN_MENU_ACT_CHALLENGE_GAME, MOO_KEY_h); menu_make_back(menu_allocate_item()); } static void main_menu_make_game_custom_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_custom_set_item_dimensions; menu_make_enum(menu_allocate_item(), "Difficulty", mm_get_custom_difficulty_value, &game_opt_custom.difficulty, 0, DIFFICULTY_NUM - 1, MOO_KEY_d); menu_make_enum(menu_allocate_item(), "AI ID", mm_get_custom_ai_id_value, &game_opt_custom.ai_id, 0, GAME_AI_NUM - 1, MOO_KEY_a); menu_make_page(menu_allocate_item(), "Galaxy", MAIN_MENU_PAGE_GAME_CUSTOM_GALAXY, MOO_KEY_g); menu_make_page(menu_allocate_item(), "Homeworlds", MAIN_MENU_PAGE_GAME_CUSTOM_HOMEWORLDS, MOO_KEY_h); menu_make_back(menu_allocate_item()); menu_make_action(menu_allocate_item(), "Next", MAIN_MENU_ACT_CUSTOM_GAME, MOO_KEY_n); } static void main_menu_make_game_custom_galaxy_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_enum(menu_allocate_item(), "Size", mm_get_custom_galaxy_size_value, &game_opt_custom.galaxy_size, 0, GALAXY_SIZE_HUGE, MOO_KEY_s); menu_make_str_func(menu_allocate_item(), "Galaxy Seed", mm_get_custom_galaxy_seed_str, mm_gen_custom_galaxy_seed, MOO_KEY_e); menu_make_int(menu_allocate_item(), "Players", &game_opt_custom.players, 2, PLAYER_NUM, MOO_KEY_p); menu_make_bool(menu_allocate_item(), "Improved generator", &game_opt_custom.improved_galaxy_generator, MOO_KEY_g); menu_make_int(menu_allocate_item(), "Num dist checks", &game_opt_custom.homeworlds.num_dist_checks, 0, PLAYER_NUM, MOO_KEY_d); menu_make_int(menu_allocate_item(), "Num OK planet checks", &game_opt_custom.homeworlds.num_ok_planet_checks, 0, PLAYER_NUM, MOO_KEY_o); menu_make_bool(menu_allocate_item(), "Nebulae", &game_opt_custom.nebulae, MOO_KEY_n); menu_make_back(menu_allocate_item()); } static void main_menu_make_game_custom_homeworlds_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_int(menu_allocate_item(), "Max population", &game_opt_custom.homeworlds.max_pop, 50, 120, MOO_KEY_p); menu_make_enum(menu_allocate_item(), "Special", mm_get_custom_special_value, &game_opt_custom.homeworlds.special, 0, PLANET_SPECIAL_4XTECH, MOO_KEY_e); menu_make_int(menu_allocate_item(), "Num scouts", &game_opt_custom.homeworlds.num_scouts, 0, 5, MOO_KEY_s); menu_make_int(menu_allocate_item(), "Num fighters", &game_opt_custom.homeworlds.num_fighters, 0, 10, MOO_KEY_f); menu_make_int(menu_allocate_item(), "Num colony ships", &game_opt_custom.homeworlds.num_colony_ships, 0, 2, MOO_KEY_c); menu_make_bool(menu_allocate_item(), "Armed colony ships", &game_opt_custom.homeworlds.armed_colony_ships, MOO_KEY_a); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_game_set_item_dimensions; menu_make_page(menu_allocate_item(), "Input", MAIN_MENU_PAGE_OPTIONS_INPUT, MOO_KEY_i); menu_make_page(menu_allocate_item(), "Add-ons", MAIN_MENU_PAGE_OPTIONS_ADDONS, MOO_KEY_a); menu_make_page(menu_allocate_item(), "Sound", MAIN_MENU_PAGE_OPTIONS_SOUND, MOO_KEY_s); menu_make_page(menu_allocate_item(), "Starmap", MAIN_MENU_PAGE_OPTIONS_STARMAP, MOO_KEY_t); menu_make_page(menu_allocate_item(), "Video", MAIN_MENU_PAGE_OPTIONS_VIDEO, MOO_KEY_v); menu_make_page(menu_allocate_item(), "Misc", MAIN_MENU_PAGE_OPTIONS_MISC, MOO_KEY_m); menu_make_page(menu_allocate_item(), "Preset", MAIN_MENU_PAGE_PRESET, MOO_KEY_p); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_input_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Disable Mouse Warp", &ui_mouse_warp_disabled, MOO_KEY_w); menu_make_bool(menu_allocate_item(), "LMB Behavior Fix", &ui_mouse_lmb_fix, MOO_KEY_l); menu_make_bool(menu_allocate_item(), "Invert slider", &ui_mwi_slider, MOO_KEY_i); menu_make_bool(menu_allocate_item(), "Invert counter", &ui_mwi_counter, MOO_KEY_n); menu_make_bool_func(menu_allocate_item(), "Keyboard repeat", &ui_kbd_repeat, main_menu_toggle_kbd_repeat, MOO_KEY_k); menu_make_bool(menu_allocate_item(), "Direction Keys Fix", &ui_kbd_cursor_keys_fix, MOO_KEY_d); menu_make_bool(menu_allocate_item(), "Illogical Hotkey Fix", &ui_illogical_hotkey_fix, MOO_KEY_h); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_sound_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool_func(menu_allocate_item(), "Music", &opt_music_enabled, main_menu_toggle_music, MOO_KEY_m); menu_make_int_func(menu_allocate_item(), "Music volume", &opt_music_volume, 0, 128, main_menu_update_music_volume, MOO_KEY_u); menu_make_bool(menu_allocate_item(), "SFX", &opt_sfx_enabled, MOO_KEY_s); menu_make_int_func(menu_allocate_item(), "SFX volume", &opt_sfx_volume, 0, 128, main_menu_update_sfx_volume, MOO_KEY_f); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_video_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_int(menu_item_force_restart(menu_allocate_item()), "UI scale", &ui_scale_hint, 1, UI_SCALE_MAX, MOO_KEY_s); hw_opt_menu_make_page_video(); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_addons_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "UI Extra", &ui_extra_enabled, MOO_KEY_e); menu_make_bool(menu_allocate_item(), "UI Fixbugs", &ui_fixbugs_enabled, MOO_KEY_f); menu_make_bool(menu_allocate_item(), "Combat Autoresolve", &ui_space_combat_autoresolve, MOO_KEY_v); menu_make_bool(menu_allocate_item(), "UI SM Ships", &ui_sm_ships_enabled, MOO_KEY_s); menu_make_bool(menu_allocate_item(), "Load Options Extra", &ui_load_opts_extra, MOO_KEY_o); menu_make_page(menu_allocate_item(), "Message Filter", MAIN_MENU_PAGE_OPTIONS_ADDONS_MESSAGE_FILTER, MOO_KEY_m); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_addons_message_filter_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Max Factories", &game_opt_message_filter[FINISHED_FACT], MOO_KEY_f); menu_make_bool(menu_allocate_item(), "Max Population", &game_opt_message_filter[FINISHED_POPMAX], MOO_KEY_f); menu_make_bool(menu_allocate_item(), "Atmos / Soil", &game_opt_message_filter[FINISHED_SOILATMOS], MOO_KEY_f); menu_make_bool(menu_allocate_item(), "Stargate", &game_opt_message_filter[FINISHED_STARGATE], MOO_KEY_f); menu_make_bool(menu_allocate_item(), "Planetary Shield", &game_opt_message_filter[FINISHED_SHIELD], MOO_KEY_f); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_misc_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Skip Intro", &game_opt_skip_intro_always, MOO_KEY_i); menu_make_bool(menu_allocate_item(), "Skip Random News", &game_opt_skip_random_news, MOO_KEY_n); menu_make_bool(menu_allocate_item(), "Skip Copy Protection", &ui_copyprotection_disabled, MOO_KEY_p); menu_make_bool(menu_allocate_item(), "News Orion Colonized", &game_num_news_orion, MOO_KEY_o); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_starmap_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Explicit Cursor Context", &ui_sm_explicit_cursor_context, MOO_KEY_c); menu_make_bool(menu_allocate_item(), "No '?' Cursor", &ui_sm_no_question_mark_cursor, MOO_KEY_q); menu_make_bool(menu_allocate_item(), "Expanded Scroll", &ui_sm_expanded_scroll, MOO_KEY_e); menu_make_bool(menu_allocate_item(), "Mouseover Focus", &ui_sm_mouseover_focus, MOO_KEY_m); menu_make_bool(menu_allocate_item(), "Scroll by mouse", &ui_sm_mouse_scroll, MOO_KEY_s); menu_make_bool(menu_allocate_item(), "UHJK scroll", &ui_sm_uhjk_scroll, MOO_KEY_u); menu_make_bool(menu_allocate_item(), "Smoother scrolling", &ui_sm_smoother_scrolling, MOO_KEY_o); menu_make_int(menu_allocate_item(), "Scroll speed", &ui_sm_scroll_speed, 0, UI_SCROLL_SPEED_MAX, MOO_KEY_p); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_page(menu_allocate_item(), "AI Behavior", MAIN_MENU_PAGE_OPTIONS_RULES_AI, MOO_KEY_a); menu_make_page(menu_allocate_item(), "Difficulty Modifiers", MAIN_MENU_PAGE_OPTIONS_RULES_DIFFICULTY, MOO_KEY_d); menu_make_page(menu_allocate_item(), "Fleet Behavior", MAIN_MENU_PAGE_OPTIONS_RULES_FLEET_BEHAVIOR, MOO_KEY_f); menu_make_page(menu_allocate_item(), "Monster", MAIN_MENU_PAGE_OPTIONS_RULES_MONSTER, MOO_KEY_m); menu_make_page(menu_allocate_item(), "Orbital Bombardment", MAIN_MENU_PAGE_OPTIONS_RULES_ORBITAL_BOMBARDMENT, MOO_KEY_o); menu_make_page(menu_allocate_item(), "Planetary Development", MAIN_MENU_PAGE_OPTIONS_RULES_PLANETARY_DEVELOPMENT, MOO_KEY_p); menu_make_page(menu_allocate_item(), "Slider Behavior", MAIN_MENU_PAGE_OPTIONS_RULES_SLIDER_BEHAVIOR, MOO_KEY_l); menu_make_page(menu_allocate_item(), "Space Battle", MAIN_MENU_PAGE_OPTIONS_RULES_BATTLE, MOO_KEY_s); menu_make_page(menu_allocate_item(), "Other", MAIN_MENU_PAGE_OPTIONS_RULES_OTHER, MOO_KEY_t); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_ai_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Transport Range Fix", &game_num_ai_trans_range_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "4th Colony Curse Fix", &game_num_ai_4_colony_curse_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Doom Stack Fix", &game_num_doom_stack_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "First Tech Cost Fix", &game_num_ai_first_tech_cost_fix, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_battle_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "No Tohit Accumulation", &game_num_bt_no_tohit_acc, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Oracle Fix", &game_num_bt_oracle_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Precap Tohit", &game_num_bt_precap_tohit, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Wait No Reload", &game_num_bt_wait_no_reload, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_difficulty_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "AI Fleet Cheating Fix", &game_num_ai_fleet_cheating_fix, MOO_KEY_UNKNOWN); menu_make_int(menu_allocate_item(), "Tech Cost Multiplier", &game_num_tech_costmul, 50, 400, MOO_KEY_UNKNOWN); menu_make_int(menu_allocate_item(), "AI Tech Cost Multiplier", &game_num_tech_costmula2, 50, 100, MOO_KEY_UNKNOWN); menu_make_int(menu_allocate_item(), "Human Tech Cost Multiplier", &game_num_tech_costmuld2, 100, 400, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_fleet_behavior_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Extended Reloc Range", &game_num_extended_reloc_range, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Ship Scanner Fix", &game_num_ship_scanner_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Retreat Redirection Fix", &game_num_retreat_redir_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Stargate Redirection Fix", &game_num_stargate_redir_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Transport Redirection Fix", &game_num_trans_redir_fix, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_monster_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Monster Rest Attack", &game_num_monster_rest_att, MOO_KEY_UNKNOWN); menu_make_bool(menu_item_force_restart(menu_allocate_item()), "Guardian Repair Fix", &game_opt_fix_guardian_repair, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_orbital_bombardment_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Bio Damage Fix", &game_num_orbital_bio_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Allow Any Weapon", &game_num_orbital_weap_any, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Allow Weapon 4", &game_num_orbital_weap_4, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Torpedo Damage Fix", &game_num_orbital_torpedo, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Computer Bonus Fix", &game_num_orbital_comp_fix, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_planetary_development_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Factory Cost Fix", &game_num_factory_cost_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "First Tech Rp Fix", &game_num_first_tech_rp_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Hidden Child Labor Fix", &game_num_hidden_child_labor_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Leaving Transport Fix", &game_num_leaving_trans_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Population Tenths Fix", &game_num_pop_tenths_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Soil Rounding Fix", &game_num_soil_rounding_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Waste Calc Fix", &game_num_waste_calc_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Colonized Factories Fix", &game_num_colonized_factories_fix, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_slider_behavior_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Cond Switch To Ind Fix", &game_num_cond_switch_to_ind_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Eco Done Fix", &game_num_slider_eco_done_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Newtech Adjust Fix", &game_num_newtech_adjust_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Waste Adjust Fix", &game_num_waste_adjust_fix, MOO_KEY_UNKNOWN); menu_make_bool(menu_allocate_item(), "Slider Respects Locks", &game_num_slider_respects_locks, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_options_rules_other_page(struct main_menu_data_s *d) { d->set_item_dimensions = mm_options_set_item_dimensions; menu_make_bool(menu_allocate_item(), "Deterministic RNG", &game_num_deterministic, MOO_KEY_UNKNOWN); menu_make_bool(menu_item_force_restart(menu_allocate_item()), "Fix Other Bugs", &game_opt_fix_bugs, MOO_KEY_UNKNOWN); menu_make_bool(menu_item_force_restart(menu_allocate_item()), "Starting Ships Fix", &game_opt_fix_starting_ships, MOO_KEY_UNKNOWN); menu_make_back(menu_allocate_item()); } static void main_menu_make_preset_page(struct main_menu_data_s *d) { d->set_item_dimensions = main_menu_set_item_dimensions; menu_make_func(menu_allocate_item(), "Classic", mm_enable_preset_classic, MOO_KEY_c); menu_make_func(menu_allocate_item(), "1oom", mm_enable_preset_1oom, MOO_KEY_1); menu_make_back(menu_allocate_item()); } /* -------------------------------------------------------------------------- */ struct main_menu_page_s { void (*make_page)(struct main_menu_data_s *); }; static struct main_menu_page_s mm_pages[MAIN_MENU_PAGE_NUM] = { { main_menu_make_main_page, }, { main_menu_make_game_page, }, { main_menu_make_game_custom_page, }, { main_menu_make_game_custom_galaxy_page, }, { main_menu_make_game_custom_homeworlds_page, }, { main_menu_make_options_page, }, { main_menu_make_options_input_page, }, { main_menu_make_options_sound_page, }, { main_menu_make_options_video_page, }, { main_menu_make_options_addons_page, }, { main_menu_make_options_addons_message_filter_page, }, { main_menu_make_options_misc_page, }, { main_menu_make_options_starmap_page, }, { main_menu_make_options_rules_page, }, { main_menu_make_options_rules_ai_page, }, { main_menu_make_options_rules_battle_page, }, { main_menu_make_options_rules_difficulty_page, }, { main_menu_make_options_rules_fleet_behavior_page, }, { main_menu_make_options_rules_monster_page, }, { main_menu_make_options_rules_orbital_bombardment_page, }, { main_menu_make_options_rules_planetary_development_page, }, { main_menu_make_options_rules_slider_behavior_page, }, { main_menu_make_options_rules_other_page, }, { main_menu_make_preset_page, }, }; static bool main_menu_load_page(struct main_menu_data_s *d, main_menu_page_id_t page_i) { if (page_i < 0 || page_i >= MAIN_MENU_PAGE_NUM) { return false; } d->current_page_i = page_i; uiobj_table_clear(); menu_clear(); mm_pages[page_i].make_page(d); d->item_count = menu_get_item_count(); d->scrollmisc = 0; d->oi_plus = uiobj_add_inputkey(MOO_KEY_PLUS); d->oi_minus = uiobj_add_inputkey(MOO_KEY_MINUS); d->oi_equals = uiobj_add_inputkey(MOO_KEY_EQUALS); for (int i = 0; i < d->item_count; ++i) { struct main_menu_item_s *it = &d->items[i]; it->data = *menu_get_item(i); d->set_item_dimensions(d, i); it->active = it->data.is_active ? it->data.is_active() : true; if (it->active) { it->oi = uiobj_add_mousearea(it->x - it->w / 2, it->y, it->x + it->w / 2, it->y + it->h - 2, it->data.key); it->oi_shift = uiobj_add_inputkey(it->data.key | MOO_MOD_SHIFT); it->oi_wheel = uiobj_add_mousewheel(it->x - it->w / 2, it->y, it->x + it->w / 2, it->y + it->h - 2, &d->scrollmisc); } else { it->oi = UIOBJI_INVALID; it->oi_shift = UIOBJI_INVALID; it->oi_wheel = UIOBJI_INVALID; } } return true; } static void main_menu_push_page(struct main_menu_data_s *d, main_menu_page_id_t page_i) { if (d->page_stack_i + 1 >= MM_PAGE_STACK_SIZE) { return; } if (main_menu_load_page(d, page_i)) { ++d->page_stack_i; d->page_stack[d->page_stack_i] = page_i; } } static void main_menu_pop_page(struct main_menu_data_s *d) { if (d->page_stack_i > 0) { ui_sound_play_sfx_06(); --d->page_stack_i; main_menu_load_page(d, d->page_stack[d->page_stack_i]); } } static int main_menu_get_item(struct main_menu_data_s *d, int16_t oi) { for (int i = 0; i < d->item_count; ++i) { if (oi == d->items[i].oi) { return i; } } return -1; } static int main_menu_get_item_shift(struct main_menu_data_s *d, int16_t oi) { for (int i = 0; i < d->item_count; ++i) { if (oi == d->items[i].oi_shift) { return i; } } return -1; } static int main_menu_get_item_wheel(struct main_menu_data_s *d, int16_t oi) { for (int i = 0; i < d->item_count; ++i) { if (oi == d->items[i].oi_wheel) { return i; } } return -1; } static void main_menu_item_do_plus(struct main_menu_data_s *d, int item_i) { const struct main_menu_item_s *it = &d->items[item_i]; if (it->data.need_restart) { force_restart = true; } if (it->data.type == MENU_ITEM_TYPE_RETURN) { d->ret = it->data.action_i; d->flag_done = true; } else if (it->data.type == MENU_ITEM_TYPE_PAGE) { main_menu_push_page(d, it->data.action_i); } else if (it->data.type == MENU_ITEM_TYPE_PAGE_BACK) { main_menu_pop_page(d); } else if (it->data.type == MENU_ITEM_TYPE_FUNCTION) { if (it->data.func) { it->data.func(); } } else if (it->data.type == MENU_ITEM_TYPE_BOOL) { if (it->data.func) { it->data.func(); } else { bool *v = it->data.value_ptr; *v = !*v; } } else if (it->data.type == MENU_ITEM_TYPE_INT || it->data.type == MENU_ITEM_TYPE_ENUM) { uint32_t *v = it->data.value_ptr; uint32_t old_value = *v; uint32_t step = 1; if (!kbd_is_modifier(MOO_MOD_CTRL)) { step = (it->data.value_max - it->data.value_min + 9) / 10; } *v += step; if (kbd_is_modifier(MOO_MOD_ALT)) { *v = it->data.value_max; } SETMIN(*v, it->data.value_max); if (it->data.func && old_value != *v) { it->data.func(); } } else if (it->data.type == MENU_ITEM_TYPE_STR) { if (it->data.func) { it->data.func(); } } } static void main_menu_item_do_minus(struct main_menu_data_s *d, int item_i) { const struct main_menu_item_s *it = &d->items[item_i]; if (it->data.need_restart) { force_restart = true; } if (it->data.type == MENU_ITEM_TYPE_INT || it->data.type == MENU_ITEM_TYPE_ENUM) { uint32_t *v = it->data.value_ptr; uint32_t old_value = *v; uint32_t step = 1; if (!kbd_is_modifier(MOO_MOD_CTRL)) { step = (it->data.value_max - it->data.value_min + 9) / 10; } if (((*v - it->data.value_min) < step) || kbd_is_modifier(MOO_MOD_ALT)) { *v = it->data.value_min; } else { *v -= step; } if (it->data.func && old_value != *v) { it->data.func(); } } else { main_menu_item_do_plus(d, item_i); } } static main_menu_action_t main_menu_do(struct main_menu_data_s *d) { bool flag_fadein = false; d->page_stack_i = -1; d->frame = 0; d->refresh = true; d->flag_done = false; d->ret = -1; if (ui_draw_finish_mode != 0) { ui_palette_fadeout_19_19_1(); } lbxpal_select(1, -1, 0); ui_cursor_setup_area(1, &ui_cursor_area_all_i1); uiobj_table_clear(); ui_draw_erase_buf(); hw_video_copy_back_to_page2(); main_menu_push_page(d, MAIN_MENU_PAGE_MAIN); d->highlight = main_menu_get_item(d, uiobj_at_cursor()); uiobj_set_callback_and_delay(main_menu_draw_cb, d, 2); while (!d->flag_done) { int16_t oi1, oi2; ui_delay_prepare(); oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); d->highlight = main_menu_get_item(d, oi2); main_menu_draw_cb(d); d->clicked_i = main_menu_get_item(d, oi1); d->shift_i = main_menu_get_item_shift(d, oi1); d->wheel_i = main_menu_get_item_wheel(d, oi1); if ((oi1 == d->oi_plus || oi1 == d->oi_equals) && d->highlight != -1) { ui_sound_play_sfx_24(); main_menu_item_do_plus(d, d->highlight); } else if ((oi1 == d->oi_minus) && d->highlight != -1) { ui_sound_play_sfx_24(); main_menu_item_do_minus(d, d->highlight); } else if (d->wheel_i != -1) { if ((d->scrollmisc >= 0) != (ui_mwi_counter && 1) ) { ui_sound_play_sfx_24(); main_menu_item_do_plus(d, d->wheel_i); } else { ui_sound_play_sfx_24(); main_menu_item_do_minus(d, d->wheel_i); } d->scrollmisc = 0; } else if (d->clicked_i != -1) { ui_sound_play_sfx_24(); main_menu_item_do_plus(d, d->clicked_i); } else if (d->shift_i != -1) { ui_sound_play_sfx_24(); main_menu_item_do_minus(d, d->shift_i); } else if (oi1 == UIOBJI_ESC) { if (d->highlight != -1) { ui_sound_play_sfx_24(); main_menu_item_do_minus(d, d->highlight); } else { main_menu_pop_page(d); } } uiobj_finish_frame(); if ((ui_draw_finish_mode != 0) && !flag_fadein) { ui_palette_fadein_4b_19_1(); flag_fadein = true; } ui_delay_ticks_or_click(2); } uiobj_unset_callback(); return d->ret; } /* -------------------------------------------------------------------------- */ main_menu_action_t ui_main_menu(struct game_new_options_s *newopts, struct game_new_options_s *customopts, struct game_new_options_s *challengeopts, int *load_game_i_ptr) { struct main_menu_data_s d; bool flag_done = false; main_menu_action_t ret = MAIN_MENU_ACT_QUIT_GAME; uiobj_set_help_id(-1); load_mainmenu_data(&d); ui_sound_play_music(1); ui_draw_finish_mode = 1; ui_cursor_setup_area(1, &ui_cursor_area_all_i0); while (!flag_done) { ret = main_menu_do(&d); ui_draw_finish_mode = 0; switch (ret) { case MAIN_MENU_ACT_NEW_GAME: flag_done = ui_new_game(newopts); ui_draw_finish_mode = 1; break; case MAIN_MENU_ACT_CUSTOM_GAME: flag_done = ui_custom_game(customopts); ui_draw_finish_mode = 1; break; case MAIN_MENU_ACT_CHALLENGE_GAME: flag_done = ui_challenge_game(challengeopts); ui_draw_finish_mode = 1; break; case MAIN_MENU_ACT_LOAD_GAME: { int i; i = ui_load_game(); if (i >= 0) { *load_game_i_ptr = i; flag_done = true; } ui_draw_finish_mode = 1; } break; case MAIN_MENU_ACT_LOAD_GAME_MOO13: { int i; i = ui_load_game_moo13(); if (i >= 0) { *load_game_i_ptr = i; flag_done = true; } ui_draw_finish_mode = 1; } break; case MAIN_MENU_ACT_QUIT_GAME: flag_done = true; break; default: flag_done = true; break; } } ui_sound_stop_music(); /* call run_starmap_exe */ if (ret != MAIN_MENU_ACT_QUIT_GAME) { ui_palette_fadeout_19_19_1(); } free_mainmenu_data(&d); return ret; } 1oom-1.11.2/src/ui/classic/uinewgame.c000066400000000000000000000514441476061725400174450ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_ai.h" #include "game_new.h" #include "game_str.h" #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uinewgame.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "util.h" /* -------------------------------------------------------------------------- */ static const uint8_t tbl_cursor_color[] = { 0x91, 0x91, 0x8d, 0x8d, 0x89, 0x89, 0x84, 0x84, 0x7f, 0x7f }; /* -------------------------------------------------------------------------- */ struct new_game_data_s { struct game_new_options_s *newopts; int frame; bool fadein; int16_t selected; player_id_t pi; bool have_human; const char *str_title; uint8_t *gfx_newgame; uint8_t *gfx_optb_ng; uint8_t *gfx_optb_cancel; uint8_t *gfx_optb_ok; uint8_t *gfx_custom; uint8_t *gfx_flag[BANNER_NUM]; uint8_t *gfx_portrait[RACE_NUM]; char *str_tbl_2space_race[RACE_NUM + 2]; char *str_tbl_2space_banner[BANNER_NUM + 2]; }; static void new_game_load_data(struct new_game_data_s *d) { d->gfx_newgame = lbxfile_item_get(LBXFILE_VORTEX, 5); d->gfx_optb_ng = lbxfile_item_get(LBXFILE_VORTEX, 6); d->gfx_optb_cancel = lbxfile_item_get(LBXFILE_VORTEX, 0x1a); d->gfx_optb_ok = lbxfile_item_get(LBXFILE_VORTEX, 0x1b); d->gfx_custom = lbxfile_item_get(LBXFILE_VORTEX, 9); for (int i = 0; i < BANNER_NUM; ++i) { const banner_t t[BANNER_NUM] = { /* wrong order in lbx */ BANNER_GREEN, BANNER_BLUE, BANNER_RED, BANNER_WHITE, BANNER_YELLOW, BANNER_PURPLE }; d->gfx_flag[t[i]] = lbxfile_item_get(LBXFILE_VORTEX, 0xa + i); } for (int i = 0; i < RACE_NUM; ++i) { d->gfx_portrait[i] = lbxfile_item_get(LBXFILE_VORTEX, 0x10 + i); } for (int i = 0; i < RACE_NUM + 1; ++i) { d->str_tbl_2space_race[i] = util_concat(" ", game_str_tbl_race[i], NULL); } d->str_tbl_2space_race[RACE_NUM + 1] = 0; for (int i = 0; i < BANNER_NUM + 1; ++i) { d->str_tbl_2space_banner[i] = util_concat(" ", game_str_tbl_banner[i], NULL); } d->str_tbl_2space_banner[BANNER_NUM + 1] = 0; } static void new_game_free_data(struct new_game_data_s *d) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_newgame); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_optb_ng); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_optb_cancel); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_optb_ok); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_custom); for (int i = 0; i < BANNER_NUM; ++i) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_flag[i]); lib_free(d->str_tbl_2space_banner[i]); } lib_free(d->str_tbl_2space_banner[BANNER_NUM + 1]); for (int i = 0; i < RACE_NUM; ++i) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_portrait[i]); lib_free(d->str_tbl_2space_race[i]); } lib_free(d->str_tbl_2space_race[RACE_NUM + 1]); } static void new_game_draw_cb1(void *vptr) { struct new_game_data_s *d = vptr; ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, d->gfx_newgame, UI_SCREEN_W, ui_scale); } static void new_game_draw_race_cb(void *vptr) { struct new_game_data_s *d = vptr; hw_video_copy_back_from_page2(); if (d->selected < RACE_NUM) { lbxgfx_draw_frame(91, 11, d->gfx_portrait[d->selected], UI_SCREEN_W, ui_scale); lbxfont_select(0, 4, 0, 0); for (int i = 0; i < 3; ++i) { if (*game_str_tbl_traits[d->selected * 3 + i]) { lbxfont_print_str_center(0x6f, 0x35 + i * 8, game_str_tbl_traits[d->selected * 3 + i], UI_SCREEN_W, ui_scale); } } } } static int16_t ui_new_game_choose_race(struct game_new_options_s *newopts, struct new_game_data_s *d) { int16_t race; d->selected = 0; new_game_draw_race_cb(d); uiobj_finish_frame(); if (d->fadein) { d->fadein = false; ui_palette_fadein_4b_19_1(); } uiobj_set_callback_and_delay(new_game_draw_race_cb, d, 2); uiobj_table_clear(); lbxfont_select(5, 0xf, 0, 0); race = uiobj_select_from_list1(0xa, 0xa, 0x32, game_str_ng_choose_race, (char const * const *)d->str_tbl_2space_race, &d->selected, 0, 0xf, 2, true); if (race == -1) { ui_sound_play_sfx_06(); return -1; } ui_sound_play_sfx_24(); newopts->pdata[d->pi].race = race; return race; } static void new_game_draw_banner_cb(void *vptr) { struct new_game_data_s *d = vptr; race_t race = d->newopts->pdata[d->pi].race; hw_video_copy_back_from_page2(); if (d->str_title) { lbxfont_select(5, 0, 0, 0); lbxfont_print_str_normal(0xa, 0xa, d->str_title, UI_SCREEN_W, ui_scale); lbxgfx_apply_colortable(0xa, 0x14, 0x52, 0x1f, 2, UI_SCREEN_W, ui_scale); } if (race < RACE_NUM) { lbxgfx_draw_frame(91, 11, d->gfx_portrait[race], UI_SCREEN_W, ui_scale); } ui_draw_filled_rect(0x5a, 0x35, 0x83, 0x5a, 0, ui_scale); ui_draw_box1(0x5a, 0x35, 0x83, 0x5a, 0x9b, 0x9b, ui_scale); if (d->selected < BANNER_NUM) { lbxgfx_set_new_frame(d->gfx_flag[d->selected], d->frame); gfx_aux_draw_frame_to(d->gfx_flag[d->selected], &ui_data.aux.screen); gfx_aux_draw_frame_from(0x5b, 0x38, &ui_data.aux.screen, UI_SCREEN_W, ui_scale); } if (++d->frame == 0xa) { d->frame = 0; } } static int16_t ui_new_game_choose_banner(struct game_new_options_s *newopts, struct new_game_data_s *d) { int16_t banner; d->selected = 0; d->frame = 0; d->str_title = 0; uiobj_table_clear(); uiobj_set_callback_and_delay(new_game_draw_banner_cb, d, 2); lbxfont_select(5, 0xf, 0, 0); banner = uiobj_select_from_list1(0xa, 0xa, 0x32, game_str_ng_choose_banner, (char const * const *)d->str_tbl_2space_banner, &d->selected, 0, 0xf, 2, true); if (banner == -1) { ui_sound_play_sfx_06(); return -1; } ui_sound_play_sfx_24(); newopts->pdata[d->pi].banner = banner; return banner; } static bool ui_new_game_pname(struct game_new_options_s *newopts, struct new_game_data_s *d, bool flag_generate) { char buf[32]; bool flag_ok; if (!flag_generate) { lib_strcpy(buf, newopts->pdata[d->pi].playername, sizeof(buf)); flag_generate = (buf[0] == '\0'); } uiobj_set_callback_and_delay(new_game_draw_banner_cb, d, 2); d->str_title = game_str_ng_your_name; uiobj_table_clear(); flag_ok = false; while (!flag_ok) { lbxfont_select(5, 0xf, 0xf, 0xf); if (flag_generate) { game_new_generate_emperor_name(d->newopts->pdata[d->pi].race, buf, sizeof(buf)); } if (!uiobj_read_str(0xf, 0x16, 0x41, buf, 0xb/*len*/, 0, 0, tbl_cursor_color)) { return false; } util_trim_whitespace(buf, sizeof(buf)); flag_ok = buf[0] != '\0'; flag_generate = true; } lib_strcpy(newopts->pdata[d->pi].playername, buf, EMPEROR_NAME_LEN); ui_sound_play_sfx_24(); return true; } static bool ui_new_game_hname(struct game_new_options_s *newopts, struct new_game_data_s *d, bool flag_generate) { char buf[32]; bool flag_ok; if (!flag_generate) { lib_strcpy(buf, newopts->pdata[d->pi].homename, sizeof(buf)); flag_generate = (buf[0] == '\0'); } uiobj_set_callback_and_delay(new_game_draw_banner_cb, d, 2); d->str_title = game_str_ng_home_name; uiobj_table_clear(); flag_ok = false; while (!flag_ok) { lbxfont_select(5, 0xf, 0xf, 0xf); if (flag_generate) { game_new_generate_home_name(d->newopts->pdata[d->pi].race, buf, sizeof(buf)); } if (!uiobj_read_str(0xf, 0x16, 0x32, buf, PLANET_NAME_LEN, 0, 0, tbl_cursor_color)) { return false; } util_trim_whitespace(buf, sizeof(buf)); flag_ok = buf[0] != '\0'; flag_generate = true; } lib_strcpy(newopts->pdata[d->pi].homename, buf, PLANET_NAME_LEN); ui_sound_play_sfx_24(); lbxfont_select(5, 1, 0xf, 0xf); return true; } static bool ui_new_game_racebannernames(struct game_new_options_s *newopts, struct new_game_data_s *d) { d->pi = PLAYER_0; /* orion.exe inits game->offs02 and game_new:researchflag here for whatever reason */ uiobj_table_clear(); ui_palette_fadeout_19_19_1(); d->fadein = true; lbxpal_select(4, -1, 0); lbxpal_build_colortables(); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, d->gfx_custom, UI_SCREEN_W, ui_scale); ui_draw_box1(0x5a, 0xa, 0x83, 0x2d, 0x9b, 0x9b, ui_scale); hw_video_copy_back_to_page2(); if (0 || (ui_new_game_choose_race(newopts, d) < 0) || (ui_new_game_choose_banner(newopts, d) < 0) || (!ui_new_game_pname(newopts, d, true)) || (!ui_new_game_hname(newopts, d, true)) ) { return false; } return true; } /* -------------------------------------------------------------------------- */ static void new_game_draw_extra_cb(void *vptr) { struct new_game_data_s *d = vptr; struct game_new_options_s *newopts = d->newopts; hw_video_copy_back_from_page3(); lbxfont_select(5, 0, 0, 0); for (player_id_t i = 0; i < d->newopts->players; ++i) { int x0 = 4 + (i / 3) * 160; int y0 = 20 + (i % 3) * 50; if (newopts->pdata[i].race < RACE_NUM) { lbxgfx_draw_frame(x0 + 1, y0 + 1, d->gfx_portrait[newopts->pdata[i].race], UI_SCREEN_W, ui_scale); } if (newopts->pdata[i].banner < BANNER_NUM) { lbxgfx_set_new_frame(d->gfx_flag[newopts->pdata[i].banner], d->frame); gfx_aux_draw_frame_to(d->gfx_flag[newopts->pdata[i].banner], &ui_data.aux.screen); gfx_aux_draw_frame_from(x0 + 43 + 1, y0 + 1, &ui_data.aux.screen, UI_SCREEN_W, ui_scale); } lbxfont_print_str_normal(x0 + 43 + 41 + 2, y0 + 2 , d->newopts->pdata[i].playername, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x0 + 43 + 41 + 2, y0 + 2 + 11, d->newopts->pdata[i].homename, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x0 + 43 + 41 + 2, y0 + 2 + 22, d->newopts->pdata[i].is_ai ? game_str_ng_computer : game_str_ng_player, UI_SCREEN_W, ui_scale); } if (!d->have_human) { lbxfont_print_str_center(160, 2, game_str_ng_allai, UI_SCREEN_W, ui_scale); } if (++d->frame >= 10) { d->frame = 0; } } static bool ui_new_game_extra(struct game_new_options_s *newopts, struct new_game_data_s *d) { bool flag_done = false, flag_ok = false; int16_t oi_cancel, oi_ok, oi_race[PLAYER_NUM], oi_banner[PLAYER_NUM], oi_pname[PLAYER_NUM], oi_hname[PLAYER_NUM], oi_ai[PLAYER_NUM]; d->pi = PLAYER_0; d->str_title = 0; d->frame = 0; d->have_human = false; for (int i = 0; i < newopts->players; ++i) { if (!newopts->pdata[i].is_ai) { d->have_human = true; break; } } for (int i = 0; i < newopts->players; ++i) { if (newopts->pdata[i].race != RACE_RANDOM) { if (!strlen(newopts->pdata[i].playername)) { game_new_generate_emperor_name(newopts->pdata[i].race, newopts->pdata[i].playername, EMPEROR_NAME_LEN); } if (!strlen(newopts->pdata[i].homename)) { game_new_generate_home_name(newopts->pdata[i].race, newopts->pdata[i].homename, PLANET_NAME_LEN); } } } uiobj_table_clear(); ui_palette_fadeout_19_19_1(); d->fadein = true; lbxpal_select(4, -1, 0); lbxpal_build_colortables(); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, d->gfx_custom, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page3(); ui_draw_box1(0x5a, 0xa, 0x83, 0x2d, 0x9b, 0x9b, ui_scale); hw_video_copy_back_to_page2(); hw_video_copy_back_from_page3(); for (int i = 0; i < newopts->players; ++i) { int x0 = 4 + (i / 3) * 160; int y0 = 20 + (i % 3) * 50; ui_draw_box1(x0, y0, x0 + 41, y0 + 35, 0x9b, 0x9b, ui_scale); ui_draw_filled_rect(x0 + 43, y0, x0 + 43 + 41, y0 + 35, 0, ui_scale); ui_draw_box1(x0 + 43, y0, x0 + 43 + 41, y0 + 35, 0x9b, 0x9b, ui_scale); } lbxfont_select(5, 0, 0, 0); lbxfont_print_str_center(40, 180, game_str_ng_cancel, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(260, 180, game_str_ng_ok, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page3(); #define MAKE_UIOBJS() \ do { \ uiobj_table_clear(); \ oi_cancel = uiobj_add_mousearea(0, 170, 80, 199, MOO_KEY_ESCAPE); \ oi_ok = uiobj_add_mousearea(220, 170, 300, 199, MOO_KEY_SPACE); \ for (int i = 0; i < newopts->players; ++i) { \ int x0 = 4 + (i / 3) * 160; \ int y0 = 20 + (i % 3) * 50; \ oi_race[i] = uiobj_add_mousearea(x0, y0, x0 + 41, y0 + 35, MOO_KEY_UNKNOWN); \ oi_banner[i] = uiobj_add_mousearea(x0 + 43, y0, x0 + 43 + 41, y0 + 35, MOO_KEY_UNKNOWN); \ oi_pname[i] = uiobj_add_mousearea(x0 + 43 + 41 + 2, y0 + 2, x0 + 43 + 41 + 2 + 60, y0 + 2 + 10, MOO_KEY_UNKNOWN); \ oi_hname[i] = uiobj_add_mousearea(x0 + 43 + 41 + 2, y0 + 2 + 11, x0 + 43 + 41 + 2 + 60, y0 + 2 + 11 + 10, MOO_KEY_UNKNOWN); \ oi_ai[i] = uiobj_add_mousearea(x0 + 43 + 41 + 2, y0 + 2 + 22, x0 + 43 + 41 + 2 + 60, y0 + 2 + 22 + 10, MOO_KEY_UNKNOWN); \ } \ for (int i = newopts->players; i < PLAYER_NUM; ++i) { \ oi_race[i] = UIOBJI_INVALID; \ oi_banner[i] = UIOBJI_INVALID; \ oi_pname[i] = UIOBJI_INVALID; \ oi_hname[i] = UIOBJI_INVALID; \ oi_ai[i] = UIOBJI_INVALID; \ } \ } while (0) MAKE_UIOBJS(); uiobj_set_callback_and_delay(new_game_draw_extra_cb, d, 2); uiobj_set_xyoff(1, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi != UIOBJI_ESC) && (oi != UIOBJI_NONE) && (oi != oi_cancel)) { ui_sound_play_sfx_24(); } if ((oi == UIOBJI_ESC) || (oi == oi_cancel)) { ui_sound_play_sfx_06(); flag_ok = false; flag_done = true; } else if (oi == oi_ok) { if (d->have_human) { flag_ok = true; flag_done = true; } } for (int i = 0; i < newopts->players; ++i) { if (oi == oi_race[i]) { race_t old_race, new_race; old_race = newopts->pdata[i].race; d->pi = i; ui_new_game_choose_race(newopts, d); new_race = newopts->pdata[i].race; if (new_race != old_race) { if (new_race < RACE_NUM) { game_new_generate_emperor_name(new_race, newopts->pdata[i].playername, EMPEROR_NAME_LEN); game_new_generate_home_name(new_race, newopts->pdata[i].homename, PLANET_NAME_LEN); } else { newopts->pdata[i].playername[0] = '\0'; newopts->pdata[i].homename[0] = '\0'; } } uiobj_set_callback_and_delay(new_game_draw_extra_cb, d, 2); } else if (oi == oi_banner[i]) { d->pi = i; d->selected = newopts->pdata[i].banner; ui_new_game_choose_banner(newopts, d); uiobj_set_callback_and_delay(new_game_draw_extra_cb, d, 2); } else if (oi == oi_pname[i]) { d->pi = i; d->selected = newopts->pdata[i].banner; ui_new_game_pname(newopts, d, false); uiobj_set_callback_and_delay(new_game_draw_extra_cb, d, 2); } else if (oi == oi_hname[i]) { d->pi = i; d->selected = newopts->pdata[i].banner; ui_new_game_hname(newopts, d, false); uiobj_set_callback_and_delay(new_game_draw_extra_cb, d, 2); } else if (oi == oi_ai[i]) { newopts->pdata[i].is_ai = !newopts->pdata[i].is_ai; d->have_human = false; for (int j = 0; j < newopts->players; ++j) { if (!newopts->pdata[j].is_ai) { d->have_human = true; break; } } } } new_game_draw_extra_cb(d); MAKE_UIOBJS(); uiobj_finish_frame(); if (d->fadein) { d->fadein = false; ui_palette_fadein_4b_19_1(); } ui_delay_ticks_or_click(2); } #undef MAKE_UIOBJS return flag_ok; } /* -------------------------------------------------------------------------- */ bool ui_new_game(struct game_new_options_s *newopts) { struct new_game_data_s d; bool flag_done = false, flag_fadein = false, flag_ok = false; uint16_t oppon = 0, gsize = 0, diffic = 0; int16_t oi_gsize, oi_diffic, oi_oppon, oi_cancel, oi_ok; int16_t oi_esc, oi_d, oi_g, oi_o, oi_space; d.newopts = newopts; gsize = newopts->galaxy_size; diffic = newopts->difficulty; oppon = newopts->players - 1/*0-based*/ - 1/*player*/; ui_palette_fadeout_19_19_1(); lbxpal_select(3, -1, 0); lbxpal_build_colortables(); new_game_load_data(&d); #define MAKE_UIOBJS() \ do { \ lbxfont_select(0, 0, 0, 0); \ uiobj_table_clear(); \ oi_esc = uiobj_add_inputkey(MOO_KEY_ESCAPE); \ oi_gsize = uiobj_add_t0(0xaf, 0x1d, game_str_tbl_gsize[gsize], d.gfx_optb_ng, MOO_KEY_UNKNOWN); \ oi_diffic = uiobj_add_t0(0xaf, 0x44, game_str_tbl_diffic[diffic], d.gfx_optb_ng, MOO_KEY_UNKNOWN); \ oi_oppon = uiobj_add_t0(0xaf, 0x6b, game_str_tbl_oppon[oppon], d.gfx_optb_ng, MOO_KEY_UNKNOWN); \ oi_cancel = uiobj_add_t0(0x5a, 0x93, "", d.gfx_optb_cancel, MOO_KEY_UNKNOWN); \ oi_ok = uiobj_add_t0(0xa1, 0x93, "", d.gfx_optb_ok, MOO_KEY_UNKNOWN); \ oi_d = uiobj_add_inputkey(MOO_KEY_d); \ oi_g = uiobj_add_inputkey(MOO_KEY_g); \ oi_o = uiobj_add_inputkey(MOO_KEY_o); \ oi_space = uiobj_add_inputkey(MOO_KEY_SPACE); \ } while (0) MAKE_UIOBJS(); uiobj_set_callback_and_delay(new_game_draw_cb1, &d, 2); uiobj_set_xyoff(1, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi != UIOBJI_ESC) && (oi != UIOBJI_NONE)) { ui_sound_play_sfx_24(); } if ((oi == UIOBJI_ESC) || (oi == oi_cancel)) { ui_sound_play_sfx_06(); } if ((oi == oi_diffic) || (oi == oi_d)) { if (++diffic >= 5) { diffic = 0; } } if ((oi == oi_gsize) || (oi == oi_g)) { if (++gsize >= 4) { gsize = 0; } } if ((oi == oi_oppon) || (oi == oi_o)) { if (++oppon >= 5) { oppon = 0; } } if ((oi == UIOBJI_ESC) || (oi == oi_cancel) || (oi == oi_esc)) { flag_ok = false; flag_done = true; } if ((oi == oi_ok) || (oi == oi_space)) { flag_ok = true; flag_done = true; } new_game_draw_cb1(&d); MAKE_UIOBJS(); uiobj_finish_frame(); if (!flag_fadein) { ui_palette_fadein_4b_19_1(); flag_fadein = true; } ui_delay_ticks_or_click(2); } #undef MAKE_UIOBJS newopts->galaxy_size = gsize; newopts->difficulty = diffic; newopts->players = oppon + 1/*0-based*/ + 1/*player*/; uiobj_unset_callback(); if (flag_ok) { flag_ok = ui_new_game_racebannernames(newopts, &d); } uiobj_unset_callback(); new_game_free_data(&d); return flag_ok; } bool ui_custom_game(struct game_new_options_s *newopts) { struct new_game_data_s d; bool flag_ok = false; d.newopts = newopts; new_game_load_data(&d); flag_ok = ui_new_game_extra(newopts, &d); new_game_free_data(&d); return flag_ok; } bool ui_challenge_game(struct game_new_options_s *newopts) { static const struct game_new_options_s challenge = GAME_NEW_OPTS_CHALLENGE_118835000; struct new_game_data_s d; bool flag_ok = false; d.newopts = newopts; *d.newopts = challenge; new_game_load_data(&d); flag_ok = ui_new_game_racebannernames(newopts, &d); uiobj_unset_callback(); new_game_free_data(&d); if (d.newopts->pdata[0].race == RACE_MRRSHAN) { d.newopts->pdata[1].race = RACE_ALKARI; } if (d.newopts->pdata[0].race == RACE_SAKKRA) { d.newopts->pdata[2].race = RACE_MEKLAR; } if (d.newopts->pdata[0].race == RACE_PSILON) { d.newopts->pdata[3].race = RACE_HUMAN; } if (d.newopts->pdata[0].race == RACE_KLACKON) { d.newopts->pdata[4].race = RACE_MEKLAR; } if (d.newopts->pdata[0].race == RACE_SILICOID) { d.newopts->pdata[5].race = RACE_HUMAN; } return flag_ok; } 1oom-1.11.2/src/ui/classic/uinewgame.h000066400000000000000000000005211476061725400174400ustar00rootroot00000000000000#ifndef INC_1OOM_UINEWGAME_H #define INC_1OOM_UINEWGAME_H #include "types.h" struct game_new_options_s; /* returns false on cancel */ extern bool ui_new_game(struct game_new_options_s *newopts); extern bool ui_custom_game(struct game_new_options_s *newopts); extern bool ui_challenge_game(struct game_new_options_s *newopts); #endif 1oom-1.11.2/src/ui/classic/uinews.c000066400000000000000000000253731476061725400170000ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game_news.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uinews.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct news_data_s { int frame; struct news_s *ns; const char *str; }; /* -------------------------------------------------------------------------- */ static void news_free_data(void) { if (ui_data.gfx.news.icon != 0) { lbxfile_item_release(LBXFILE_NEWSCAST, ui_data.gfx.news.icon); ui_data.gfx.news.icon = 0; } } static void news_load_data(news_type_t type) { if (!ui_data.news.flag_also) { news_free_data(); lbxgfx_set_frame_0(ui_data.gfx.news.nc); lbxgfx_set_frame_0(ui_data.gfx.news.world); lbxgfx_set_frame_0(ui_data.gfx.news.gnn); } if (type != GAME_NEWS_NONE) { ui_data.gfx.news.icon = lbxfile_item_get(LBXFILE_NEWSCAST, 3 + (int)type); } else { news_free_data(); } } static void ui_news_cb1(void *vptr) { struct news_data_s *d = vptr; ui_draw_filled_rect(32, 142, 287, 182, 0, ui_scale); ui_draw_filled_rect(34, 184, 285, 191, 0, ui_scale); ui_draw_line1(33, 182, 286, 182, 0, ui_scale); ui_draw_line1(32, 183, 287, 183, 0, ui_scale); { uint8_t *gfx = ui_data.gfx.news.nc; int fn = lbxgfx_get_frame(gfx); lbxgfx_set_frame_0(gfx); for (int f = 0; f <= fn; ++f) { lbxgfx_draw_frame(14, 14, gfx, UI_SCREEN_W, ui_scale); } } if (ui_data.gfx.news.icon != 0) { lbxgfx_draw_frame(208, 38, ui_data.gfx.news.icon, UI_SCREEN_W, ui_scale); } { uint8_t *gfx = ui_data.gfx.news.world; int fn = lbxgfx_get_frame(gfx); lbxgfx_set_frame_0(gfx); for (int f = 0; f <= fn; ++f) { lbxgfx_draw_frame(76, 36, gfx, UI_SCREEN_W, ui_scale); } } lbxfont_select(3, 1, 0, 0); ui_draw_filled_rect(38, 145, 284, 190, 0, ui_scale); lbxfont_set_space_w(2); lbxfont_print_str_split(38, 145, 245, d->str, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); if (d->ns->type == GAME_NEWS_STATS) { lbxfont_select(3, 1, 0, 0); for (int i = 0; i < d->ns->statsnum; ++i) { char buf[5]; int x, y; x = 48 + (i / 3) * 122; y = 157 + (i % 3) * 10; lib_sprintf(buf, sizeof(buf), "%i.", i + 1); lbxfont_print_str_right(x, y, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(x + 7, y, d->ns->stats[i], UI_SCREEN_W, ui_scale); } } ++d->frame; } static void ui_news_draw_start_anim(void) { int frame; ui_delay_1(); ui_sound_stop_music(); uiobj_table_clear(); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, ui_data.gfx.news.tv, UI_SCREEN_W, ui_scale); uiobj_finish_frame(); ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, ui_data.gfx.news.tv, UI_SCREEN_W, ui_scale); ui_sound_play_music(9); frame = 0; while (frame < 25) { ui_delay_prepare(); if (frame > 0) { uint16_t f; f = lbxgfx_get_frame(ui_data.gfx.news.gnn) - 1; lbxgfx_set_new_frame(ui_data.gfx.news.gnn, f); lbxgfx_draw_frame(14, 14, ui_data.gfx.news.gnn, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame(14, 14, ui_data.gfx.news.gnn, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(32, 142, 287, 182, 0xc1, ui_scale); ui_draw_filled_rect(34, 184, 285, 191, 0xc1, ui_scale); ui_draw_line1(33, 182, 286, 182, 0xc1, ui_scale); ui_draw_line1(32, 183, 287, 183, 0xc1, ui_scale); ui_draw_finish(); ui_delay_ticks_or_click(1); ++frame; } } /* -------------------------------------------------------------------------- */ static uint8_t ui_news_fade_tbl_xoff[] = { 2, 2, 2, 1, 1, 3, 0, 3, 3, 2, 0, 1, 3, 3, 1, 3, 3, 0, 3, 1, 2, 3, 0, 2, 1, 1, 2, 2, 1, 1, 3, 3, 2, 3, 3, 0, 2, 3, 0, 2, 0, 3, 2, 0, 2, 0, 0, 3, 1, 0, 1, 1, 1, 3, 3, 1, 1, 0, 0, 2, 1, 1, 2, 1, 0, 0, 0, 3, 3, 1, 1, 2, 2, 1, 2, 2, 0, 2, 3, 1, 2, 2, 2, 0, 0, 0, 1, 1, 0, 2, 0, 3, 2, 2, 1, 0, 3, 1, 2, 3, 0, 0, 1, 0, 2, 2, 3, 2, 1, 1, 2, 2, 0, 3, 0, 0, 2, 0, 0, 3, 3, 1, 2, 1, 0, 0, 1, 3, 1, 1, 1, 0, 0, 2, 3, 1, 0, 3, 3, 0, 1, 0, 0, 0, 1, 3, 1, 3, 3, 2, 2, 3, 2, 0, 1, 1, 0, 3, 0, 2, 0, 2, 1, 1, 3, 1, 2, 1, 3, 1, 0, 1, 3, 3, 1, 1, 3, 2, 3, 2, 3, 1, 1, 2, 0, 2, 3, 3, 2, 2, 0, 2, 3, 3, 3, 2, 2, 0, 2, 0, 1, 0, 1, 3, 2, 1, 2, 2, 0, 1, 0, 2, 1, 1, 3, 0, 3, 3, 3, 0, 3, 0, 2, 1, 1, 0, 0, 2, 1, 2, 3, 3, 1, 0, 1, 3, 0, 2, 3, 0, 2, 1, 2, 3, 0, 2, 2, 0, 2, 3, 1, 0, 3, 3, 3, 0 }; static uint8_t ui_news_fade_tbl_line[] = { 0, 3, 30, 18, 28, 22, 29, 12, 34, 47, 31, 32, 7, 49, 46, 14, 38, 43, 35, 40, 11, 9, 36, 4, 33, 26, 39, 15, 5, 21, 2, 16, 25, 10, 48, 13, 24, 37, 17, 19, 44, 6, 8, 20, 1, 23, 41, 27, 45, 42 }; static uint8_t ui_news_fade_tbl_col[] = { 2, 9, 30, 38, 13, 27, 31, 1, 19, 8, 24, 36, 37, 26, 0, 11, 23, 32, 22, 12, 16, 20, 29, 18, 28, 7, 10, 35, 14, 25, 5, 33, 15, 21, 4, 17, 6, 3, 39, 34 }; static inline void ui_news_fade_plot(uint8_t *pb, uint8_t *pf, int si, uint8_t ah) { if (ui_scale == 1) { pf[si * 4 + ah] = pb[si * 4 + ah]; } else { pf += (si * 4 + ah) * ui_scale; pb += (si * 4 + ah) * ui_scale; for (int y = 0; y < ui_scale; ++y) { for (int x = 0; x < ui_scale; ++x) { pf[x] = pb[x]; } pf += UI_SCREEN_W; pb += UI_SCREEN_W; } } } #define UI_NEWS_FADE_PIXELS_PER_FRAME 12000 static void ui_news_fade(void) { int pixelcount = UI_NEWS_FADE_PIXELS_PER_FRAME; uint8_t *pb, *pf; pb = hw_video_get_buf(); pf = hw_video_get_buf_front(); for (int loops = 4; loops > 0; --loops) { int we0; we0 = (loops - 1) << 6; for (int wde = 39; wde >= 0; --wde) { for (int we2 = 49; we2 >= 0; --we2) { int dx, v, si; uint8_t bl, ah; v = dx = ui_news_fade_tbl_line[we2]; si = v * UI_SCREEN_W / 4; v += wde; if (v >= 40) { v -= 40; if (v >= 40) { v -= 40; } } v = ui_news_fade_tbl_col[v]; bl = v; si += v * 2; bl += dx + we0; ah = ui_news_fade_tbl_xoff[bl++]; ui_news_fade_plot(pb, pf, si, ah); si += 8000; ui_news_fade_plot(pb, pf, si, ah); si -= 4000; ui_news_fade_plot(pb, pf, si, ah); si += 8000; ui_news_fade_plot(pb, pf, si, ah); si -= 12000; ah = ui_news_fade_tbl_xoff[bl++]; ui_news_fade_plot(pb, pf, si, ah); si += 8000; ui_news_fade_plot(pb, pf, si, ah); si -= 4000; ui_news_fade_plot(pb, pf, si, ah); si += 8000; ui_news_fade_plot(pb, pf, si, ah); pixelcount -= 8; if (pixelcount <= 0) { pixelcount = UI_NEWS_FADE_PIXELS_PER_FRAME; hw_video_redraw_front(); ui_delay_1(); } } } } memcpy(pf, pb, UI_SCREEN_W * UI_SCREEN_H); hw_video_redraw_front(); ui_delay_1(); } /* -------------------------------------------------------------------------- */ void ui_news_won(bool flag_good) { bool flag_skip = false, flag_fade; struct news_data_s d; struct news_s ns; lbxpal_select(0, -1, 0); lbxpal_set_update_range(0, 255); ui_draw_finish_mode = 2; d.str = flag_good ? game_str_gnn_end_good : game_str_gnn_end_tyrant; d.ns = &ns; ns.type = GAME_NEWS_NONE; news_load_data(GAME_NEWS_NONE); ui_news_draw_start_anim(); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(1); uiobj_set_callback_and_delay(ui_news_cb1, &d, 3); flag_fade = true; d.frame = 0; for (int i = 0; (i < 0x46) && !flag_skip; ++i) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_skip = true; break; } ui_news_cb1(&d); ui_delay_ticks_or_click(3); if (flag_fade) { ui_news_fade(); } else { ui_draw_finish(); } flag_fade = false; } hw_audio_music_fadeout(); uiobj_unset_callback(); ui_data.news.flag_also = false; } void ui_news(struct game_s *g, struct news_s *ns) { bool flag_skip = false, flag_fade; struct news_data_s d; ui_switch_all(g); d.ns = ns; if (!ui_data.news.flag_also) { if (ui_draw_finish_mode == 0) { ui_palette_fadeout_a_f_1(); } ui_draw_finish_mode = 2; ui_news_draw_start_anim(); flag_fade = true; } else { d.str = game_str_gnn_also; for (int i = 0; (i < 5) && !flag_skip; ++i) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_skip = true; } if (!flag_skip) { ui_news_cb1(&d); ui_delay_ticks_or_click(3); ui_draw_finish(); } } flag_fade = false; } game_news_get_msg(g, ns, ui_data.strbuf, UI_STRBUF_SIZE); d.str = ui_data.strbuf; news_load_data(ns->type); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); uiobj_set_downcount(1); uiobj_set_callback_and_delay(ui_news_cb1, &d, 3); flag_skip = false; while (!flag_skip) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_skip = true; break; } ui_news_cb1(&d); ui_delay_ticks_or_click(3); if (flag_fade) { ui_news_fade(); } else { ui_draw_finish(); } flag_fade = false; } ui_data.news.flag_also = true; ui_sound_stop_music(); uiobj_unset_callback(); uiobj_table_clear(); } void ui_news_start(void) { ui_data.news.flag_also = false; } void ui_news_end(void) { if (ui_data.news.flag_also) { ui_data.news.flag_also = false; ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; } } 1oom-1.11.2/src/ui/classic/uinews.h000066400000000000000000000001721476061725400167730ustar00rootroot00000000000000#ifndef INC_1OOM_UINEWS_H #define INC_1OOM_UINEWS_H #include "types.h" extern void ui_news_won(bool flag_good); #endif 1oom-1.11.2/src/ui/classic/uinewships.c000066400000000000000000000070531476061725400176570ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uigmap.h" #include "uilanding.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct newships_data_s { struct game_s *g; player_id_t api; uint8_t *gfx_newship; struct starmap_data_s sm; }; static void newships_load_data(struct newships_data_s *d) { d->gfx_newship = lbxfile_item_get(LBXFILE_BACKGRND, 0x14); } static void newships_free_data(struct newships_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_newship); } static void newships_draw_cb(void *vptr) { struct newships_data_s *d = vptr; const struct game_s *g = d->g; int x = 38, y = 27; char buf[0x20]; ui_starmap_draw_basic(&d->sm); ui_draw_filled_rect(x, y, x + 151, y + 128, 0x2b, ui_scale); lbxgfx_draw_frame(x, y, d->gfx_newship, UI_SCREEN_W, ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_set_color_c_n(0x49, 5); lib_sprintf(buf, sizeof(buf), "%s%i", game_str_year, g->year + YEAR_BASE); lbxfont_print_str_center(x + 76, y + 9, buf, UI_SCREEN_W, ui_scale); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { shipsum_t n; n = g->evn.new_ships[d->api][i]; if (n != 0) { const shipdesign_t *sd = &(g->srd[d->api].design[i]); uint8_t *gfx; int x0, y0; x0 = x + 8 + (i % 3) * 48; y0 = y + 35 + (i / 3) * 47; ui_draw_filled_rect(x0, y0, x0 + 39, y0 + 39, 0, ui_scale); ui_draw_filled_rect(x0, y0 + 31, x0 + 39, y0 + 39, 0xe9, ui_scale); ui_draw_line1(x0, y0 + 30, x0 + 39, y0 + 30, 0x5c, ui_scale); lbxfont_select(2, 0, 0, 0); lbxfont_print_str_center(x0 + 20, y0 + 33, sd->name, UI_SCREEN_W, ui_scale); ui_draw_stars(x0, y0 + 2, i * 10, 40, ui_scale); gfx = ui_data.gfx.ships[sd->look]; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x0 + 4, y0 + 3, gfx, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(x0 + 36, y0 + 23, n, UI_SCREEN_W, ui_scale); } } ui_draw_set_stars_xoffs(false); } /* -------------------------------------------------------------------------- */ void ui_newships(struct game_s *g, int pi) { struct newships_data_s d; bool flag_done = false; int tempnum; tempnum = g->evn.build_finished_num[pi]; g->evn.build_finished_num[pi] = 0; ui_switch_1(g, pi); d.g = g; d.api = pi; ui_starmap_common_init(g, &d.sm, pi); d.sm.bottom_highlight = -1; newships_load_data(&d); uiobj_set_callback_and_delay(newships_draw_cb, &d, 4); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } if (!flag_done) { newships_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } } ui_sound_play_sfx_24(); ui_delay_1(); uiobj_unset_callback(); uiobj_table_clear(); newships_free_data(&d); g->evn.build_finished_num[pi] = tempnum; } 1oom-1.11.2/src/ui/classic/uinewtech.c000066400000000000000000000512731476061725400174570ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_diplo.h" #include "game_planet.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "game_tech.h" #include "game_techtypes.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct newtech_data_s { struct game_s *g; player_id_t api; uint8_t *gfx_lab; uint8_t *gfx_tech; uint8_t *gfx_spies; uint8_t *gfx_framing; uint8_t *gfx_pulldown_u; uint8_t *gfx_pulldown_d; uint8_t *gfx_eco_chng2; uint8_t *gfx_eco_chng4; uint8_t *gfx_robo_but; newtech_t nt; uint8_t music_i; int cur_source; uint8_t anim; uint8_t dialog_type; bool flag_fadeout; bool flag_music; bool flag_is_current; bool flag_choose_next; uint8_t tech_next[TECH_NEXT_MAX]; int num_next; int16_t selected; int16_t tbl_tech[TECH_NEXT_MAX + 1]; }; static const uint8_t newtech_music_tbl[6] = { 5, 6, 7, 5, 5, 5 }; static void newtech_load_data(struct newtech_data_s *d) { d->gfx_framing = lbxfile_item_get(LBXFILE_BACKGRND, 9); d->gfx_pulldown_u = lbxfile_item_get(LBXFILE_BACKGRND, 0x1a); d->gfx_pulldown_d = lbxfile_item_get(LBXFILE_BACKGRND, 0x1b); d->gfx_eco_chng2 = lbxfile_item_get(LBXFILE_BACKGRND, 0x1f); d->gfx_eco_chng4 = lbxfile_item_get(LBXFILE_BACKGRND, 0x30); d->gfx_robo_but = lbxfile_item_get(LBXFILE_BACKGRND, 0x31); d->gfx_spies = 0; } static void newtech_free_data(struct newtech_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_framing); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_pulldown_u); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_pulldown_d); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_eco_chng2); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_eco_chng4); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_robo_but); if (d->gfx_spies) { lbxfile_item_release(LBXFILE_SPIES, d->gfx_spies); } } static void newtech_draw_cb1(void *vptr) { struct newtech_data_s *d = vptr; struct game_s *g = d->g; char *buf = ui_data.strbuf; hw_video_copy_back_from_page2(); { int frame = lbxgfx_get_frame(d->gfx_spies); lbxgfx_set_frame_0(d->gfx_spies); for (int f = 0; f <= frame; ++f) { lbxgfx_draw_frame(0, 0, d->gfx_spies, UI_SCREEN_W, ui_scale); } if ((d->anim = (d->anim + 1) % 3) != 0) { lbxgfx_set_new_frame(d->gfx_spies, frame); } } game_tech_get_newtech_msg(g, d->api, &(d->nt), buf, UI_STRBUF_SIZE); lbxfont_select_set_12_4(5, 5, 0, 0); lbxfont_print_str_center(161, 7, buf, UI_SCREEN_W, ui_scale); if (d->nt.source != TECHSOURCE_CHOOSE) { int strh, y; char *p, c; game_tech_get_name(d->g->gaux, d->nt.field, d->nt.tech, buf, UI_STRBUF_SIZE); p = buf; while ((c = *p) != 0) { if (islower(c)) { *p = toupper(c); } ++p; } lbxfont_select_set_12_4(5, 8, 0, 0); lbxfont_print_str_center(160, 32, buf, UI_SCREEN_W, ui_scale); game_tech_get_descr(d->g->gaux, d->nt.field, d->nt.tech, buf, UI_STRBUF_SIZE); lbxfont_select_set_12_5(4, 0xf, 0, 0); strh = lbxfont_calc_split_str_h(305, buf); /* BUG? Some lowercase letters extend past the screen, for example 'p' in the Hyper-X msg. On DOS/v1.3 this only overwrites unused VRAM. y <= 148 would be OK. In this version of 1oom, the video buffer does not contain padding, which can lead to small visible artifacts. */ y = (strh >= 36) ? 150 : 160; lbxfont_print_str_split(9, y, 305, buf, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } if (d->nt.frame) { /*ui_newtech_draw_frame:*/ ui_draw_filled_rect(31, 62, 202, 125, 0xfb, ui_scale); ui_draw_filled_rect(37, 68, 196, 91, 0x04, ui_scale); lbxgfx_draw_frame(31, 62, d->gfx_framing, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(50, 106, 110, 120, 0x00, ui_scale); ui_draw_filled_rect(51, 107, 109, 119, tbl_banner_color2[g->eto[d->nt.other1].banner], ui_scale); ui_draw_filled_rect(122, 106, 183, 120, 0x00, ui_scale); ui_draw_filled_rect(123, 107, 182, 119, tbl_banner_color2[g->eto[d->nt.other2].banner], ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_print_str_center(80, 110, game_str_tbl_races[g->eto[d->nt.other1].race], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(152, 110, game_str_tbl_races[g->eto[d->nt.other2].race], UI_SCREEN_W, ui_scale); lbxfont_select(5, 0, 0, 0); lbxfont_set_gap_h(2); lbxfont_print_str_split(40, 70, 154, game_str_nt_frame, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxfont_select(0, 0, 0, 0); lbxfont_print_str_center(115, 96, game_str_nt_victim, UI_SCREEN_W, ui_scale); } } static void newtech_choose_next_draw_cb(void *vptr) { struct newtech_data_s *d = vptr; char buf[RESEARCH_DESCR_LEN + 20]; int x = 145, y = 30, yo, pos; uint8_t tech = d->tbl_tech[d->selected]; uint32_t cost; d->nt.source = TECHSOURCE_CHOOSE; newtech_draw_cb1(d); yo = ((d->num_next > 10) ? 8 : 9) * d->num_next + 8; SETMAX(yo, 30); ui_draw_filled_rect(x, y, x + 165, y + yo + 12, 0xf9, ui_scale); lbxgfx_draw_frame_offs(x, y, d->gfx_pulldown_u, 0, y, UI_VGA_W - 1, y + yo - 1, UI_SCREEN_W, ui_scale); /* WASBUG MOO1 does not limit the bottom part which will go below screen with enough techs to choose from. On DOS/v1.3 this only overwrite unused VRAM. We must the the _offs version. */ lbxgfx_draw_frame_offs(x, y + yo, d->gfx_pulldown_d, 0, 0, UI_VGA_W - 1, UI_VGA_H - 1, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_te_field[d->nt.field], game_str_te_techno); lbxfont_select(5, 0xe, 0, 0); lbxfont_print_str_center(x + 85, y + 5, buf, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(0, 0, 0xe, 0); game_tech_get_descr(d->g->gaux, d->nt.field, tech, buf, sizeof(buf)); pos = strlen(buf); cost = game_tech_get_next_rp(d->g, d->api, d->nt.field, tech); if (game_num_tech_costmuld2 != 100) { cost = (cost * game_num_tech_costmuld2) / 100; } if (game_num_tech_costmul != 100) { cost = (cost * game_num_tech_costmul) / 100; } lib_sprintf(&buf[pos], sizeof(buf) - pos, " \x02(%u %s)\x1", cost, game_str_te_rp); lbxfont_print_str_split(151, y + yo + 18, 156, buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } static void ui_newtech_choose_next(struct newtech_data_s *d) { char tname[TECH_NEXT_MAX][35]; const char *nptr[TECH_NEXT_MAX + 1]; bool cond[TECH_NEXT_MAX + 1]; int di = (d->num_next > 10) ? 8 : 9; for (int i = 0; i < (TECH_NEXT_MAX + 1); ++i) { cond[i] = true; } for (int i = 0; i < d->num_next; ++i) { uint8_t tech; tech = d->tech_next[i]; d->tbl_tech[i] = tech; /* WASBUG overwrites flag_copybuf, flag_dialog and d->tech_next */ game_tech_get_name(d->g->gaux, d->nt.field, tech, tname[i], 35); nptr[i] = tname[i]; } nptr[d->num_next] = 0; uiobj_set_callback_and_delay(newtech_choose_next_draw_cb, d, 1); uiobj_table_clear(); d->selected = 0; newtech_choose_next_draw_cb(d); lbxfont_select(0, 0, 0, 0); lbxfont_set_gap_h(di - 6); ui_draw_filled_rect(155, 49, 304, 56, 0x60, ui_scale); for (int i = 0; i < d->num_next; ++i) { lbxfont_print_str_normal(156, i * di + di + 41, tname[i], UI_SCREEN_W, ui_scale); } lbxfont_select_set_12_1(0, 0, 0, 0); ui_draw_finish(); lbxfont_select(0, 0, 0, 0); lbxfont_set_gap_h(di - 6); /*sel = */uiobj_select_from_list1(156, 41, 148, "", nptr, &d->selected, cond, 1, 0x60, true); ui_sound_play_sfx_24(); ui_delay_prepare(); game_tech_start_next(d->g, d->api, d->nt.field, d->tbl_tech[d->selected]); ui_delay_ticks_or_click(2); uiobj_unset_callback(); } static void newtech_adjust_draw_typestr(char *buf, size_t bufsize, const char *str1, const char *str2, int x, int y, int we) { lib_strcat(buf, game_str_nt_inc, bufsize); lib_strcat(buf, str1, bufsize); if (str2) { lib_strcat(buf, str2, bufsize); } lbxfont_print_str_split(x + 15, y + 16, 110 + we, buf, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } static void newtech_adjust_draw_cb(void *vptr) { struct newtech_data_s *d = vptr; char buf[0x96]; int x = 150, y = 30; newtech_draw_cb1(d); ui_draw_filled_rect(x, y, x + 135, y + 80, 0xf9, ui_scale); lbxgfx_draw_frame(x, y, (d->dialog_type == 0) ? d->gfx_eco_chng2 : d->gfx_eco_chng4, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(0, 0, 0, 0); lib_strcpy(buf, game_str_nt_doyou, sizeof(buf)); switch (d->dialog_type) { case 0: lib_strcat(buf, game_str_nt_redueco, sizeof(buf)); lbxfont_print_str_split(x + 15, y + 11, 110, buf, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.scrapbut_yes); lbxgfx_set_frame_0(ui_data.gfx.starmap.scrapbut_no); lbxgfx_draw_frame(x + 83, y + 60, ui_data.gfx.starmap.scrapbut_yes, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(x + 18, y + 60, ui_data.gfx.starmap.scrapbut_no, UI_SCREEN_W, ui_scale); break; case 1: newtech_adjust_draw_typestr(buf, sizeof(buf), game_str_nt_ind, 0, x, y, 0); break; case 2: newtech_adjust_draw_typestr(buf, sizeof(buf), game_str_nt_ecoall, game_str_nt_terra, x, y, 0); break; case 3: newtech_adjust_draw_typestr(buf, sizeof(buf), game_str_nt_def, 0, x, y - 5, 0); break; case 4: newtech_adjust_draw_typestr(buf, sizeof(buf), game_str_nt_ecostd, game_str_nt_terra, x - 1, y - 5, 2); break; case 5: newtech_adjust_draw_typestr(buf, sizeof(buf), game_str_nt_ecohost, game_str_nt_terra, x - 1, y - 5, 2); break; default: break; } } static void ui_newtech_adjust(struct newtech_data_s *d) { int16_t oi_tbl[3], oi_y, oi_n; int x = 150, y = 30; bool flag_done = false; uiobj_set_callback_and_delay(newtech_adjust_draw_cb, d, 1); uiobj_table_clear(); oi_y = UIOBJI_INVALID; oi_n = UIOBJI_INVALID; UIOBJI_SET_TBL_INVALID(oi_tbl); if (d->dialog_type == 0) { oi_y = uiobj_add_t0(x + 83, y + 60, "", ui_data.gfx.starmap.scrapbut_yes, MOO_KEY_y); oi_n = uiobj_add_t0(x + 18, y + 60, "", ui_data.gfx.starmap.scrapbut_no, MOO_KEY_n); } else { lbxfont_select(2, 6, 0, 0); oi_n = uiobj_add_t0(x + 10, y + 60, game_str_tbl_nt_adj[0], d->gfx_robo_but, MOO_KEY_n); oi_tbl[0] = uiobj_add_t0(x + 42, y + 60, game_str_tbl_nt_adj[1], d->gfx_robo_but, MOO_KEY_2); oi_tbl[1] = uiobj_add_t0(x + 74, y + 60, game_str_tbl_nt_adj[2], d->gfx_robo_but, MOO_KEY_5); oi_tbl[2] = uiobj_add_t0(x + 106, y + 60, game_str_tbl_nt_adj[3], d->gfx_robo_but, MOO_KEY_7); } while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_n)) { ui_sound_play_sfx_06(); flag_done = true; } if (oi == oi_y) { ui_sound_play_sfx_24(); game_update_tech_util(d->g); game_update_eco_on_waste(d->g, d->api, true); flag_done = true; } for (int i = 0; i < 3; ++i) { if (oi == oi_tbl[i]) { const planet_slider_i_t tbl_si[5] = { PLANET_SLIDER_IND, PLANET_SLIDER_ECO, PLANET_SLIDER_DEF, PLANET_SLIDER_ECO, PLANET_SLIDER_ECO }; const int tbl_gr[5] = { 0, 0, 0, 1, 2 }; ui_sound_play_sfx_24(); game_update_tech_util(d->g); if (!game_num_newtech_adjust_fix) { game_update_eco_on_waste(d->g, d->api, true); } game_planet_adjust_percent(d->g, d->api, tbl_si[d->dialog_type - 1], game_num_tbl_tech_autoadj[i + 1], tbl_gr[d->dialog_type - 1]); flag_done = true; } } if (!flag_done) { newtech_adjust_draw_cb(d); ui_draw_finish(); } ui_delay_ticks_or_click(1); } uiobj_table_clear(); } static void ui_newtech_do(struct newtech_data_s *d) { struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); uint8_t tech = d->nt.tech; bool flag_dialog; if (d->cur_source != d->nt.source) { if ((d->nt.source <= TECHSOURCE_FOUND) || (d->cur_source != 0)) { int m; m = ((d->nt.source == TECHSOURCE_RESEARCH) || (d->nt.source > TECHSOURCE_CHOOSE)) ? d->music_i : newtech_music_tbl[d->nt.source]; ui_sound_play_music(m); } d->flag_music = true; d->cur_source = d->nt.source; } flag_dialog = false; if (tech < 51) { flag_dialog = false; if ((d->nt.field == TECH_FIELD_CONSTRUCTION) && (((tech - 5) % 10) == 0) && (g->evn.best_wastereduce[d->api] < tech)) { flag_dialog = true; d->dialog_type = 0; g->evn.best_wastereduce[d->api] = tech; } if ((d->nt.field == TECH_FIELD_PLANETOLOGY) && (g->evn.best_ecorestore[d->api] < tech)) { if (0 || (tech == TECH_PLAN_IMPROVED_ECO_RESTORATION) || (tech == TECH_PLAN_ENHANCED_ECO_RESTORATION) || (tech == TECH_PLAN_ADVANCED_ECO_RESTORATION) || (tech == TECH_PLAN_COMPLETE_ECO_RESTORATION) ) { flag_dialog = true; d->dialog_type = 0; g->evn.best_ecorestore[d->api] = tech; } } if (e->race == RACE_SILICOID) { flag_dialog = false; } if ((d->nt.field == TECH_FIELD_COMPUTER) && (((tech - 8) % 10) == 0) && (g->evn.best_roboctrl[d->api] < tech)) { flag_dialog = true; d->dialog_type = 1; g->evn.best_roboctrl[d->api] = tech; } if (d->nt.field == TECH_FIELD_PLANETOLOGY) { if ((((tech - 2) % 6) == 0) && (g->evn.best_terraform[d->api] < tech)) { flag_dialog = true; d->dialog_type = 2; g->evn.best_terraform[d->api] = tech; } if ((tech == TECH_PLAN_SOIL_ENRICHMENT) || (tech == TECH_PLAN_ADVANCED_SOIL_ENRICHMENT)) { flag_dialog = true; d->dialog_type = 4; } if (tech == TECH_PLAN_ATMOSPHERIC_TERRAFORMING) { flag_dialog = true; d->dialog_type = 5; } } if ((d->nt.field == TECH_FIELD_FORCE_FIELD) && (((tech - 12) % 10) == 0)) { flag_dialog = true; d->dialog_type = 3; } } if ((ui_draw_finish_mode == 0) && d->flag_fadeout) { ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; } d->flag_fadeout = false; again: if (d->flag_choose_next) { nexttech_t *xt = &(g->evn.newtech[d->api].next[d->nt.field]); d->num_next = xt->num; if (d->num_next == 0) { return; } memcpy(d->tech_next, xt->tech, d->num_next); d->nt.frame = false; d->nt.source = TECHSOURCE_CHOOSE; ui_newtech_choose_next(d); } else { bool flag_done; int16_t oi_ok, oi_o1, oi_o2; oi_ok = UIOBJI_INVALID; oi_o1 = UIOBJI_INVALID; oi_o2 = UIOBJI_INVALID; flag_done = false; uiobj_set_callback_and_delay(newtech_draw_cb1, d, 1); uiobj_table_clear(); if (!d->nt.frame) { oi_ok = uiobj_add_mousearea_all(MOO_KEY_SPACE); } else { oi_o1 = uiobj_add_mousearea(50, 106, 110, 120, MOO_KEY_UNKNOWN); oi_o2 = uiobj_add_mousearea(122, 106, 183, 120, MOO_KEY_UNKNOWN); } while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_ok)) { flag_done = true; } if ((oi == oi_o1) || (oi == oi_o2)) { player_id_t framed = (oi == oi_o1) ? d->nt.other1 : d->nt.other2; flag_done = true; ui_sound_play_sfx_24(); g->evn.stolen_spy[d->nt.stolen_from][d->api] = framed; game_diplo_esp_frame(g, framed, d->nt.stolen_from); } newtech_draw_cb1(d); ui_draw_finish(); ui_delay_ticks_or_click(3); } uiobj_table_clear(); if (flag_dialog) { ui_newtech_adjust(d); } if (d->flag_is_current) { d->flag_is_current = false; d->flag_choose_next = true; d->nt.frame = false; goto again; } } uiobj_unset_callback(); } /* -------------------------------------------------------------------------- */ void ui_newtech(struct game_s *g, int pi) { struct newtech_data_s d; empiretechorbit_t *e = &(g->eto[pi]); bool flag_copybuf = false; ui_sound_stop_music(); uiobj_set_xyoff(0, 0); memset(&d, 0, sizeof(d)); d.g = g; d.api = pi; d.flag_fadeout = true; d.cur_source = -1; d.flag_music = false; d.anim = 0; newtech_load_data(&d); for (int i = 0; i < g->evn.newtech[pi].num; ++i) { d.nt = g->evn.newtech[pi].d[i]; if (!flag_copybuf) { flag_copybuf = true; ui_switch_1(g, pi); hw_video_copy_back_from_page2(); hw_video_copy_back_to_page3(); } d.flag_is_current = false; d.flag_choose_next = false; if (g->eto[pi].tech.project[d.nt.field] == d.nt.tech) { d.flag_is_current = true; } ui_draw_erase_buf(); d.gfx_lab = lbxfile_item_get(LBXFILE_TECHNO, (d.nt.source != TECHSOURCE_TRADE) ? d.nt.source : 0); lbxgfx_draw_frame(0, 0, d.gfx_lab, UI_SCREEN_W, ui_scale); { int v; if (d.nt.tech <= 50) { v = game_tech_get_gfx_i(g->gaux, d.nt.field, d.nt.tech); } else { const int tbl[TECH_FIELD_NUM] = { 9, 22, 20, 25, 15, 29 }; v = tbl[d.nt.field]; } d.gfx_tech = lbxfile_item_get(LBXFILE_TECHNO, v); } lbxgfx_draw_frame(145, 54, d.gfx_tech, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); { int v; if (d.nt.source == TECHSOURCE_TRADE) { v = g->eto[d.nt.v06].race; } else { v = d.nt.source * 10 + e->race; } if (d.gfx_spies) { lbxfile_item_release(LBXFILE_SPIES, d.gfx_spies); } d.gfx_spies = lbxfile_item_get(LBXFILE_SPIES, v); } d.music_i = newtech_music_tbl[d.nt.source]; ui_newtech_do(&d); lbxfile_item_release(LBXFILE_TECHNO, d.gfx_lab); lbxfile_item_release(LBXFILE_TECHNO, d.gfx_tech); } for (tech_field_t field = 0; field < TECH_FIELD_NUM; ++field) { if (game_tech_can_choose(g, pi, field)) { if (!flag_copybuf) { flag_copybuf = true; ui_switch_1(g, pi); hw_video_copy_back_from_page2(); hw_video_copy_back_to_page3(); } if (d.cur_source == -1) { ui_draw_erase_buf(); d.gfx_lab = lbxfile_item_get(LBXFILE_TECHNO, 0); lbxgfx_draw_frame(0, 0, d.gfx_lab, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); lbxfile_item_release(LBXFILE_TECHNO, d.gfx_lab); if (d.gfx_spies) { lbxfile_item_release(LBXFILE_SPIES, d.gfx_spies); } d.gfx_spies = lbxfile_item_get(LBXFILE_SPIES, e->race); d.music_i = newtech_music_tbl[0]; } d.nt.field = field; d.nt.tech = 0; d.nt.source = TECHSOURCE_CHOOSE; d.flag_choose_next = true; d.nt.frame = false; ui_newtech_do(&d); } } if (d.flag_music) { ui_sound_stop_music(); } if (flag_copybuf) { hw_video_copy_back_from_page3(); hw_video_copy_back_to_page2(); ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; } g->evn.newtech[pi].num = 0; newtech_free_data(&d); } 1oom-1.11.2/src/ui/classic/uiobj.c000066400000000000000000002224671476061725400166010ustar00rootroot00000000000000#include "config.h" #include #include "uiobj.h" #include "comp.h" #include "game_types.h" /* only for UIOBJ_MAX */ #include "hw.h" #include "kbd.h" #include "lbxfont.h" #include "lbxgfx.h" #include "log.h" #include "lib.h" #include "mouse.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidelay.h" #include "uidraw.h" #include "uihelp.h" #include "uipal.h" /* -------------------------------------------------------------------------- */ /* WASBUG? MOO1 allocs 0x1650 bytes fitting 150 which is not always enough. Absolute max is planets + orbits + fleets + transports + some buttons. This is overkill for actual gameplay but we are not limited by 1993 memory sizes. */ #define UIOBJ_MAX (PLANETS_MAX * 7 + FLEET_ENROUTE_MAX + TRANSPORT_MAX + 32) #define UIOBJ_OFFSCREEN (320 * UI_SCALE_MAX + 100) typedef enum { UIOBJ_TYPE_BUTTON = 0, UIOBJ_TYPE_TOGGLE = 1, UIOBJ_TYPE_SET = 2, UIOBJ_TYPE_SETVAL = 3, UIOBJ_TYPE_TEXTINPUT = 4, UIOBJ_TYPE_SLIDER = 6, UIOBJ_TYPE_MOUSEAREA = 7, UIOBJ_TYPE_ALTSTR = 8, UIOBJ_TYPE_TEXTLINE = 0xa, UIOBJ_TYPE_SCROLLAREA = 0xb, UIOBJ_TYPE_WHEELAREA = 0xc } uiobj_type_t; typedef struct uiobj_s { /*00*/ uint16_t x0; /*02*/ uint16_t y0; /*04*/ uint16_t x1; /* inclusive */ /*06*/ uint16_t y1; /* inclusive */ /* 13 types t0..3: buttons with gfx (and optional text) with different highlight conditions t1: toggle t2: set1 t3: setval t4: textinput t6: slider t7: mousearea or inputkey t8: altstr ta: text line tb: scroll area tc: mouse wheel area */ /*08*/ uint8_t type; /*..*/ uint8_t scale; /*1a*/ int16_t *vptr; /*24*/ uint32_t key; union { struct { /*16*/ const char *str; /*20*/ uint8_t *lbxdata; /*18*/ int16_t z18; /* t3:uiobji? */ /*0c*/ uint8_t fontnum; /* t1..3? */ /*0e*/ uint8_t fonta2; /* t1..3? */ /*1c*/ bool indep; /* from lbxgfx offs 0x10 */ } t0; /* t{0..3} */ struct { /*16*/ char *buf; /*22*/ const uint8_t *colortbl; /*20*/ uint16_t max_chars; /*0c*/ uint8_t fontnum; /*0e*/ uint8_t fonta2; /*14*/ uint8_t fonta4; /*1a*/ uint8_t rectcolor; /*1c*/ bool align_right; /*..*/ bool allow_lcase; } t4; struct { /*..*/ void (*cb)(void *ctx, uint8_t slideri, int16_t value); /*..*/ void *ctx; /*1c*/ uint16_t vmin; /*1e*/ uint16_t vmax; /*..*/ uint8_t slideri; } t6; struct { /*16*/ const char *str; /*18*/ uint16_t pos; /*1a*/ uint16_t len; } t8; struct { /*16*/ const char *str; /*18*/ int16_t z18; /*0c*/ uint8_t fontnum; /*0e*/ uint8_t fonta2; /*14*/ uint8_t fonta2b; /*10*/ uint8_t subtype; /* 0, 1, 0xf */ /*1c*/ uint8_t sp0v; /*12*/ bool z12; } ta; struct { /*1c*/ int16_t *xptr; /*1e*/ int16_t *yptr; /*..*/ uint8_t *zptr; /*18*/ uint16_t xdiv; /*1a*/ uint16_t ydiv; /*..*/ uint8_t zmax; } tb; }; } uiobj_t; /* -------------------------------------------------------------------------- */ static uint16_t uiobj_table_num = 0; static uint16_t uiobj_table_num_old = 0; static int16_t uiobj_focus_oi = -1; static int16_t uiobj_clicked_oi = 0; static int uiobj_xoff = 1; static int uiobj_yoff = -1; static int16_t uiobj_mouseoff = 0; static int16_t uiobj_handle_downcount = 0; static int16_t uiobj_kbd_alt_oi = 0; static uint16_t uiobj_delay = 2; static int16_t uiobj_help_id = -1; static bool uiobj_flag_select_list_active = false; static bool uiobj_flag_select_list_multipage = false; static int16_t uiobj_kbd_movey = -1; static bool uiobj_flag_skip_delay = false; static bool uiobj_flag_have_cb = false; static void (*uiobj_callback)(void *) = NULL; static void *uiobj_cbdata = NULL; static uiobj_t uiobj_tbl[UIOBJ_MAX]; /* -------------------------------------------------------------------------- */ int uiobj_minx = 0; int uiobj_miny = 0; int uiobj_maxx = 0; int uiobj_maxy = 0; /* -------------------------------------------------------------------------- */ static int16_t uiobj_alloc(void) { if (uiobj_table_num < (UIOBJ_MAX - 1)) { return uiobj_table_num++; } else { log_fatal_and_die("uiobj_table size exceeded"); } } static int smidx(const uiobj_t *p) { return p->x0 + (p->x1 - p->x0) / 2; } static int smidy(const uiobj_t *p) { return p->y0 + (p->y1 - p->y0) / 2; } static int scmidx(const uiobj_t *p) { return (p->x0 + (p->x1 - p->x0) / 2) * p->scale; } static int scmidy(const uiobj_t *p) { return (p->y0 + (p->y1 - p->y0) / 2) * p->scale; } static int smidtexty(const uiobj_t *p) { int16_t v = lbxfont_get_height(); --v; if (v < 0) { ++v; } v /= 2; return smidy(p) - v; } static inline bool uiobj_is_at_xy(const uiobj_t *p, int x, int y) { uint8_t scale; if (p->x0 == UIOBJ_OFFSCREEN) { return false; } x += uiobj_mouseoff; y += uiobj_mouseoff; scale = p->scale; if (0 || (x < (p->x0 * scale)) || (x > (p->x1 * scale + scale - 1)) || (y < (p->y0 * scale)) || (y > (p->y1 * scale + scale - 1)) ) { return false; } return true; } static void uiobj_handle_t03_cond(uiobj_t *p, bool cond) { if (cond) { lbxgfx_set_frame_0(p->t0.lbxdata); lbxgfx_draw_frame(p->x0, p->y0, p->t0.lbxdata, UI_SCREEN_W, p->scale); lbxfont_select(p->t0.fontnum, p->t0.fonta2, 0, 0); lbxfont_print_str_center(smidx(p), smidtexty(p), p->t0.str, UI_SCREEN_W, p->scale); } else { if (p->t0.indep == 0) { lbxgfx_set_frame_0(p->t0.lbxdata); lbxgfx_draw_frame(p->x0, p->y0, p->t0.lbxdata, UI_SCREEN_W, p->scale); } else { lbxgfx_set_new_frame(p->t0.lbxdata, 1); } lbxgfx_draw_frame(p->x0, p->y0, p->t0.lbxdata, UI_SCREEN_W, p->scale); lbxfont_select(p->t0.fontnum, p->t0.fonta2, 0, 0); lbxfont_print_str_center(smidx(p) + uiobj_xoff, smidtexty(p) + uiobj_yoff, p->t0.str, UI_SCREEN_W, p->scale); } } static void uiobj_handle_t4_sub2(uiobj_t *p, uint16_t len, uint16_t a4, const char *str) { char strbuf[64]; int16_t si, va; si = a4; ui_delay_prepare(); lib_strcpy(strbuf, str, sizeof(strbuf)); uiobj_do_callback(); /*ve = p->x1 - p->x0;*/ lbxfont_select(p->t4.fontnum, p->t4.fonta2, p->t4.fonta4, 0); va = lbxfont_get_height() - 1; if (p->t4.rectcolor != 0) { ui_draw_filled_rect(p->x0, p->y0, p->x1, p->y1, p->t4.rectcolor, p->scale); } { uint16_t l, w, x, vc; char c; c = strbuf[len]; strbuf[len] = 0; x = lbxfont_calc_str_width(strbuf) + p->x0; strbuf[len] = c; w = lbxfont_get_char_w(c ? c : ' '); if ((si > 0) && (si <= va)) { vc = p->y0 + va; l = 0; while (si > 0) { ui_draw_line1(x, vc - si + 1, x + w + 1, vc - si + 1, p->t4.colortbl[l], p->scale); ++l; --si; } } else if (si != 0) { si = va - (si - va); l = 0; while (si > 0) { ui_draw_line1(x, p->y0 + si - 1, x + w + 1, p->y0 + si - 1, p->t4.colortbl[va - l - 1], p->scale); ++l; --si; } } } lbxfont_select_subcolors_13not1(); lbxfont_print_str_normal(p->x0, p->y0, strbuf, UI_SCREEN_W, p->scale); ui_palette_set_n(); uiobj_finish_frame(); ui_delay_ticks_or_click(uiobj_delay); } static bool uiobj_textinput_do(uiobj_t *p, int w, char *buf, int max_chars, bool allow_lcase, bool copy_truncated) { char strbuf[64]; int len, pos, fonth, animpos = 0; bool flag_mouse_button = false, flag_quit = false, flag_got_first = false; mookey_t key = MOO_KEY_UNKNOWN; hw_textinput_start(); lib_strcpy(strbuf, buf, sizeof(strbuf)); len = strlen(strbuf); if (lbxfont_calc_str_width(strbuf) > w) { if (len != 0) { len = 0; strbuf[len] = '\0'; } } pos = len; if (pos >= max_chars) { pos = max_chars; } if (copy_truncated) { lib_strcpy(buf, strbuf, (size_t)max_chars + 1); } fonth = lbxfont_get_height(); uiobj_handle_t4_sub2(p, pos, animpos, strbuf); while ((key != MOO_KEY_RETURN) && (!flag_mouse_button)) { uint32_t keyp; bool flag_ok; char c; while (!(kbd_have_keypress() || flag_mouse_button)) { hw_event_handle(); if ((1/*mouse_flag_initialized*/) && (mouse_buttons || (mouse_getclear_click_hw() != 0))) { flag_mouse_button = true; break; } else { ++animpos; if (((fonth << 1) - 1) < animpos) { animpos = 0; } uiobj_handle_t4_sub2(p, pos, animpos, strbuf); } } if (flag_mouse_button) { break; } keyp = kbd_get_keypress(); key = KBD_GET_KEY(keyp); c = KBD_GET_CHAR(keyp); switch (key) { case MOO_KEY_BACKSPACE: if (!flag_got_first) { strbuf[0] = '\0'; len = pos = 0; animpos = 0; flag_got_first = true; } else if (len > 0) { if (pos >= len) { --len; --pos; animpos = 0; } else if (pos > 0) { for (int i = pos; i < len; ++i) { strbuf[i - 1] = strbuf[i]; } --len; --pos; } strbuf[len] = '\0'; } break; case MOO_KEY_DELETE: if ((len > 0) && (pos < len)) { for (int i = pos; i < len; ++i) { strbuf[i] = strbuf[i + 1]; } --len; animpos = 0; strbuf[len] = '\0'; } break; case MOO_KEY_LEFT: flag_got_first = true; if (pos > 0) { --pos; animpos = 0; } break; case MOO_KEY_RIGHT: if ((pos < max_chars) && (pos < len)) { ++pos; animpos = 0; if (pos >= len) { strbuf[len] = ' '; strbuf[len + 1] = '\0'; if ((pos >= max_chars) || (lbxfont_calc_str_width(strbuf) > w)) { --pos; } strbuf[len] = '\0'; } } break; case MOO_KEY_ESCAPE: flag_mouse_button = true; flag_quit = true; break; default: flag_ok = false; if ((!allow_lcase) && (c >= 'a') && (c <= 'z')) { c -= 0x20; /* az -> AZ */ } if (0 || ((c >= 'A') && (c < ']')) || (allow_lcase && (c >= 'a') && (c < '{')) || ((c >= '-') && (c < ';')) || (c == ' ') || (c == '-') ) { flag_ok = true; } if (flag_ok) { flag_got_first = true; strbuf[len] = c; strbuf[len + 1] = '\0'; if ((len < max_chars) && (lbxfont_calc_str_width(strbuf) <= w)) { strbuf[len] = '\0'; if (pos < len) { for (int i = len; i > pos; --i) { strbuf[i] = strbuf[i - 1]; } ++len; strbuf[pos] = c; ++pos; } else { strbuf[len] = c; ++len; strbuf[len] = ' '; strbuf[len + 1] = '\0'; if ((len < max_chars) && (lbxfont_calc_str_width(strbuf) <= w)) { ++pos; } } strbuf[len] = '\0'; animpos = 0; } else { strbuf[len] = '\0'; } } break; } uiobj_handle_t4_sub2(p, pos, animpos, strbuf); } hw_textinput_stop(); lib_strcpy(buf, strbuf, (size_t)max_chars + 1); if (flag_mouse_button) /*&& (mouse_flag_initialized)*/ { while (mouse_buttons) { hw_event_handle(); } } /* TODO ui_cursor_erase0(); */ uiobj_focus_oi = -1; mouse_getclear_click_hw(); mouse_getclear_click_sw(); return flag_quit; } static void uiobj_handle_t4_sub1(uiobj_t *p) { int w; while (mouse_buttons) { hw_event_handle(); uiobj_do_callback(); } w = p->x1 - p->x0; lbxfont_select(p->t4.fontnum, p->t4.fonta2, p->t4.fonta4, 0); uiobj_textinput_do(p, w, p->t4.buf, p->t4.max_chars, p->t4.allow_lcase, true); } static void uiobj_handle_t6_slider_input(uiobj_t *p) { int16_t sliderval, slideroff, di; di = moouse_x + uiobj_mouseoff; slideroff = ((p->t6.vmax - p->t6.vmin) * (di - p->x0 * p->scale)) / ((p->x1 - p->x0) * p->scale); if (p->x1 * p->scale <= di) { sliderval = p->t6.vmax; } else if (p->x0 >= di) { sliderval = p->t6.vmin; } else { sliderval = p->t6.vmin + slideroff; } SETMAX(sliderval, p->t6.vmin); SETMIN(sliderval, p->t6.vmax); *p->vptr = sliderval; if (p->t6.cb) { p->t6.cb(p->t6.ctx, p->t6.slideri, sliderval); } } static void uiobj_handle_ta_sub1(int x0, int y0, int x1, int y1, uint8_t subtype, uint8_t p0v, int scale) { switch (subtype) { case 1: ui_draw_filled_rect(x0, y0, x1, y1, p0v, scale); break; case 0xf: lbxgfx_apply_colortable(x0, y0, x1, y1, p0v, UI_SCREEN_W, scale); break; default: break; } } /* not a function in MOO1 but part of uiobj_handle_objects */ static inline void uiobj_handle_objects_sub1(int i) { uiobj_t *p = &uiobj_tbl[i]; switch (p->type) { case UIOBJ_TYPE_BUTTON: uiobj_handle_t03_cond(p, true); break; case UIOBJ_TYPE_TOGGLE: uiobj_handle_t03_cond(p, *p->vptr == 0); break; case UIOBJ_TYPE_SET: uiobj_handle_t03_cond(p, *p->vptr == 0); break; case UIOBJ_TYPE_SETVAL: uiobj_handle_t03_cond(p, *p->vptr != p->t0.z18); break; case UIOBJ_TYPE_TEXTLINE: lbxfont_select(p->ta.fontnum, p->ta.fonta2, 0, 0); if (*p->vptr != p->ta.z18) { if (!p->ta.z12) { /* ?? what is the point in this second call? */ lbxfont_select(p->ta.fontnum, p->ta.fonta2b, 0, 0); } /*19ca3*/ lbxfont_print_str_normal(p->x0, p->y0 + 1, p->ta.str, UI_SCREEN_W, p->scale); } else { int16_t gap_h, char_h; gap_h = lbxfont_get_gap_h(); if (gap_h < 0) { ++gap_h; } gap_h /= 2; if (gap_h == 0) { gap_h = 1; } char_h = lbxfont_get_height(); /*19ce2*/ uiobj_handle_ta_sub1(p->x0 - 1, p->y0 - gap_h + 1, p->x1, p->y0 + char_h + 1, p->ta.subtype, p->ta.sp0v, p->scale); lbxfont_print_str_normal(p->x0, p->y0 + 1, p->ta.str, UI_SCREEN_W, p->scale); } break; case UIOBJ_TYPE_TEXTINPUT: if (uiobj_focus_oi != i) { lbxfont_select(p->t4.fontnum, p->t4.fonta2, p->t4.fonta4, 0); ui_draw_filled_rect(p->x0, p->y0, p->x1, p->y1, p->t4.rectcolor, p->scale); if (!p->t4.align_right) { lbxfont_print_str_normal(p->x0, p->y0, p->t4.buf, UI_SCREEN_W, p->scale); } else { lbxfont_print_str_right(p->x1, p->y0, p->t4.buf, UI_SCREEN_W, p->scale); } } break; case UIOBJ_TYPE_SLIDER: { uint16_t v = *p->vptr; SETMAX(v, p->t6.vmin); SETMIN(v, p->t6.vmax); *p->vptr = v; } break; default: break; } } static void uiobj_handle_click(int i, bool in_focus) { uiobj_t *p = &uiobj_tbl[i]; switch (p->type) { case UIOBJ_TYPE_BUTTON: uiobj_handle_t03_cond(p, !in_focus); break; case UIOBJ_TYPE_TOGGLE: uiobj_handle_t03_cond(p, (!in_focus) || (*p->vptr == 1)); break; case UIOBJ_TYPE_SET: uiobj_handle_t03_cond(p, (!in_focus) && (*p->vptr == 0)); break; case UIOBJ_TYPE_SETVAL: if (!in_focus) { *p->vptr = UIOBJI_INVALID; /* TODO or other 0xfc18? */ } else { *p->vptr = p->t0.z18; } uiobj_handle_t03_cond(p, *p->vptr != p->t0.z18); break; case UIOBJ_TYPE_TEXTLINE: if (!in_focus) { *p->vptr = 0; } else if (p->ta.z12) { *p->vptr = p->ta.z18; } lbxfont_select(p->ta.fontnum, p->ta.fonta2, 0, 0); if (*p->vptr != p->ta.z18) { if (p->ta.z12) { lbxfont_print_str_normal(p->x0, p->y0, p->ta.str, UI_SCREEN_W, p->scale); } else { lbxfont_select(p->ta.fontnum, p->ta.fonta2b, 0, 0); lbxfont_print_str_normal(p->x0, p->y0 + 1, p->ta.str, UI_SCREEN_W, p->scale); lbxfont_select_subcolors_0(); } } else { int16_t char_h, gap_h; gap_h = lbxfont_get_gap_h(); if (gap_h < 0) { ++gap_h; } gap_h /= 2; if (gap_h == 0) { gap_h = 1; } char_h = lbxfont_get_height(); uiobj_handle_ta_sub1(p->x0 - 1, p->y0 - gap_h + 1, p->x1, p->y0 + char_h + 1, p->ta.subtype, p->ta.sp0v, p->scale); lbxfont_print_str_normal(p->x0, p->y0 + 1, p->ta.str, UI_SCREEN_W, p->scale); } break; case UIOBJ_TYPE_SCROLLAREA: if (in_focus) { *p->tb.xptr = (moouse_x - p->x0) / p->tb.xdiv; *p->tb.yptr = (moouse_y - p->y0) / p->tb.ydiv; } break; case UIOBJ_TYPE_SLIDER: /* MOO1 checks for in_focus here which makes dragging the slider to min/max needlessly hard */ uiobj_handle_t6_slider_input(p); break; case UIOBJ_TYPE_TEXTINPUT: uiobj_handle_t4_sub1(p); break; default: break; } } static int16_t uiobj_kbd_dir_key_dy_list(int diry) { int16_t oi2 = uiobj_at_cursor(); int16_t oi = oi2; uiobj_t *p; if (oi != 0) { if (diry == 1) { while ((++oi < (uiobj_table_num - 1)) && (uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE)) { if (uiobj_tbl[oi].ta.z12) { break; } } if (!((oi < (uiobj_table_num - 1)) && (uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE))) { if (uiobj_flag_select_list_multipage) { oi = oi2; uiobj_kbd_movey = 1; } else { oi = 0; while (oi < uiobj_table_num) { ++oi; if (/*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && uiobj_tbl[oi].ta.z12) { break; } } if (oi >= uiobj_table_num) { oi = oi2; } } } } else { if (uiobj_flag_select_list_multipage && (oi == 1)) { uiobj_kbd_movey = -1; oi = 1; } else { if (oi > 1) { --oi; } else { oi = uiobj_table_num - 1 - 1; } while (oi && (uiobj_tbl[oi].type != UIOBJ_TYPE_TEXTLINE)) { --oi; } while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && !uiobj_tbl[oi].ta.z12) { --oi; } if (oi <= 0) { if (uiobj_flag_select_list_multipage) { uiobj_kbd_movey = -1; oi = 1; } else { oi = uiobj_table_num - 1 - 1; while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && uiobj_tbl[oi].ta.z12) { --oi; } while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && !uiobj_tbl[oi].ta.z12) { --oi; } if (oi == 0) { oi = oi2; } } } } } } else { p = &uiobj_tbl[1]; if (p->vptr && (*p->vptr >= 0)) { oi2 = *p->vptr + 1; if (oi2 >= uiobj_table_num) { oi2 = 0; } oi = oi2; if (diry == 1) { while ((++oi < (uiobj_table_num - 1)) && (uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE)) { if (uiobj_tbl[oi].ta.z12) { break; } } if (!((oi < uiobj_table_num) && (uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE))) { if (uiobj_flag_select_list_multipage) { uiobj_kbd_movey = 1; } else if (oi < uiobj_table_num) { oi = 1; while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && !uiobj_tbl[oi].ta.z12) { ++oi; } if (oi >= uiobj_table_num) { oi = oi2; } } } } else { if ((oi == 1) && uiobj_flag_select_list_multipage) { uiobj_kbd_movey = -1; } else { if (oi <= 1) { oi = uiobj_table_num - 1 - 1; } else { --oi; } while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && !uiobj_tbl[oi].ta.z12) { --oi; } if (oi == 0) { oi = uiobj_table_num - 1 - 1; while (oi && /*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && !uiobj_tbl[oi].ta.z12) { --oi; } if (oi == 0) { oi = oi2; } } } } } else { for (oi = 1; oi < uiobj_table_num; ++oi) { if (/*not tested in MOO1!*/(uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) && uiobj_tbl[oi].ta.z12) { break; } } if (oi >= uiobj_table_num) { oi = 0; } } } if ((oi < 0) || (oi >= uiobj_table_num)) { oi = 0; } if (oi > 0) { p = &uiobj_tbl[oi]; mouse_stored_x = scmidx(p); mouse_stored_y = scmidy(p); if ((moouse_x != mouse_stored_x) || (moouse_y != mouse_stored_y)) { ui_cursor_update_gfx_i(mouse_stored_x, mouse_stored_y); uiobj_mouseoff = ui_cursor_mouseoff; mouse_stored_x -= uiobj_mouseoff; mouse_stored_y -= uiobj_mouseoff; hw_mouse_set_xy(mouse_stored_x, mouse_stored_y); if (p->type == UIOBJ_TYPE_TEXTLINE) { *p->vptr = p->ta.z18; } } } return oi; } static inline bool uiobj_kbd_dir_obj_ok(const uiobj_t *p) { return ((p->type < UIOBJ_TYPE_SCROLLAREA) && (p->x0 != UIOBJ_OFFSCREEN) && ((p->type != UIOBJ_TYPE_TEXTLINE) || p->ta.z12)); } static int16_t uiobj_kbd_dir_key_dxdy(int dirx, int diry, int16_t oi2, int mx, int my) { int dx = UIOBJ_OFFSCREEN, dy = UIOBJ_OFFSCREEN; int slope = UIOBJ_OFFSCREEN; int mind = UIOBJ_OFFSCREEN * UIOBJ_OFFSCREEN; int dist; int16_t oi = oi2; uiobj_t *p; if (ui_fixbugs_enabled) { mx += ui_cursor_mouseoff; my += ui_cursor_mouseoff; } { bool flag_found = false; for (int i = 1; i < uiobj_table_num; ++i) { p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { flag_found = true; break; } } if (!flag_found) { return UIOBJI_NONE; } } if ((diry != 0) && (dirx == 0)) { for (int i = 1; i < uiobj_table_num; ++i) { if (ui_kbd_cursor_keys_fix) { break; } if (i == oi2) { if (i != (uiobj_table_num - 1)) { ++i; } else { break; } } p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { dy = (diry < 0) ? (my - scmidy(p)) : (scmidy(p) - my); dx = scmidx(p) - mx; if ((p->x0 * p->scale <= mx) && (p->x1 * p->scale >= mx) && ((dx < -6 * p->scale) || (dx > 6 * p->scale))) { dx = 6 * p->scale; } if ((dx > -6 * p->scale) && (dx < 6 * p->scale) && (dy > 0) && (dy < mind)) { mind = dy; oi = i; } } } if (oi == oi2 || ui_kbd_cursor_keys_fix) { for (int i = 1; i < uiobj_table_num; ++i) { if (i == oi2) { if (i != (uiobj_table_num - 1)) { ++i; } else { break; } } p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { dy = (diry < 0) ? (my - scmidy(p)) : (scmidy(p) - my); dx = scmidx(p) - mx; if (!ui_kbd_cursor_keys_fix && (p->x0 * p->scale <= mx) && (p->x1 * p->scale >= mx) && ((dx < -6 * p->scale) || (dx > 6 * p->scale))) { dx = 6 * p->scale; } if (dx < 0) { dx = -dx; } if (dy < 0) { dx = UIOBJ_OFFSCREEN; } if (dy == 0) { if (ui_kbd_cursor_keys_fix) { continue; } else { dy = 1; } } slope = (dx * 100) / dy; if ((slope >= 0) && (slope < 0x2c)) { dist = (dx * dx) + (dy * dy); if (dist < mind) { mind = dist; oi = i; } } } } } } if ((dirx != 0) && (diry == 0)) { for (int i = 1; i < uiobj_table_num; ++i) { if (ui_kbd_cursor_keys_fix) { break; } if (i == oi2) { if (i != (uiobj_table_num - 1)) { ++i; } else { break; } } p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { dx = (dirx < 0) ? (mx - scmidx(p)) : (scmidx(p) - mx); dy = scmidy(p) - my; if ((p->y0 * p->scale <= my) && (p->y1 * p->scale >= my) && ((dy * p->scale < -6) || (dy * p->scale > 6))) { dy = 6 * p->scale; } if ((dy > -6 * p->scale) && (dy < 6 * p->scale) && (dx > 0) && (dx < mind)) { mind = dx; oi = i; } } } if (oi == oi2 || ui_kbd_cursor_keys_fix) { for (int i = 1; i < uiobj_table_num; ++i) { if (i == oi2) { if (i != (uiobj_table_num - 1)) { ++i; } else { break; } } p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { dx = (dirx < 0) ? (mx - scmidx(p)) : (scmidx(p) - mx); dy = scmidy(p) - my; if (!ui_kbd_cursor_keys_fix && (p->y0 * p->scale <= my) && (p->y1 * p->scale >= my) && ((dy < -6 * p->scale) || (dy > 6 * p->scale))) { dy = 6 * p->scale; } if (dy < 0) { dy = -dy; } if (dx < 0) { dy = UIOBJ_OFFSCREEN; } if (dx == 0) { if (ui_kbd_cursor_keys_fix) { continue; } else { dx = 1; } } slope = (dy * 100) / dx; if ((slope >= 0) && (slope < 0x2c)) { dist = (dx * dx) + (dy * dy); if (dist < mind) { mind = dist; oi = i; } } } } } } if ((dirx != 0) && (diry != 0)) { for (int i = 1; i < uiobj_table_num; ++i) { if (i == oi2) { if (i != (uiobj_table_num - 1)) { ++i; } else { break; } } p = &uiobj_tbl[i]; if (uiobj_kbd_dir_obj_ok(p)) { dx = (dirx < 0) ? (mx - scmidx(p)) : (scmidx(p) - mx); dy = (diry < 0) ? (my - scmidy(p)) : (scmidy(p) - my); if ((dx < 0) || (dy < 0)) { slope = UIOBJ_OFFSCREEN; continue; } if ((dx >= dy) && (dy != 0)) { slope = (dy * 100) / dx; } if ((dy > dx) && (dx != 0)) { slope = (dx * 100) / dy; } if ((dx == 0) || (dy == 0)) { slope = UIOBJ_OFFSCREEN; } if ((slope >= 34) && (slope <= 105)) { dist = (dx * dx) + (dy * dy); if (dist < mind) { mind = dist; oi = i; } } } } } return oi; } static int16_t uiobj_kbd_dir_key(int dirx, int diry) { if (uiobj_flag_select_list_active && (diry != 0)) { return uiobj_kbd_dir_key_dy_list(diry); } else { int mx, my; int16_t oi, oi2; uiobj_t *p; if (1/*mouse_initialized*/) { mx = moouse_x; my = moouse_y; } else { mx = mouse_stored_x; my = mouse_stored_y; } oi2 = 0; oi = uiobj_table_num - 1; while (oi > 0) { p = &uiobj_tbl[oi]; if (p->type < UIOBJ_TYPE_SCROLLAREA) { if (uiobj_is_at_xy(p, mx, my)) { if (p->type == UIOBJ_TYPE_TEXTLINE) { if (p->ta.z12) { oi2 = oi; } } else { oi2 = oi; } } } --oi; } /*15a7a*/ oi = oi2; if ((dirx == 0) && (diry == 0)) { return oi; } oi = uiobj_kbd_dir_key_dxdy(dirx, diry, oi2, mx, my); if ((oi != oi2) && (oi != UIOBJI_NONE)) { uiobj_set_focus_forced(oi); } return oi; } } static char uiobj_get_keychar(uint32_t key) { mookey_t k = KBD_GET_KEY(key); if (0 || ((k >= MOO_KEY_SPACE) && (k < MOO_KEY_a)) || ((k >= MOO_KEY_KP0) && (k <= MOO_KEY_KP_EQUALS)) ) { return KBD_GET_CHAR(key); } return 0; } static int16_t uiobj_handle_kbd_find_alt(int16_t oi, uint32_t key) { const uiobj_t *p = &uiobj_tbl[oi]; mookey_t k = KBD_GET_KEY(key); uint32_t kmod = KBD_GET_KEYMOD(key); char c = uiobj_get_keychar(key); while (1 && (oi != uiobj_table_num) && (!((p->type != UIOBJ_TYPE_ALTSTR) && ((kmod == p->key) || (c && (c == p->key))))) ) { if ((p->type == UIOBJ_TYPE_ALTSTR) && KBD_MOD_ONLY_ALT(key) && (k == p->key)) { break; } ++oi; p = &uiobj_tbl[oi]; } return oi; } static uint32_t uiobj_handle_kbd(int16_t *oiptr) { uint32_t key = kbd_get_keypress(); uiobj_t *p; int16_t /*si*/oi, /*di*/oi2; bool flag_reset_alt_str; #ifdef FEATURE_MODEBUG if (KBD_GET_KEY(key) == 0) { LOG_DEBUG((0, "%s: got 0 key 0x%x\n", __func__, KBD_GET_KEY(key), key)); } #endif if (uiobj_kbd_alt_oi >= uiobj_table_num) { uiobj_kbd_alt_oi = 0; } oi = uiobj_kbd_alt_oi + 1; oi = uiobj_handle_kbd_find_alt(oi, key); p = &uiobj_tbl[oi]; if (oi == uiobj_table_num) { oi = uiobj_handle_kbd_find_alt(1, key); p = &uiobj_tbl[oi]; } uiobj_kbd_alt_oi = oi; flag_reset_alt_str = true; if (oi < uiobj_table_num) { *oiptr = oi; uiobj_set_focus(oi); p = &uiobj_tbl[oi]; if (p->type == UIOBJ_TYPE_ALTSTR) { if (++p->t8.pos >= p->t8.len) { p->t8.pos = 0; } else { *oiptr = 0; key = MOO_KEY_UNKNOWN; } p->key = p->t8.str[p->t8.pos]; flag_reset_alt_str = false; } } else { int dirx, diry; dirx = 0; diry = 0; oi2 = *oiptr; switch (KBD_GET_KEYMOD(key)) { case MOO_KEY_LEFT: case MOO_KEY_KP4: dirx = -1; break; case MOO_KEY_RIGHT: case MOO_KEY_KP6: dirx = 1; break; case MOO_KEY_UP: case MOO_KEY_KP8: diry = -1; break; case MOO_KEY_DOWN: case MOO_KEY_KP2: diry = 1; break; case MOO_KEY_KP7: dirx = -1; diry = -1; break; case MOO_KEY_KP9: dirx = 1; diry = -1; break; case MOO_KEY_KP1: dirx = -1; diry = 1; break; case MOO_KEY_KP3: dirx = 1; diry = 1; break; default: break; } if ((dirx || diry) && (KBD_GET_MOD(key) == 0)) { oi2 = uiobj_kbd_dir_key(dirx, diry); } *oiptr = oi2; } if (flag_reset_alt_str) { for (int16_t oi3 = 0; oi3 < uiobj_table_num; ++oi3) { p = &uiobj_tbl[oi3]; if (p->type == UIOBJ_TYPE_ALTSTR) { p->t8.pos = 0; p->key = p->t8.str[0]; } } } return key; } static void uiobj_click_obj(int16_t oi, int mx, int my) { if ((mx < 0) || (mx >= UI_SCREEN_W) || (my < 0) || (my >= UI_SCREEN_H)) { return; } if (1/*mouse_flag_initialized*/) { uiobj_t *p = &uiobj_tbl[oi]; if (uiobj_focus_oi != oi) { if (uiobj_focus_oi != -1) { uiobj_t *q = &uiobj_tbl[uiobj_focus_oi]; /*if (uiobj_focus_oi != oi) { redundant, checked above */ if ((q->type != UIOBJ_TYPE_SETVAL) || (p->type == UIOBJ_TYPE_SETVAL)) { if (q->type == UIOBJ_TYPE_TEXTLINE) { if ((p->type == UIOBJ_TYPE_TEXTLINE) && p->ta.z12) { uiobj_handle_click(uiobj_focus_oi, false); } } else { uiobj_handle_click(uiobj_focus_oi, false); } } } uiobj_focus_oi = oi; uiobj_handle_click(oi, true); if (p->type == UIOBJ_TYPE_TEXTINPUT) { mx = moouse_x; my = moouse_y; } if (!ui_mouse_warp_disabled) { hw_mouse_set_xy(mx, my); } } } else { /*don't care*/ } } static void uiobj_finish_callback_delay_p(int delay) { if (uiobj_flag_have_cb) { ui_delay_prepare(); uiobj_do_callback(); ui_palette_set_n(); uiobj_finish_frame(); ui_delay_ticks_or_click(delay); } else { ui_delay_prepare(); ui_palette_set_n(); uiobj_finish_frame(); ui_delay_ticks_or_click(delay); /* MOO1 does not do this, but we need it to update mouse_* etc */ } } static void uiobj_finish_callback_delay_1(void) { uiobj_finish_callback_delay_p(1); } static void uiobj_finish_callback_delay_stored(void) { uiobj_finish_callback_delay_p(uiobj_delay); } static void uiobj_slider_plus(uiobj_t *p, int adj) { uint16_t vmin = p->t6.vmin; uint16_t value = *p->vptr; uint16_t vdiff = p->t6.vmax - vmin; int newval = ((value - vmin) * 100) / vdiff + adj; if (newval <= 100) { newval = (newval * vdiff) / 100 + vmin; if (newval == value) { ++newval; } } else { newval = p->t6.vmax; } value = newval; SETMIN(value, p->t6.vmax); *p->vptr = value; if (p->t6.cb) { p->t6.cb(p->t6.ctx, p->t6.slideri, value); } } static void uiobj_slider_minus(uiobj_t *p, int adj) { uint16_t vmin = p->t6.vmin; uint16_t value = *p->vptr; uint16_t vdiff = p->t6.vmax - vmin; int newval = ((value - vmin) * 100) / vdiff - adj; if (newval >= 0) { newval = (newval * vdiff) / 100 + vmin; } else { newval = p->t6.vmin; } value = newval; SETMAX(value, p->t6.vmin); *p->vptr = value; if (p->t6.cb) { p->t6.cb(p->t6.ctx, p->t6.slideri, value); } } static int16_t uiobj_handle_input_sub0(void) { int16_t oi = 0; uiobj_t *p, *q; int mx = moouse_x, my = moouse_y, mb; uiobj_focus_oi = -1; uiobj_clicked_oi = 0; uiobj_mouseoff = ui_cursor_mouseoff; if (kbd_have_keypress()) { uint32_t key = uiobj_handle_kbd(&oi); mookey_t k = KBD_GET_KEY(key); uint32_t kmod = KBD_GET_KEYMOD(key); char c = uiobj_get_keychar(key); if (k == MOO_KEY_UNKNOWN) { return 0; } /* checks for F11 and F12 debug keys omitted */ if (kmod == MOO_KEY_F1) { if (uiobj_help_id != -1) { ui_help(uiobj_help_id); } return 0; } if (kmod == MOO_KEY_ESCAPE) { return -1; } p = &uiobj_tbl[oi]; if (p->type == UIOBJ_TYPE_ALTSTR) { return oi; } if ((kmod == p->key) || (c && (c == p->key))) { if (p->type == UIOBJ_TYPE_SLIDER) { return 0; } if (oi != 0) { if (p->x0 == UIOBJ_OFFSCREEN) { mx = UIOBJ_OFFSCREEN; my = UIOBJ_OFFSCREEN; } else { mx = scmidx(p); my = scmidy(p); } uiobj_click_obj(oi, mx, my); if (p->type == UIOBJ_TYPE_TOGGLE) { if (*p->vptr == 0) { *p->vptr = 1; } else { *p->vptr = 0; } } else if (p->type == UIOBJ_TYPE_SET) { if (*p->vptr == 0) { *p->vptr = 1; } } } uiobj_finish_callback_delay_1(); uiobj_focus_oi = -1; return oi; } if (k == MOO_KEY_RETURN) { oi = uiobj_find_obj_at_cursor(); if (oi != 0) { p = &uiobj_tbl[oi]; if (p->type != UIOBJ_TYPE_SLIDER) { uiobj_click_obj(oi, mx, my); } if (p->type == UIOBJ_TYPE_TOGGLE) { if (*p->vptr == 0) { *p->vptr = 1; } else { *p->vptr = 0; } } else if (p->type == UIOBJ_TYPE_SET) { if (*p->vptr == 0) { *p->vptr = 1; } } if (uiobj_flag_skip_delay == 0) { uiobj_finish_callback_delay_1(); } uiobj_focus_oi = -1; return oi; } else { if (uiobj_flag_select_list_active) { for (oi = 1; oi < uiobj_table_num; ++oi) { p = &uiobj_tbl[oi]; if ((p->type == UIOBJ_TYPE_TEXTLINE) && (*p->vptr == p->ta.z18) && p->ta.z12) { uiobj_focus_oi = -1; return oi; } } } } } if ((c == '+') || (c == '-')) { oi = uiobj_find_obj_at_cursor(); if (oi != 0) { p = &uiobj_tbl[oi]; if (p->type == UIOBJ_TYPE_SLIDER) { if (c == '+') { uiobj_slider_plus(p, 5); } else { uiobj_slider_minus(p, 5); } uiobj_focus_oi = -1; return oi; } } } uiobj_focus_oi = -1; return 0; } if (mouse_scroll) { int scroll = mouse_scroll; mouse_scroll = 0; uiobj_focus_oi = -1; oi = 0; ui_cursor_update_gfx_i(mx, my); uiobj_mouseoff = ui_cursor_mouseoff; for (int i = 1; i < uiobj_table_num; ++i) { p = &uiobj_tbl[i]; if (((p->type == UIOBJ_TYPE_SLIDER) || (p->type == UIOBJ_TYPE_SCROLLAREA) || (p->type == UIOBJ_TYPE_WHEELAREA)) && uiobj_is_at_xy(p, mx, my)) { oi = i; break; } } if (oi != 0) { if (p->type == UIOBJ_TYPE_SLIDER) { if (ui_mwi_slider) { scroll = -scroll; } if (scroll > 0) { uiobj_slider_plus(p, scroll); } else { uiobj_slider_minus(p, -scroll); } return oi; } else if (p->type == UIOBJ_TYPE_SCROLLAREA) { uint8_t z = *p->tb.zptr; if (scroll < 0) { if (z < p->tb.zmax) { ++z; } else { return 0; } } else { if (z > 1) { --z; } else { return 0; } } *p->tb.zptr = z; *p->tb.xptr = -1; *p->tb.yptr = -1; return oi; } else if (p->type == UIOBJ_TYPE_WHEELAREA) { *p->vptr += scroll; return oi; } } return 0; } if (mouse_buttons == 0) { if (!mouse_getclear_click_hw()) { return 0; } mb = mouse_click_buttons; if (mb == MOUSE_BUTTON_MASK_RIGHT) { mouse_getclear_click_hw(); mouse_getclear_click_sw(); return -1; } else { mx = mouse_click_x; my = mouse_click_y; oi = 0; /*key = 0;*/ ui_cursor_update_gfx_i(mx, my); uiobj_mouseoff = ui_cursor_mouseoff; for (int oi2 = 0; oi2 < uiobj_table_num; ++oi2) { p = &uiobj_tbl[oi2]; if (!uiobj_is_at_xy(p, mx, my)) { continue; } oi = oi2; break; } p = &uiobj_tbl[oi]; if (oi != 0) { uiobj_clicked_oi = oi; uiobj_click_obj(oi, mx, my); uiobj_finish_callback_delay_1(); } uiobj_focus_oi = -1; if (oi != 0) { mouse_getclear_click_sw(); } { uiobj_clicked_oi = oi; if (mb == MOUSE_BUTTON_MASK_RIGHT) { return -oi; } else { return oi; } } } } else { mb = mouse_buttons; if (mb == MOUSE_BUTTON_MASK_RIGHT) { while ((mb = mouse_buttons) == MOUSE_BUTTON_MASK_RIGHT) { uiobj_finish_callback_delay_1(); } mouse_getclear_click_hw(); mouse_getclear_click_sw(); return -1; } if (ui_mouse_lmb_fix) { oi = uiobj_find_obj_at_cursor(); } while (mouse_buttons != 0) { mx = moouse_x; my = moouse_y; uiobj_mouseoff = ui_cursor_mouseoff; if (ui_mouse_lmb_fix) { if ((uiobj_tbl[oi].type == UIOBJ_TYPE_TEXTLINE) ||(uiobj_tbl[oi].type == UIOBJ_TYPE_SETVAL)) { int oi_next = uiobj_find_obj_at_cursor(); if ((oi_next != 0) && (uiobj_tbl[oi].type == uiobj_tbl[oi_next].type)) { oi = oi_next; } } } else { oi = uiobj_find_obj_at_cursor(); } if (oi == 0) { if (uiobj_focus_oi != -1) { p = &uiobj_tbl[uiobj_focus_oi]; if (p->type == UIOBJ_TYPE_SLIDER) { uiobj_do_callback(); } if ((p->type != UIOBJ_TYPE_SETVAL) && (p->type != UIOBJ_TYPE_TEXTLINE)) { uiobj_handle_click(uiobj_focus_oi, false); hw_mouse_set_xy(mx, my); } uiobj_focus_oi = -1; } mouse_set_click_xy(mx, my); break; } p = &uiobj_tbl[oi]; if ((oi != uiobj_focus_oi) && (p->type != UIOBJ_TYPE_TEXTINPUT)) { if (uiobj_focus_oi >= 0 && uiobj_tbl[uiobj_focus_oi].type == UIOBJ_TYPE_SLIDER) { uiobj_do_callback(); } uiobj_click_obj(oi, mx, my); } uiobj_clicked_oi = oi; if (uiobj_flag_skip_delay != 0) { break; } if (mouse_buttons != 0) { uiobj_finish_callback_delay_stored(); } } q = &uiobj_tbl[uiobj_clicked_oi]; if (q->type == UIOBJ_TYPE_SLIDER) { uiobj_do_callback(); } uiobj_clicked_oi = 0; if (oi != 0) { mouse_getclear_click_hw(); mouse_getclear_click_sw(); switch (p->type) { case UIOBJ_TYPE_SET: if (*p->vptr == 0) { *p->vptr = 1; } break; case UIOBJ_TYPE_TOGGLE: if (*p->vptr == 0) { *p->vptr = 1; } else { *p->vptr = 0; } break; case UIOBJ_TYPE_TEXTINPUT: uiobj_click_obj(oi, mx, my); default: break; } } uiobj_focus_oi = -1; if (ui_mouse_lmb_fix && (oi != uiobj_find_obj_at_cursor()) && (uiobj_tbl[oi].type != UIOBJ_TYPE_TEXTINPUT)) { return 0; } if (mb == MOUSE_BUTTON_MASK_RIGHT) { return -oi; } else { return oi; } } return 0; } static void uiobj_add_set_xys(uiobj_t *p, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t scale) { p->scale = scale; p->x0 = x0; p->y0 = y0; p->x1 = x1; p->y1 = y1; } static void uiobj_add_t03_do(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, mookey_t key, uint8_t scale) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x, y, x + lbxgfx_get_w(lbxdata) - 1, y + lbxgfx_get_h(lbxdata) - 1, scale); p->t0.str = str; p->t0.fontnum = lbxfont_get_current_fontnum(); p->t0.fonta2 = lbxfont_get_current_fonta2(); p->t0.lbxdata = lbxdata; p->t0.indep = lbxgfx_get_indep(lbxdata); p->key = key; } static void uiobj_handle_objects(void) { for (int i = 1; i < uiobj_table_num; ++i) { uiobj_t *p = &uiobj_tbl[i]; if ((i == uiobj_focus_oi) && (p->type != UIOBJ_TYPE_TEXTINPUT)) { uiobj_handle_click(i, true); } else { uiobj_handle_objects_sub1(i); } } } /* -------------------------------------------------------------------------- */ void uiobj_table_clear(void) { uiobj_table_num = 1; uiobj_focus_oi = -1; uiobj_clicked_oi = 0; } void uiobj_table_set_last(int16_t oi) { uiobj_table_num = oi + 1; uiobj_focus_oi = -1; } void uiobj_table_num_store(void) { uiobj_table_num_old = uiobj_table_num; uiobj_table_num = 0; uiobj_flag_have_cb = false; } void uiobj_table_num_restore(void) { uiobj_table_num = uiobj_table_num_old; if (uiobj_callback) { uiobj_flag_have_cb = true; } } int16_t uiobj_handle_input_cond(void) { if (uiobj_handle_downcount > 0) { --uiobj_handle_downcount; return 0; } uiobj_handle_downcount = 0; if (uiobj_table_num <= 1) { return 0; } if (1/*mouse_initialized*/) { return uiobj_handle_input_sub0(); } else { return 0;/*uiobj_handle_input_sub1();*/ } } void uiobj_finish_frame(void) { int mx, my; mx = moouse_x; my = moouse_y; uiobj_handle_objects(); ui_cursor_update_gfx_i(mx, my); ui_cursor_store_bg1(mx, my); ui_cursor_draw1(mx, my); hw_video_draw_buf(); /* HACK MOO1 maintains the bg for both buffers, we simply erase the cursor right after draw. */ ui_cursor_copy_bg1_to_bg0(); ui_cursor_erase0(); } void uiobj_set_downcount(int16_t v) { uiobj_handle_downcount = v; mouse_getclear_click_hw(); mouse_getclear_click_sw(); } void uiobj_set_xyoff(int xoff, int yoff) { uiobj_xoff = xoff; uiobj_yoff = yoff; } void uiobj_set_limits(int minx, int miny, int maxx, int maxy) { SETMAX(minx, 0); SETMAX(miny, 0); SETMIN(maxx, UI_SCREEN_W - 1); SETMIN(maxy, UI_SCREEN_H - 1); if (minx > maxx) { int t = minx; minx = maxx; maxx = t; } if (miny > maxy) { int t = miny; miny = maxy; maxy = t; } uiobj_minx = minx; uiobj_miny = miny; uiobj_maxx = maxx; uiobj_maxy = maxy; } void uiobj_set_limits_all(void) { uiobj_minx = 0; uiobj_miny = 0; uiobj_maxx = UI_SCREEN_W - 1; uiobj_maxy = UI_SCREEN_H - 1; } void uiobj_set_help_id(int16_t v) { uiobj_help_id = v; } int16_t uiobj_get_clicked_oi(void) { return uiobj_clicked_oi; } void uiobj_set_skip_delay(bool v) { uiobj_flag_skip_delay = v; } void uiobj_set_callback_and_delay(void (*cb)(void *), void *data, uint16_t delay) { uiobj_callback = cb; uiobj_cbdata = data; uiobj_flag_have_cb = true; uiobj_delay = ((delay > 0) && (delay < 10)) ? delay : 2; } void uiobj_unset_callback(void) { uiobj_callback = NULL; uiobj_cbdata = NULL; uiobj_flag_have_cb = false; } void uiobj_do_callback(void) { if (uiobj_flag_have_cb) { uiobj_callback(uiobj_cbdata); } } void uiobj_set_focus_forced(int16_t uiobji) { uiobj_t *p = &uiobj_tbl[uiobji]; int x, y; x = scmidx(p); y = scmidy(p); if ((y < 0) || (y >= UI_SCREEN_H) || (x < 0) || (x >= UI_SCREEN_W)) { return; } ui_cursor_update_gfx_i(x, y); uiobj_mouseoff = ui_cursor_mouseoff; x -= uiobj_mouseoff; y -= uiobj_mouseoff; hw_mouse_set_xy(x, y); /* needed anywhere? */ mouse_stored_x = x; mouse_stored_y = y; } void uiobj_set_focus(int16_t uiobji) { if (!ui_mouse_warp_disabled) { uiobj_set_focus_forced(uiobji); } } int16_t uiobj_find_obj_at_cursor(void) { int x = moouse_x, y = moouse_y; ui_cursor_update_gfx_i(x, y); uiobj_mouseoff = ui_cursor_mouseoff; for (int i = 1; i < uiobj_table_num; ++i) { uiobj_t *p = &uiobj_tbl[i]; if (!uiobj_is_at_xy(p, x, y)) { continue; } return i; } return 0; } int16_t uiobj_at_cursor(void) { uiobj_t *p; int i, x = moouse_x, y = moouse_y; ui_cursor_update_gfx_i(x, y); uiobj_mouseoff = ui_cursor_mouseoff; i = uiobj_find_obj_at_cursor(); p = &uiobj_tbl[i]; if ((p->type == UIOBJ_TYPE_TEXTLINE) && !p->ta.z12) { i = 0; } return i; } int16_t uiobj_add_t0(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_t03_do(x, y, str, lbxdata, key, ui_scale); p->type = UIOBJ_TYPE_BUTTON; p->vptr = 0; return uiobj_alloc(); } int16_t uiobj_add_t1(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_t03_do(x, y, str, lbxdata, key, ui_scale); p->type = UIOBJ_TYPE_TOGGLE; p->vptr = vptr; return uiobj_alloc(); } int16_t uiobj_add_t2(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_t03_do(x, y, str, lbxdata, key, ui_scale); p->type = UIOBJ_TYPE_SET; p->vptr = vptr; return uiobj_alloc(); } int16_t uiobj_add_t3(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, int16_t z18, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_t03_do(x, y, str, lbxdata, key, ui_scale); p->type = UIOBJ_TYPE_SETVAL; p->vptr = vptr; p->t0.z18 = z18; return uiobj_alloc(); } int16_t uiobj_add_textinput(int x, int y, int w, char *buf, uint16_t max_chars, uint8_t rcolor, bool alignr, bool allow_lcase, const uint8_t *colortbl, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x, y, x + w, y + lbxfont_get_height(), ui_scale); p->t4.fontnum = lbxfont_get_current_fontnum(); p->t4.fonta2 = lbxfont_get_current_fonta2(); p->t4.fonta4 = lbxfont_get_current_fonta2b(); p->t4.max_chars = max_chars; p->t4.buf = buf; p->t4.rectcolor = rcolor; p->t4.align_right = alignr; p->t4.allow_lcase = allow_lcase; p->t4.colortbl = colortbl; p->type = UIOBJ_TYPE_TEXTINPUT; p->vptr = 0; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_slider_int(uint16_t x0, uint16_t y0, uint16_t vmin, uint16_t vmax, uint16_t w, uint16_t h, int16_t *vptr) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x0, y0, x0 + w, y0 + h, ui_scale); p->t6.vmin = vmin; p->t6.vmax = vmax; p->type = UIOBJ_TYPE_SLIDER; p->key = MOO_KEY_UNKNOWN; p->vptr = vptr; p->t6.cb = 0; p->t6.ctx = 0; p->t6.slideri = 0; return uiobj_alloc(); } int16_t uiobj_add_slider_func(uint16_t x0, uint16_t y0, uint16_t vmin, uint16_t vmax, uint16_t w, uint16_t h, int16_t *vptr, void (*cb)(void *ctx, uint8_t slideri, int16_t value), void *ctx, uint8_t slideri) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x0, y0, x0 + w, y0 + h, ui_scale); p->t6.vmin = vmin; p->t6.vmax = vmax; p->type = UIOBJ_TYPE_SLIDER; p->key = MOO_KEY_UNKNOWN; p->vptr = vptr; p->t6.cb = cb; p->t6.ctx = ctx; p->t6.slideri = slideri; return uiobj_alloc(); } int16_t uiobj_add_mousearea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x0, y0, x1, y1, ui_scale); p->type = UIOBJ_TYPE_MOUSEAREA; p->vptr = 0; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_mousearea_limited(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t scale, mookey_t key) { uiobj_t *p; if ((x1 < uiobj_minx) || (x0 > uiobj_maxx) || (y1 < uiobj_miny) || (y0 > uiobj_maxy)) { return UIOBJI_OUTSIDE; } p = &uiobj_tbl[uiobj_table_num]; x0 = MAX(x0, uiobj_minx); x1 = MIN(x1, uiobj_maxx); y0 = MAX(y0, uiobj_miny); y1 = MIN(y1, uiobj_maxy); uiobj_add_set_xys(p, x0, y0, x1, y1, scale); p->type = UIOBJ_TYPE_MOUSEAREA; p->vptr = 0; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_mousewheel(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int16_t *vptr) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x0, y0, x1, y1, ui_scale); p->type = UIOBJ_TYPE_WHEELAREA; p->vptr = vptr; p->key = MOO_KEY_UNKNOWN; return uiobj_alloc(); } int16_t uiobj_add_mousearea_all(mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, 0, 0, UI_SCREEN_W - 1, UI_SCREEN_H - 1, 1); p->type = UIOBJ_TYPE_MOUSEAREA; p->vptr = 0; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_inputkey(uint32_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; p->x0 = UIOBJ_OFFSCREEN; p->y0 = UIOBJ_OFFSCREEN; p->x1 = UIOBJ_OFFSCREEN; p->y1 = UIOBJ_OFFSCREEN; p->scale = 1; p->type = UIOBJ_TYPE_MOUSEAREA; p->vptr = 0; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_alt_str(const char *str) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; int len = 0; while ((str[len] != 0) && (len < 0x1e)) { ++len; } p->x0 = UIOBJ_OFFSCREEN; p->y0 = UIOBJ_OFFSCREEN; p->x1 = UIOBJ_OFFSCREEN; p->y1 = UIOBJ_OFFSCREEN; p->scale = 1; p->type = UIOBJ_TYPE_ALTSTR; p->vptr = 0; p->t8.str = str; p->t8.pos = 0; p->t8.len = len; { char b = *str; if ((b >= 'a') && (b <= 'z')) { b -= 'a' - 'A'; } p->key = b; } return uiobj_alloc(); } int16_t uiobj_add_ta(uint16_t x, uint16_t y, uint16_t w, const char *str, bool z12, int16_t *vptr, int16_t z18, uint8_t subtype, uint8_t sp0v, mookey_t key) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x, y - 1, x + w, y + lbxfont_get_height() + 1, ui_scale); p->ta.fontnum = lbxfont_get_current_fontnum(); p->ta.fonta2 = lbxfont_get_current_fonta2(); p->ta.fonta2b = lbxfont_get_current_fonta2b(); p->ta.z18 = z18; p->ta.z12 = z12; p->ta.str = str; p->ta.subtype = subtype; p->ta.sp0v = sp0v; p->type = UIOBJ_TYPE_TEXTLINE; p->vptr = vptr; p->key = key; return uiobj_alloc(); } int16_t uiobj_add_tb(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t xscale, uint16_t yscale, int16_t *xptr, int16_t *yptr, uint8_t *zptr, uint8_t zmax) { uiobj_t *p = &uiobj_tbl[uiobj_table_num]; uiobj_add_set_xys(p, x, y, x + w * xscale, y + h * yscale, ui_scale); p->tb.xdiv = w * ui_scale; p->tb.ydiv = h * ui_scale; p->tb.xptr = xptr; p->tb.yptr = yptr; p->tb.zptr = zptr; p->tb.zmax = zmax; p->type = UIOBJ_TYPE_SCROLLAREA; p->vptr = 0; p->key = MOO_KEY_UNKNOWN; return uiobj_alloc(); } void uiobj_dec_y1(int16_t oi) { uiobj_t *p = &uiobj_tbl[oi]; --p->y1; } void uiobj_ta_set_val_0(int16_t oi) { uiobj_t *p = &uiobj_tbl[oi]; if (p->type == UIOBJ_TYPE_TEXTLINE) { *p->vptr = 0; } } void uiobj_ta_set_val_1(int16_t oi) { uiobj_t *p = &uiobj_tbl[oi]; if (p->type == UIOBJ_TYPE_TEXTLINE) { *p->vptr = 1; } } int16_t uiobj_select_from_list3(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, uint8_t subtype, uint8_t sp0v, bool update_at_cursor, bool add_switch, int sx, int sy) { int h, dy, ty = y, di = -1; bool flag_done = false, toz12, flag_copy_buf = false; uint16_t itemi = 0, v6 = 0; int16_t oi = 0, oi_title, v18 = 0; int16_t oi_switch = UIOBJI_INVALID; char const * const *s = strtbl; uiobj_flag_select_list_active = true; uiobj_set_downcount(1); uiobj_table_clear(); h = lbxfont_get_height(); dy = lbxfont_get_gap_h() + h; while (!flag_done) { if (*s == 0) { flag_done = true; break; } if (!v6) { if ((!condtbl) || condtbl[itemi]) { di = itemi; v6 = 1; } } /*18a50*/ ty += dy; if (!condtbl) { toz12 = true; } else { toz12 = condtbl[itemi]; } uiobj_add_ta(x, ty, w, *s, toz12, selptr, itemi, subtype, sp0v, MOO_KEY_UNKNOWN); ++itemi; ++s; } v6 = itemi; lbxfont_select(lbxfont_get_current_fontnum(), lbxfont_get_current_fonta2(), lbxfont_get_current_fonta4(), 0); oi_title = uiobj_add_ta(x, y, w, title, false, &v18, 1, 0, 0, MOO_KEY_UNKNOWN); if (add_switch) { oi_switch = uiobj_add_mousearea(120, sy + 3, 200, sy + 11, MOO_KEY_UNKNOWN); } if ((*selptr < 0) || (*selptr >= v6) || (*selptr < di)) { if ((di >= 0) && (di < v6)) { *selptr = uiobj_tbl[di + 1].ta.z18; } else { *selptr = -1; } } flag_done = false; oi = 0; while (!flag_done) { ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi == oi_switch) { flag_done = true; break; } if (oi != 0) { flag_done = true; } if ((oi == oi_title) || ((oi > 0) && condtbl && !condtbl[oi - 1])) { flag_done = false; } if (flag_done) { break; } uiobj_do_callback(); if (update_at_cursor) { int oi2; oi2 = uiobj_at_cursor(); if (oi2 > 0) { *selptr = uiobj_tbl[oi2].ta.z18; } } ui_palette_set_n(); uiobj_finish_frame(); if (!flag_copy_buf) { ui_draw_copy_buf(); flag_copy_buf = true; } ui_delay_ticks_or_click(uiobj_delay); } uiobj_table_clear(); uiobj_flag_select_list_active = false; mouse_getclear_click_hw(); mouse_getclear_click_sw(); if (oi == oi_switch) { return -2; } if (oi < 0) { return -1; } return oi - 1; } int16_t uiobj_select_from_list1(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, uint8_t subtype, uint8_t sp0v, bool update_at_cursor) { return uiobj_select_from_list3(x, y, w, title, strtbl, selptr, condtbl, subtype, sp0v, update_at_cursor, false, 0, 0); } int16_t uiobj_select_from_list4(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, int linenum, int upx, int upy, uint8_t *uplbx, int dnx, int dny, uint8_t *dnlbx, uint8_t subtype, uint8_t sp0v, bool update_at_cursor, bool add_switch, int sx, int sy) { int h, dy, ty, linei = 0, itemi = 0, itemnum, itemoffs, foundi = 0; bool flag_done = false, flag_copy_buf = false, flag_found = false; uint16_t fonta4, fonta2b; int16_t oi = 0, oi_title, oi_up, oi_dn, oi_wheel, v18 = 0, upvar, dnvar, curval, scroll = 0; int16_t oi_switch = UIOBJI_INVALID; char const * const *s = strtbl; uiobj_flag_select_list_active = true; uiobj_flag_select_list_multipage = true; uiobj_kbd_movey = 0; fonta4 = lbxfont_get_current_fonta4(); fonta2b = lbxfont_get_current_fonta2b(); uiobj_set_downcount(1); uiobj_table_clear(); h = lbxfont_get_height(); dy = lbxfont_get_gap_h() + h; ty = y + dy; while (!flag_done) { if (*s == 0) { flag_done = true; break; } if (!flag_found) { if ((!condtbl) || condtbl[itemi]) { foundi = itemi; flag_found = true; } } ++itemi; ++s; } itemnum = itemi; { int i; i = *selptr; if ((i < 0) || (i >= itemnum)) { i = 0; } if ((i + linenum) > itemnum) { i = itemnum - linenum; SETMAX(i, 0); } itemoffs = i; } s = &strtbl[itemoffs]; for (itemi = itemoffs; (itemi < itemnum) && (linei < linenum); ++itemi, ++linei, ++s, ty += dy) { uiobj_add_ta(x, ty, w, *s, (!condtbl) || condtbl[itemi], selptr, itemi, subtype, sp0v, MOO_KEY_UNKNOWN); } if ((*selptr < 0) || (*selptr >= itemnum)) { if ((foundi >= 0) && (foundi < itemnum)) { *selptr = itemoffs; } else { *selptr = -1; } } lbxfont_select(lbxfont_get_current_fontnum(), lbxfont_get_current_fonta2(), fonta4, 0); oi_title = uiobj_add_ta(x, y, w, title, false, &v18, 1, 0, 0, MOO_KEY_UNKNOWN); upvar = (itemoffs == 0) ? 1 : 0; dnvar = (itemi >= itemnum) ? 1 : 0; oi_up = uiobj_add_t2(upx, upy, "", uplbx, &upvar, MOO_KEY_PAGEUP); oi_dn = uiobj_add_t2(dnx, dny, "", dnlbx, &dnvar, MOO_KEY_PAGEDOWN); if (add_switch) { oi_switch = uiobj_add_mousearea(120, sy + 3, 200, sy + 11, MOO_KEY_UNKNOWN); } oi_wheel = uiobj_add_mousewheel(0, 0, 319, 199, &scroll); flag_done = false; curval = *selptr; while (!flag_done) { bool flag_rebuild; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi < 0) || ((oi > 0) && (oi < oi_title) && uiobj_tbl[oi].ta.z12)) { flag_done = true; break; } flag_rebuild = false; if (oi == oi_up) { itemoffs -= linenum; SETMAX(itemoffs, 0); flag_rebuild = true; } else if (oi == oi_dn) { int i; i = itemoffs + linenum; if ((i + linenum) > itemnum) { i = itemnum - linenum; SETMAX(i, 0); } if (i >= itemnum) { i = itemoffs; } itemoffs = i; flag_rebuild = true; } else if (oi == oi_wheel) { int i; i = itemoffs + scroll; scroll = 0; if ((i + linenum) > itemnum) { i = itemnum - linenum; } SETMAX(i, 0); if (i >= itemnum) { i = itemoffs; } itemoffs = i; flag_rebuild = true; } else if (oi == oi_switch) { flag_done = true; break; } if (uiobj_kbd_movey == 1) { int i, j; i = itemoffs + 1; j = itemoffs + linenum; while ((j < itemnum) && condtbl && (!condtbl[j])) { ++j; ++i; } if (j >= itemnum) { i = itemoffs; } if ((i + linenum) > itemnum) { i = itemnum - linenum; SETMAX(i, 0); } itemoffs = i; flag_rebuild = true; } else if (uiobj_kbd_movey == -1) { int i; i = itemoffs - 1; SETMAX(i, 0); while ((i >= 0) && condtbl && (!condtbl[i])) { --i; } SETMAX(i, 0); itemoffs = i; flag_rebuild = true; } if (flag_rebuild) { uiobj_table_clear(); lbxfont_select(lbxfont_get_current_fontnum(), lbxfont_get_current_fonta2(), fonta2b, 0); *selptr = -1; if (uiobj_kbd_movey == 1) { if ((!condtbl) || condtbl[itemoffs + linenum - 1]) { *selptr = itemoffs + linenum - 1; } else { for (int i = itemoffs + linenum - 1; i > 0; --i) { if ((!condtbl) || condtbl[i]) { *selptr = i; break; } } } } else { if ((!condtbl) || condtbl[itemoffs]) { *selptr = itemoffs; } else { for (int i = itemoffs; i < (itemoffs + linenum); ++i) { if ((!condtbl) || condtbl[i]) { *selptr = i; break; } } } } s = &strtbl[itemoffs]; linei = 0; ty = y + dy; for (itemi = itemoffs; (itemi < itemnum) && (linei < linenum); ++itemi, ++linei, ++s, ty += dy) { uiobj_add_ta(x, ty, w, *s, (!condtbl) || condtbl[itemi], selptr, itemi, subtype, sp0v, MOO_KEY_UNKNOWN); } lbxfont_select(lbxfont_get_current_fontnum(), lbxfont_get_current_fonta2(), fonta4, 0); oi_title = uiobj_add_ta(x, y, w, title, false, &v18, 1, 0, 0, MOO_KEY_UNKNOWN); upvar = (itemoffs == 0) ? 1 : 0; dnvar = (itemi >= itemnum) ? 1 : 0; oi_up = uiobj_add_t2(upx, upy, "", uplbx, &upvar, MOO_KEY_PAGEUP); oi_dn = uiobj_add_t2(dnx, dny, "", dnlbx, &dnvar, MOO_KEY_PAGEDOWN); if (add_switch) { oi_switch = uiobj_add_mousearea(120, sy + 3, 200, sy + 11, MOO_KEY_UNKNOWN); } oi_wheel = uiobj_add_mousewheel(0, 0, 319, 199, &scroll); } uiobj_kbd_movey = 0; if (update_at_cursor) { int oi2; oi2 = uiobj_at_cursor(); if (oi2 > 0) { *selptr = uiobj_tbl[oi2].ta.z18; } } uiobj_do_callback(); ui_palette_set_n(); uiobj_finish_frame(); if (!flag_copy_buf) { ui_draw_copy_buf(); flag_copy_buf = true; } ui_delay_ticks_or_click(uiobj_delay); } uiobj_table_clear(); uiobj_flag_select_list_active = false; uiobj_flag_select_list_multipage = false; mouse_getclear_click_hw(); mouse_getclear_click_sw(); if (oi == oi_switch) { *selptr = curval; return -2; } if (oi < 0) { *selptr = curval; return -1; } return oi + itemoffs - 1; } int16_t uiobj_select_from_list2(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, int linenum, int upx, int upy, uint8_t *uplbx, int dnx, int dny, uint8_t *dnlbx, uint8_t subtype, uint8_t sp0v, bool update_at_cursor) { return uiobj_select_from_list4(x, y, w, title, strtbl, selptr, condtbl, linenum, upx, upy, uplbx, dnx, dny, dnlbx, subtype, sp0v, update_at_cursor, false, 0, 0); } bool uiobj_read_str(int x, int y, int w, char *buf, int max_chars, uint8_t rcolor, bool alignr, const uint8_t *ctbl) { bool flag_quit = false; uiobj_t *p; uiobj_table_clear(); if (1/*mouse_flag_initialized*/) { while (mouse_buttons) { hw_event_handle(); } mouse_getclear_click_hw(); mouse_getclear_click_sw(); } uiobj_set_downcount(1); { int16_t oi = uiobj_add_textinput(x, y, w, buf, max_chars, rcolor, alignr, false, ctbl, MOO_KEY_UNKNOWN); uiobj_focus_oi = oi; p = &uiobj_tbl[oi]; } flag_quit = uiobj_textinput_do(p, w, buf, max_chars, true, false); uiobj_table_clear(); return !flag_quit; } void uiobj_input_flush(void) { uiobj_clicked_oi = 0; while (kbd_have_keypress()) { kbd_get_keypress(); } while (mouse_buttons) { uiobj_finish_callback_delay_stored(); } } void uiobj_input_wait(void) { bool got_any = false, got_mb = false; uiobj_input_flush(); while (!got_any) { if (mouse_buttons || mouse_getclear_click_hw()) { got_any = true; got_mb = true; } if (kbd_have_keypress()) { uint32_t kp; mookey_t k; kp = kbd_get_keypress(); k = KBD_GET_KEY(kp); if ((k != MOO_KEY_UNKNOWN) && ((k < MOO_KEY_NUMLOCK) || (k > MOO_KEY_COMPOSE))) { got_any = true; mouse_getclear_click_hw(); } } uiobj_finish_callback_delay_stored(); } if (got_mb) { while (mouse_buttons) { uiobj_finish_callback_delay_stored(); } } mouse_getclear_click_hw(); mouse_getclear_click_sw(); } 1oom-1.11.2/src/ui/classic/uiobj.h000066400000000000000000000131651476061725400165770ustar00rootroot00000000000000#ifndef INC_1OOM_UIOBJ_H #define INC_1OOM_UIOBJ_H #include "kbd.h" #include "types.h" #define UIOBJI_NONE 0 #define UIOBJI_ESC -1 #define UIOBJI_INVALID -1000 #define UIOBJI_OUTSIDE -10000 #define UIOBJI_SET_TBL_INVALID(name) do { for (int i = 0; i < (sizeof(name)/sizeof(name[0])); ++i) { name[i] = UIOBJI_INVALID; } } while (0) #define UIOBJI_SET_TBL2_INVALID(n0_, n1_) do { for (int i_ = 0; i_ < (sizeof(n0_)/sizeof(n0_[0])); ++i_) { n0_[i_] = UIOBJI_INVALID; n1_[i_] = UIOBJI_INVALID; } } while (0) #define UIOBJI_SET_TBL3_INVALID(n0_, n1_, n2_) do { for (int i_ = 0; i_ < (sizeof(n0_)/sizeof(n0_[0])); ++i_) { n0_[i_] = UIOBJI_INVALID; n1_[i_] = UIOBJI_INVALID; n2_[i_] = UIOBJI_INVALID; } } while (0) #define UIOBJI_SET_TBL4_INVALID(n0_, n1_, n2_, n3_) do { for (int i_ = 0; i_ < (sizeof(n0_)/sizeof(n0_[0])); ++i_) { n0_[i_] = UIOBJI_INVALID; n1_[i_] = UIOBJI_INVALID; n2_[i_] = UIOBJI_INVALID; n3_[i_] = UIOBJI_INVALID; } } while (0) #define UIOBJI_SET_TBL5_INVALID(n0_, n1_, n2_, n3_, n4_) do { for (int i_ = 0; i_ < (sizeof(n0_)/sizeof(n0_[0])); ++i_) { n0_[i_] = UIOBJI_INVALID; n1_[i_] = UIOBJI_INVALID; n2_[i_] = UIOBJI_INVALID; n3_[i_] = UIOBJI_INVALID; n4_[i_] = UIOBJI_INVALID; } } while (0) #define UIOBJI_SET_TBL6_INVALID(n0_, n1_, n2_, n3_, n4_, n5_) do { for (int i_ = 0; i_ < (sizeof(n0_)/sizeof(n0_[0])); ++i_) { n0_[i_] = UIOBJI_INVALID; n1_[i_] = UIOBJI_INVALID; n2_[i_] = UIOBJI_INVALID; n3_[i_] = UIOBJI_INVALID; n4_[i_] = UIOBJI_INVALID; n5_[i_] = UIOBJI_INVALID; } } while (0) /* HACK for lbxgfx_draw_frame_offs params */ extern int uiobj_minx; extern int uiobj_miny; extern int uiobj_maxx; extern int uiobj_maxy; extern void uiobj_table_clear(void); extern void uiobj_table_set_last(int16_t oi); extern void uiobj_table_num_store(void); extern void uiobj_table_num_restore(void); extern int16_t uiobj_handle_input_cond(void); extern void uiobj_finish_frame(void); extern void uiobj_set_downcount(int16_t v); extern void uiobj_set_xyoff(int xoff, int yoff); extern void uiobj_set_limits(int minx, int miny, int maxx, int maxy); extern void uiobj_set_limits_all(void); extern void uiobj_set_focus_forced(int16_t uiobji); extern void uiobj_set_focus(int16_t uiobji); extern void uiobj_set_help_id(int16_t v); extern int16_t uiobj_get_clicked_oi(void); extern void uiobj_set_skip_delay(bool v); extern int16_t uiobj_find_obj_at_cursor(void); extern int16_t uiobj_at_cursor(void); extern void uiobj_set_callback_and_delay(void (*cb)(void *), void *data, uint16_t delay); extern void uiobj_unset_callback(void); extern void uiobj_do_callback(void); extern int16_t uiobj_add_t0(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, mookey_t key); extern int16_t uiobj_add_t1(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, mookey_t key); extern int16_t uiobj_add_t2(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, mookey_t key); extern int16_t uiobj_add_t3(uint16_t x, uint16_t y, const char *str, uint8_t *lbxdata, int16_t *vptr, int16_t z18, mookey_t key); extern int16_t uiobj_add_textinput(int x, int y, int w, char *buf, uint16_t buflen, uint8_t rcolor, bool alignr, bool allow_lcase, const uint8_t *colortbl, mookey_t key); extern int16_t uiobj_add_slider_int(uint16_t x0, uint16_t y0, uint16_t vmin, uint16_t vmax, uint16_t w, uint16_t h, int16_t *vptr); extern int16_t uiobj_add_slider_func(uint16_t x0, uint16_t y0, uint16_t vmin, uint16_t vmax, uint16_t w, uint16_t h, int16_t *vptr, void (*cb)(void *ctx, uint8_t slideri, int16_t value), void *ctx, uint8_t slideri); extern int16_t uiobj_add_mousearea(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, mookey_t key); extern int16_t uiobj_add_mousewheel(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, int16_t *vptr); extern int16_t uiobj_add_mousearea_limited(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint8_t scale, mookey_t key); extern int16_t uiobj_add_mousearea_all(mookey_t key); extern int16_t uiobj_add_inputkey(uint32_t key); extern int16_t uiobj_add_alt_str(const char *str); extern int16_t uiobj_add_ta(uint16_t x, uint16_t y, uint16_t w, const char *str, bool z12, int16_t *vptr, int16_t z18, uint8_t subtype, uint8_t sp0v, mookey_t key); extern int16_t uiobj_add_tb(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t xscale, uint16_t yscale, int16_t *xptr, int16_t *yptr, uint8_t *zptr, uint8_t zmax); extern void uiobj_dec_y1(int16_t oi); extern void uiobj_ta_set_val_0(int16_t oi); extern void uiobj_ta_set_val_1(int16_t oi); extern int16_t uiobj_select_from_list1(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, uint8_t subtype, uint8_t sp0v, bool update_at_cursor); extern int16_t uiobj_select_from_list2(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, int linenum, int upx, int upy, uint8_t *uplbx, int dnx, int dny, uint8_t *dnlbx, uint8_t subtype, uint8_t sp0v, bool update_at_cursor); extern int16_t uiobj_select_from_list3(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, uint8_t subtype, uint8_t sp0v, bool update_at_cursor, bool add_switch, int sx, int sy); extern int16_t uiobj_select_from_list4(int x, int y, int w, const char *title, char const * const *strtbl, int16_t *selptr, const bool *condtbl, int linenum, int upx, int upy, uint8_t *uplbx, int dnx, int dny, uint8_t *dnlbx, uint8_t subtype, uint8_t sp0v, bool update_at_cursor, bool add_switch, int sx, int sy); extern bool uiobj_read_str(int x, int y, int w, char *buf, int buflen, uint8_t rcolor, bool alignr, const uint8_t *ctbl); extern void uiobj_input_flush(void); extern void uiobj_input_wait(void); #endif 1oom-1.11.2/src/ui/classic/uipal.c000066400000000000000000000055661476061725400166020ustar00rootroot00000000000000#include "config.h" #include #include "uipal.h" #include "hw.h" #include "os.h" #include "lbxpal.h" #include "types.h" #include "uidelay.h" /* -------------------------------------------------------------------------- */ static void fadeout_do(int start, int step, int delay) { for (uint16_t v = start; v < 0x65; v += step) { ui_delay_prepare(); lbxpal_set_update_range(0, 255); ui_palette_fade_n(v); ui_delay_ticks_or_click(delay); } } static void fadein_do(int start, int step, int delay) { for (int v = start; v >= 0; v -= step) { ui_delay_prepare(); lbxpal_set_update_range(0, 255); ui_palette_fade_n(v); ui_delay_ticks_or_click(delay); } } static void ui_palette_update(void) { memset(lbxpal_update_flag, 0, sizeof(lbxpal_update_flag)); hw_video_refresh_palette(); } /* -------------------------------------------------------------------------- */ void ui_palette_set_n(void) { int i, j; bool got_update = false; /* wait_retrace */ for (i = j = 0; j < 256; ++j, i += 3) { if (lbxpal_update_flag[j] != 0) { hw_video_set_palette_color(j, lbxpal_palette[i], lbxpal_palette[i + 1], lbxpal_palette[i + 2]); got_update = true; } } if (got_update) { ui_palette_update(); } } void ui_palette_fade_n(uint16_t fadepercent) { int v, i, j; v = 100 - fadepercent; if (v <= 0) { /* wait_retrace */ for (j = 0; j < 256; ++j) { if (lbxpal_update_flag[j] != 0) { hw_video_set_palette_color(j, 0, 0, 0); } } } else if (v >= 100) { ui_palette_set_n(); return; } else { v = ((v * 0x100) / 100) & 0xff; /* wait_retrace */ for (i = j = 0; j < 256; ++j, i += 3) { if (lbxpal_update_flag[j] != 0) { hw_video_set_palette_color(j, (((uint16_t)lbxpal_palette[i]) * v) >> 8, (((uint16_t)lbxpal_palette[i + 1]) * v) >> 8, (((uint16_t)lbxpal_palette[i + 2]) * v) >> 8); } } } ui_palette_update(); } void ui_palette_fadeout_19_19_1(void) { fadeout_do(0x19, 0x19, 1); } void ui_palette_fadeout_14_14_2(void) { fadeout_do(0x14, 0x14, 2); } void ui_palette_fadeout_a_f_1(void) { fadeout_do(0xa, 0xf, 1); } void ui_palette_fadeout_4_3_1(void) { fadeout_do(4, 3, 1); } void ui_palette_fadeout_5_5_1(void) { fadeout_do(5, 5, 1); } void ui_palette_fadein_60_3_1(void) { fadein_do(0x60, 3, 1); } void ui_palette_fadein_5f_5_1(void) { fadein_do(0x5f, 5, 1); } void ui_palette_fadein_5a_f_1(void) { fadein_do(0x5f, 0xf, 1); } void ui_palette_fadein_50_14_2(void) { fadein_do(0x50, 0x14, 2); } void ui_palette_fadein_4b_19_1(void) { fadein_do(0x4b, 0x19, 1); } 1oom-1.11.2/src/ui/classic/uipal.h000066400000000000000000000012231476061725400165710ustar00rootroot00000000000000#ifndef INC_1OOM_UIPAL_H #define INC_1OOM_UIPAL_H #include "types.h" extern void ui_palette_set_n(void); extern void ui_palette_fade_n(uint16_t fadepercent); extern void ui_palette_fade_wait_1s(void); extern void ui_palette_fadeout_19_19_1(void); extern void ui_palette_fadeout_14_14_2(void); extern void ui_palette_fadeout_a_f_1(void); extern void ui_palette_fadeout_4_3_1(void); extern void ui_palette_fadeout_5_5_1(void); extern void ui_palette_fadein_60_3_1(void); extern void ui_palette_fadein_5f_5_1(void); extern void ui_palette_fadein_5a_f_1(void); extern void ui_palette_fadein_50_14_2(void); extern void ui_palette_fadein_4b_19_1(void); #endif 1oom-1.11.2/src/ui/classic/uiplanets.c000066400000000000000000000641301476061725400174640ustar00rootroot00000000000000#include "config.h" #include #include #include "uiplanets.h" #include "comp.h" #include "game.h" #include "game_cheat.h" #include "game_misc.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ #define PLANETS_ON_SCREEN 12 struct planets_data_s { player_id_t api; int pos; int num; int16_t amount_trans; uint8_t focus_i; int planet_i; int order_i; struct game_s *g; uint8_t *gfx_report; uint8_t *gfx_but_trans; uint8_t *gfx_but_ok; uint8_t *gfx_transfer; }; static void load_pl_data(struct planets_data_s *d) { d->gfx_report = lbxfile_item_get(LBXFILE_BACKGRND, 1); d->gfx_but_trans = lbxfile_item_get(LBXFILE_BACKGRND, 0x1c); d->gfx_but_ok = lbxfile_item_get(LBXFILE_BACKGRND, 0x1d); d->gfx_transfer = lbxfile_item_get(LBXFILE_BACKGRND, 0x1e); } static void free_pl_data(struct planets_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_report); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_but_trans); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_but_ok); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_transfer); } static const char *planets_get_notes_str(const struct game_s *g, uint8_t pli, bool *flag_normal_ptr, char *buf, size_t bufsize) { const planet_t *p = &(g->planet[pli]); const char *str = NULL; bool flag_normal = false; if (g->evn.have_plague && (g->evn.plague_planet_i == pli)) { str = game_str_pl_plague; } else if (g->evn.have_nova && (g->evn.nova_planet_i == pli)) { str = game_str_pl_nova; } else if (g->evn.have_comet && (g->evn.comet_planet_i == pli)) { str = game_str_pl_comet; } else if (g->evn.have_pirates && (g->evn.pirates_planet_i == pli)) { str = game_str_pl_pirates; } else if (p->unrest == PLANET_UNREST_REBELLION) { str = game_str_pl_rebellion; } else if (p->unrest == PLANET_UNREST_UNREST) { str = game_str_pl_unrest; } else if (g->evn.have_accident && (g->evn.accident_planet_i == pli)) { str = game_str_pl_accident; } else { flag_normal = true; if (p->special != PLANET_SPECIAL_NORMAL) { str = game_str_tbl_sm_pspecial[p->special]; } else if (p->growth != PLANET_GROWTH_NORMAL) { str = game_str_tbl_sm_pgrowth[p->growth]; } if (p->have_stargate) { if (str) { lib_strcpy(buf, str, bufsize); lib_strcat(buf, " *", bufsize); str = buf; } else { str = game_str_sm_stargate; } } } if (flag_normal_ptr) { *flag_normal_ptr = flag_normal; } return str; } static const char *planets_get_dock_str(const struct game_s *g, const struct planet_s *p) { const char *str; if (p->buildship == BUILDSHIP_STARGATE) { str = game_str_sm_stargate; } else { str = g->srd[p->owner].design[p->buildship].name; } return str; } static void planets_draw_cb(void *vptr) { struct planets_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->api]); char buf[64]; int v; ui_draw_color_buf(0x5d); for (int i = 0; i < PLANETS_ON_SCREEN; ++i) { int pi; pi = d->pos + i; if ((pi < d->num) && (ui_data.sorted.value[ui_data.sorted.index[pi]] == d->focus_i)) { int y0, y1; y0 = 21 + i * 11; y1 = y0 + 6; ui_draw_filled_rect(8, y0, 309, y1, 0xeb, ui_scale); } } lbxgfx_draw_frame(0, 0, d->gfx_report, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(d->gfx_but_trans, 1); lbxgfx_draw_frame(209, 181, d->gfx_but_trans, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(213, 159, 245, 162, 0x2f, ui_scale); v = g->eto[d->api].tax; if (v > 0) { ui_draw_slider(213, 160, v * 4, 25, -1, 0x73, ui_scale); } lbxfont_select(2, 8, 0, 0); lbxfont_print_str_normal(210, 170, game_str_pl_reserve, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); v = (e->tax * e->total_production_bc) / 2000; lib_sprintf(buf, sizeof(buf), "+%i", v); lbxfont_print_str_right(272, 159, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(276, 159, game_str_bc, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(276, 170, game_str_bc, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(272, 170, e->reserve_bc, UI_SCREEN_W, ui_scale); for (int i = 0; i < PLANETS_ON_SCREEN; ++i) { int pi; pi = d->pos + i; if (pi < d->num) { int y0; const planet_t *p; const char *str; uint8_t pli; pli = ui_data.sorted.value[ui_data.sorted.index[pi]]; y0 = 21 + i * 11 + 1; /* di + 1 */ p = &(g->planet[pli]); lbxfont_select(2, 0xb, 0, 0); lbxfont_print_num_right(17, y0, ui_data.sorted.index[pi] + 1, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0, 0); lbxfont_print_str_normal(25, y0, p->name, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); if (ui_extra_enabled) { lbxfont_print_num_right(99, y0, p->pop, UI_SCREEN_W, ui_scale); lbxfont_select(2, 1, 0, 0); lbxfont_print_num_normal(102, y0, p->max_pop3, UI_SCREEN_W, ui_scale); } else { lbxfont_print_num_right(83, y0, p->pop, UI_SCREEN_W, ui_scale); } if (p->pop != p->pop_prev) { int v; char c; uint8_t *gfx = NULL; if (p->pop > p->pop_prev) { if (ui_extra_enabled) { lbxfont_select(2, 0xe, 0, 0); } else { gfx = ui_data.gfx.starmap.gr_arrow_u; } v = p->pop - p->pop_prev; c = '+'; } else { if (ui_extra_enabled) { lbxfont_select(2, 0xb, 0, 0); } else { gfx = ui_data.gfx.starmap.gr_arrow_d; } v = p->pop_prev - p->pop; c = '-'; } lib_sprintf(buf, sizeof(buf), "%c%i", c, v); if (ui_extra_enabled) { lbxfont_print_str_right(83, y0, buf, UI_SCREEN_W, ui_scale); } else { lbxgfx_draw_frame(92, y0 - 1, gfx, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(111, y0, buf, UI_SCREEN_W, ui_scale); } } lbxfont_select(2, 6, 0, 0); if (ui_extra_enabled && p->battlebg == 0) { lbxfont_select(2, 1, 0, 0); lbxfont_print_str_right(149, y0, "neb", UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_right(149, y0, game_str_tbl_roman[p->shield], UI_SCREEN_W, ui_scale); } lbxfont_select(2, 6, 0, 0); lbxfont_print_num_right(132, y0, p->factories, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(170, y0, p->missile_bases, UI_SCREEN_W, ui_scale); if (p->waste) { lbxfont_print_num_right(189, y0, p->waste, UI_SCREEN_W, ui_scale); } lbxfont_select(0, 0xe, 0, 0); if (p->unrest == PLANET_UNREST_REBELLION) { v = 0; } else { v = p->total_prod; } lbxfont_print_num_right(214, y0, v, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xb, 0, 0); { bool flag_normal; str = planets_get_notes_str(g, pli, &flag_normal, buf, sizeof(buf)); if (flag_normal) { lbxfont_select(2, 1, 0, 0); } if (str) { lbxfont_print_str_normal(268, y0, str, UI_SCREEN_W, ui_scale); } } if (ui_extra_enabled) { lbxfont_select(2, 6, 0, 0); } if (p->slider[PLANET_SLIDER_SHIP] > 0) { str = planets_get_dock_str(g, p); lbxfont_print_str_normal(221, y0, str, UI_SCREEN_W, ui_scale); } } } lbxfont_select(2, 6, 0, 0); game_print_prod_of_total(g, d->api, e->ship_maint_bc, buf, sizeof(buf)); lbxfont_print_str_right(59, 174, buf, UI_SCREEN_W, ui_scale); game_print_prod_of_total(g, d->api, e->bases_maint_bc, buf, sizeof(buf)); lbxfont_print_str_right(59, 185, buf, UI_SCREEN_W, ui_scale); v = 0; for (player_id_t i = PLAYER_0; i < PLAYER_NUM; ++i) { if (i != d->api) { v += e->spying[i]; } } lib_sprintf(buf, sizeof(buf), "%i.%i%%", v / 10, v % 10); lbxfont_print_str_right(116, 174, buf, UI_SCREEN_W, ui_scale); v = e->security; lib_sprintf(buf, sizeof(buf), "%i.%i%%", v / 10, v % 10); lbxfont_print_str_right(116, 185, buf, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%i %s", e->total_trade_bc, game_str_bc); lbxfont_print_str_right(195, 174, buf, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%i %s", e->total_production_bc, game_str_bc); lbxfont_print_str_right(195, 185, buf, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(5, 8, 0, 0); lbxfont_print_str_center(66, 161, game_str_pl_spending, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(163, 161, game_str_pl_tincome, UI_SCREEN_W, ui_scale); } static void planets_transfer_draw_cb(void *vptr) { struct planets_data_s *d = vptr; struct game_s *g = d->g; planet_t *p = &(g->planet[d->planet_i]); empiretechorbit_t *e = &(g->eto[d->api]); const int x = 100, y = 50; char buf[64]; hw_video_copy_back_from_page2(); lbxgfx_draw_frame(x, y, d->gfx_transfer, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(x + 14, y + 35, x + 64, y + 38, 0x2f, ui_scale); if (d->amount_trans > 0) { ui_draw_slider(x + 14, y + 36, d->amount_trans, 2, -1, 0x74, ui_scale); } lib_sprintf(buf, sizeof(buf), "%s %s", game_str_pl_resto, p->name); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_str_center(x + 57, y + 11, game_str_pl_transof, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(x + 57, y + 20, buf, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_right(x + 104, y + 35, game_str_bc, UI_SCREEN_W, ui_scale); { int v; v = (d->amount_trans * e->reserve_bc) / 100; lbxfont_print_num_right(x + 95, y + 35, v, UI_SCREEN_W, ui_scale); } } static void ui_planets_transfer(struct planets_data_s *d) { struct game_s *g = d->g; planet_t *p = &(g->planet[d->planet_i]); int16_t oi_cancel, oi_accept, oi_minus, oi_plus, oi_equals, oi_hash; int prod, allreserve, v; const int x = 100, y = 50; bool flag_done = false; d->amount_trans = 0; ui_draw_copy_buf(); ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); lbxgfx_set_new_frame(d->gfx_but_ok, 1); lbxgfx_set_new_frame(d->gfx_but_trans, 1); lbxgfx_set_new_frame(ui_data.gfx.starmap.reprtbut_up, 1); lbxgfx_set_new_frame(ui_data.gfx.starmap.reprtbut_down, 1); lbxgfx_draw_frame(292, 159, ui_data.gfx.starmap.reprtbut_up, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(292, 176, ui_data.gfx.starmap.reprtbut_down, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(256, 181, d->gfx_but_ok, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(209, 181, d->gfx_but_trans, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); prod = p->prod_after_maint - p->reserve; SETMAX(prod, 0); allreserve = g->eto[d->api].reserve_bc; v = allreserve; if (v != 0) { v = (prod * 100) / v; } uiobj_table_clear(); oi_cancel = uiobj_add_t0(x + 10, y + 47, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_LEFT); /* FIXME key == "\x01xb" ?? */ oi_accept = uiobj_add_t0(x + 66, y + 47, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); uiobj_add_slider_int(x + 14, y + 35, 0, 100, 50, 9, &d->amount_trans); oi_minus = uiobj_add_mousearea(x + 10, y + 33, x + 12, y + 41, MOO_KEY_UNKNOWN); oi_plus = uiobj_add_mousearea(x + 66, y + 33, x + 70, y + 41, MOO_KEY_UNKNOWN); oi_equals = uiobj_add_inputkey(MOO_KEY_EQUALS); oi_hash = uiobj_add_inputkey(MOO_KEY_HASH); uiobj_set_callback_and_delay(planets_transfer_draw_cb, d, 1); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_cancel) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; } else if (oi == oi_accept) { ui_sound_play_sfx_24(); v = (d->amount_trans * allreserve) / 100; p->reserve += v; allreserve -= v; SETMAX(allreserve, 0); g->eto[d->api].reserve_bc = allreserve; flag_done = true; } else if (oi == oi_minus) { ui_sound_play_sfx_24(); d->amount_trans -= 2; SETMAX(d->amount_trans, 0); } else if (oi == oi_plus) { ui_sound_play_sfx_24(); d->amount_trans += 2; SETMIN(d->amount_trans, 100); } else if (oi == oi_equals || oi == oi_hash) { ui_sound_play_sfx_24(); d->amount_trans = v; SETRANGE(d->amount_trans, 0, 100); } if (!flag_done) { planets_transfer_draw_cb(d); ui_draw_finish(); ui_delay_ticks_or_click(1); } } } /* -------------------------------------------------------------------------- */ enum { UI_SORT_INDEX = 0, UI_SORT_NAME, UI_SORT_GROWTH, UI_SORT_POP, UI_SORT_MAXPOP, UI_SORT_FACT, UI_SORT_SHIELD, UI_SORT_BASE, UI_SORT_WASTE, UI_SORT_PROD, UI_SORT_DOCK, UI_SORT_NOTES, UI_SORT_NUM }; #define UI_SORT_SETUP() \ const struct game_s *g = ui_data.sorted.g; \ uint16_t i0 = *((uint16_t const *)ptr0); \ uint16_t i1 = *((uint16_t const *)ptr1); \ uint8_t pli0 = ui_data.sorted.value[i0]; \ uint8_t pli1 = ui_data.sorted.value[i1]; \ const planet_t *p0 = &(g->planet[pli0]); \ const planet_t *p1 = &(g->planet[pli1]) #define UI_SORT_CMP_VALUE(_v0_, _v1_) (((_v0_) != (_v1_)) ? ((_v0_) - (_v1_)) : (i1 - i0)) #define UI_SORT_CMP_VARIABLE(_var_) UI_SORT_CMP_VALUE(p0->_var_, p1->_var_) static int planets_sort_inc_index(const void *ptr0, const void *ptr1) { uint16_t i0 = *((uint16_t const *)ptr0); uint16_t i1 = *((uint16_t const *)ptr1); return i0 - i1; } static int planets_sort_dec_index(const void *ptr0, const void *ptr1) { return planets_sort_inc_index(ptr1, ptr0); } static int planets_sort_inc_name(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return strcmp(p0->name, p1->name); } static int planets_sort_dec_name(const void *ptr0, const void *ptr1) { return planets_sort_inc_name(ptr1, ptr0); } static int planets_sort_inc_pop(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return UI_SORT_CMP_VARIABLE(pop); } static int planets_sort_dec_pop(const void *ptr0, const void *ptr1) { return planets_sort_inc_pop(ptr1, ptr0); } static int planets_sort_inc_max_pop(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return UI_SORT_CMP_VARIABLE(max_pop3); } static int planets_sort_dec_max_pop(const void *ptr0, const void *ptr1) { return planets_sort_inc_max_pop(ptr1, ptr0); } static int planets_sort_inc_growth(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); int v0 = p0->pop - p0->pop_prev; int v1 = p1->pop - p1->pop_prev; return UI_SORT_CMP_VALUE(v0, v1); } static int planets_sort_dec_growth(const void *ptr0, const void *ptr1) { return planets_sort_inc_growth(ptr1, ptr0); } static int planets_sort_inc_fact(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return UI_SORT_CMP_VARIABLE(factories); } static int planets_sort_dec_fact(const void *ptr0, const void *ptr1) { return planets_sort_inc_fact(ptr1, ptr0); } static int planets_sort_inc_shield(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); int v0 = p0->battlebg ? p0->shield : -1; int v1 = p1->battlebg ? p1->shield : -1; return UI_SORT_CMP_VALUE(v0, v1); } static int planets_sort_dec_shield(const void *ptr0, const void *ptr1) { return planets_sort_inc_shield(ptr1, ptr0); } static int planets_sort_inc_base(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return UI_SORT_CMP_VARIABLE(missile_bases); } static int planets_sort_dec_base(const void *ptr0, const void *ptr1) { return planets_sort_inc_base(ptr1, ptr0); } static int planets_sort_inc_waste(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); return UI_SORT_CMP_VARIABLE(waste); } static int planets_sort_dec_waste(const void *ptr0, const void *ptr1) { return planets_sort_inc_waste(ptr1, ptr0); } static int planets_sort_inc_prod(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); int v0 = (p0->unrest == PLANET_UNREST_REBELLION) ? 0 : p0->total_prod; int v1 = (p1->unrest == PLANET_UNREST_REBELLION) ? 0 : p1->total_prod; return UI_SORT_CMP_VALUE(v0, v1); } static int planets_sort_dec_prod(const void *ptr0, const void *ptr1) { return planets_sort_inc_prod(ptr1, ptr0); } static int planets_sort_inc_dock(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); const char *s0 = (p0->slider[PLANET_SLIDER_SHIP] > 0) ? planets_get_dock_str(g, p0) : "\xff"; const char *s1 = (p1->slider[PLANET_SLIDER_SHIP] > 0) ? planets_get_dock_str(g, p1) : "\xff"; return UI_SORT_CMP_VALUE(strcmp(s1, s0), 0); } static int planets_sort_dec_dock(const void *ptr0, const void *ptr1) { return planets_sort_inc_dock(ptr1, ptr0); } static int planets_sort_inc_notes(const void *ptr0, const void *ptr1) { UI_SORT_SETUP(); char buf0[64]; char buf1[64]; bool normal0, normal1; const char *s0 = planets_get_notes_str(g, pli0, &normal0, buf0, sizeof(buf0)); const char *s1 = planets_get_notes_str(g, pli1, &normal1, buf1, sizeof(buf1)); int d; if (normal1 && !normal0) { d = 1; } else if (normal0 && !normal1) { d = -1; } else if (!normal0 && !normal1) { d = UI_SORT_CMP_VALUE(strcmp(s1, s0), 0); } else { if (p0->special > p1->special) { d = 1; } else if (p0->special < p1->special) { d = -1; } else { d = UI_SORT_CMP_VARIABLE(growth); } } return d; } static int planets_sort_dec_notes(const void *ptr0, const void *ptr1) { return planets_sort_inc_notes(ptr1, ptr0); } typedef int sort_cb_t(const void *, const void *); static sort_cb_t * const sort_cb_tbl[UI_SORT_NUM * 2] = { planets_sort_inc_index, planets_sort_dec_index, planets_sort_inc_name, planets_sort_dec_name, planets_sort_dec_growth, planets_sort_inc_growth, planets_sort_dec_pop, planets_sort_inc_pop, planets_sort_dec_max_pop, planets_sort_inc_max_pop, planets_sort_dec_fact, planets_sort_inc_fact, planets_sort_dec_shield, planets_sort_inc_shield, planets_sort_dec_base, planets_sort_inc_base, planets_sort_dec_waste, planets_sort_inc_waste, planets_sort_dec_prod, planets_sort_inc_prod, planets_sort_dec_dock, planets_sort_inc_dock, planets_sort_dec_notes, planets_sort_inc_notes }; static void ui_planets_sort(struct planets_data_s *d) { qsort(ui_data.sorted.index, d->num, sizeof(ui_data.sorted.index[0]), sort_cb_tbl[d->order_i]); ui_data.sorted.planets_order[d->api] = d->order_i; for (int i = 0; i < d->num; ++i) { int index = ui_data.sorted.index[i]; if (ui_data.sorted.value[index] == d->focus_i) { d->pos = i - 5; break; } } if ((d->pos + PLANETS_ON_SCREEN) >= d->num) { d->pos = d->num - PLANETS_ON_SCREEN; } SETMAX(d->pos, 0); } /* -------------------------------------------------------------------------- */ void ui_planets(struct game_s *g, player_id_t active_player) { struct planets_data_s d; bool flag_done = false, flag_trans; int16_t oi_alt_moola, oi_up, oi_down, oi_wheel, oi_ok, oi_trans, oi_minus, oi_plus, oi_tbl_planets[PLANETS_ON_SCREEN]; int16_t oi_sort[UI_SORT_NUM]; uint8_t tbl_onscreen_planets[PLANETS_ON_SCREEN]; int16_t scroll = 0; load_pl_data(&d); uiobj_set_help_id(37); d.g = g; d.api = active_player; d.focus_i = g->planet_focus_i[active_player]; d.order_i = 0; d.pos = 0; d.num = 0; ui_data.sorted.g = g; for (int i = 0; i < g->galaxy_stars; ++i) { if (g->planet[i].owner == active_player) { if (i == d.focus_i) { d.pos = d.num - 5; /* WASBUG MOO1 uses i - 5 */ } ui_data.sorted.index[d.num] = d.num; ui_data.sorted.value[d.num++] = i; } } if (ui_extra_enabled) { d.order_i = ui_data.sorted.planets_order[active_player]; ui_planets_sort(&d); } again: flag_trans = false; game_update_production(g); /* this is needed for correct shown production after transfers */ oi_up = UIOBJI_INVALID; oi_down = UIOBJI_INVALID; oi_wheel = UIOBJI_INVALID; oi_ok = UIOBJI_INVALID; oi_trans = UIOBJI_INVALID; oi_minus = UIOBJI_INVALID; oi_plus = UIOBJI_INVALID; for (int i = 0; i < PLANETS_ON_SCREEN; ++i) { tbl_onscreen_planets[i] = 0; oi_tbl_planets[i] = UIOBJI_INVALID; } UIOBJI_SET_TBL_INVALID(oi_sort); uiobj_set_callback_and_delay(planets_draw_cb, &d, 1); uiobj_table_clear(); oi_alt_moola = uiobj_add_alt_str("moola"); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ok) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; } else if (oi == oi_up) { ui_sound_play_sfx_24(); d.pos -= PLANETS_ON_SCREEN; } else if (oi == oi_down) { ui_sound_play_sfx_24(); d.pos += PLANETS_ON_SCREEN; } else if (oi == oi_wheel) { d.pos += scroll; scroll = 0; } for (int i = 0; i < PLANETS_ON_SCREEN; ++i) { if (oi == oi_tbl_planets[i]) { ui_sound_play_sfx_24(); if (!flag_trans) { g->planet_focus_i[active_player] = tbl_onscreen_planets[i]; flag_done = true; } else { d.planet_i = tbl_onscreen_planets[i]; ui_planets_transfer(&d); ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); goto again; } } } if (oi == oi_alt_moola) { if (game_cheat_moola(g, active_player)) { ui_sound_play_sfx_24(); } } if ((d.pos + PLANETS_ON_SCREEN) >= d.num) { d.pos = d.num - PLANETS_ON_SCREEN; } SETMAX(d.pos, 0); if (oi == oi_minus) { ui_sound_play_sfx_24(); g->eto[active_player].tax -= 5; SETMAX(g->eto[active_player].tax, 0); } else if (oi == oi_plus) { ui_sound_play_sfx_24(); g->eto[active_player].tax += 5; SETMIN(g->eto[active_player].tax, 200); } else if (oi == oi_trans) { ui_sound_play_sfx_24(); flag_trans = true; } for (int i = 0; i < UI_SORT_NUM; ++i) { if (oi == oi_sort[i]) { int v; v = i * 2; if (v == d.order_i) { ++v; } d.order_i = v; ui_planets_sort(&d); } } ui_cursor_setup_area(1, &ui_cursor_area_tbl[flag_trans ? 9 : 0]); if (!flag_done) { uiobj_table_set_last(oi_alt_moola); oi_up = uiobj_add_t0(292, 159, "", ui_data.gfx.starmap.reprtbut_up, MOO_KEY_COMMA); oi_down = uiobj_add_t0(292, 176, "", ui_data.gfx.starmap.reprtbut_down, MOO_KEY_PERIOD); oi_ok = uiobj_add_t0(256, 181, "", d.gfx_but_ok, MOO_KEY_o); for (int i = 0; i < PLANETS_ON_SCREEN; ++i) { int pi, y0, y1; pi = i + d.pos; if (pi < d.num) { tbl_onscreen_planets[i] = ui_data.sorted.value[ui_data.sorted.index[pi]]; y0 = 21 + i * 11; y1 = y0 + 8; oi_tbl_planets[i] = uiobj_add_mousearea(7, y0, 248, y1, MOO_KEY_UNKNOWN); } } if (ui_extra_enabled) { const int x0[UI_SORT_NUM] = { 8, 23, 71, 87, 101, 117, 138, 155, 176, 194, 220, 267 }; const int x1[UI_SORT_NUM] = { 20, 60, 86, 99, 113, 134, 151, 172, 192, 216, 262, 310 }; const int y0 = 8, y1 = 16; for (int i = 0; i < UI_SORT_NUM; ++i) { oi_sort[i] = uiobj_add_mousearea(x0[i], y0, x1[i], y1, MOO_KEY_UNKNOWN); } } oi_wheel = uiobj_add_mousewheel(0, 0, 319, 159, &scroll); oi_trans = UIOBJI_INVALID; if (!flag_trans) { if (g->eto[active_player].reserve_bc != 0) { oi_trans = uiobj_add_t0(209, 181, "", d.gfx_but_trans, MOO_KEY_t); } uiobj_add_slider_int(213, 160, 0, 200, 32, 9, &g->eto[active_player].tax); oi_minus = uiobj_add_mousearea(208, 157, 211, 165, MOO_KEY_UNKNOWN); oi_plus = uiobj_add_mousearea(247, 157, 251, 165, MOO_KEY_UNKNOWN); } else { oi_minus = UIOBJI_INVALID; oi_plus = UIOBJI_INVALID; } planets_draw_cb(&d); /* FIXME not needed in original */ ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); uiobj_set_help_id(-1); free_pl_data(&d); } 1oom-1.11.2/src/ui/classic/uiplanets.h000066400000000000000000000002461476061725400174670ustar00rootroot00000000000000#ifndef INC_1OOM_UIPLANETS_H #define INC_1OOM_UIPLANETS_H #include "game_types.h" struct game_s; extern void ui_planets(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiraces.c000066400000000000000000000424751476061725400171230ustar00rootroot00000000000000#include "config.h" #include #include "uiraces.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_diplo.h" #include "game_misc.h" #include "game_str.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct races_data_s { struct game_s *g; uint8_t *gfx; int num; player_id_t api; uint8_t tbl_ei[PLAYER_NUM - 1]; bool tbl_gone[PLAYER_NUM - 1]; uint8_t cursor_mode; /* 0, 4, 5 */ int16_t tbl_spymode[PLAYER_NUM - 1]; }; static void races_data_load(struct races_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 0x34); } static void races_data_free(struct races_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void races_draw_cb(void *vptr) { struct races_data_s *d = vptr; struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); char buf[0x80]; for (int i = 0; i < d->num; ++i) { player_id_t pi; pi = d->tbl_ei[i]; e->spymode[pi] = (spymode_t)d->tbl_spymode[i]; } ui_draw_color_buf(0x5b); lbxgfx_draw_frame(0, 0, d->gfx, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(5, 0xa, 0, 0); for (int i = d->num; i < (PLAYER_NUM - 1); ++i) { int x, y; x = (i / 3) * 157; y = (i % 3) * 64; ui_draw_filled_rect(x + 58, y + 9, x + 156, y + 21, 0x5b, ui_scale); ui_draw_filled_rect(x + 56, y + 25, x + 158, y + 37, 0x5b, ui_scale); ui_draw_filled_rect(x + 58, y + 41, x + 156, y + 51, 0x5b, ui_scale); ui_draw_filled_rect(x + 56, y + 55, x + 158, y + 65, 0x5b, ui_scale); lbxfont_print_str_center(x + 109, y + 27, (i < g->players - 1) ? game_str_ra_nocont : game_str_ra_notpres, UI_SCREEN_W, ui_scale); } if (d->num) { int v; ui_draw_filled_rect(238, 141, 283, 144, 0, ui_scale); if (e->security) { ui_draw_slider(238, 142, e->security * 9, 40, -1, 0x73, ui_scale); } v = (e->security / 5); if (e->race == RACE_DARLOK) { v += 20; } lib_sprintf(buf, sizeof(buf), "+%i%%", v); lbxfont_select(2, 0xb, 0, 0); lbxfont_set_color_c_n(0x26, 5); lbxfont_print_str_right(309, 141, buf, UI_SCREEN_W, ui_scale); } else { ui_draw_filled_rect(238, 141, 283, 144, 0x5a, ui_scale); } lbxfont_select(2, 6, 0, 0); lbxfont_print_str_normal(167, 150, game_str_ra_secline1, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(167, 157, game_str_ra_secline2, UI_SCREEN_W, ui_scale); { int sumalloc = e->security; struct strbuild_s strbuild = strbuild_init(buf, sizeof(buf)); for (int i = 0; i < d->num; ++i) { player_id_t pi; pi = d->tbl_ei[i]; sumalloc += e->spying[pi]; } strbuild_catf(&strbuild, "%s: ", game_str_ra_alloc); if (sumalloc == 0) { strbuild_append_char(&strbuild, '0'); } else { strbuild_catf(&strbuild, "%i.%i", sumalloc / 10, sumalloc % 10); } strbuild_catf(&strbuild, "%% %s", game_str_ra_planres); lbxfont_select(2, 0, 0, 0); lbxfont_print_str_normal(167, 170, buf, UI_SCREEN_W, ui_scale); } for (int i = 0; i < d->num; ++i) { const uint8_t colortbl_races_banner[BANNER_NUM] = { 0xeb, 0x6d, 0xd4, 0x43, 0x0a, 0x52 }; int x, y; player_id_t pi; pi = d->tbl_ei[i]; x = (i / 3) * 157; y = (i % 3) * 64; lbxgfx_draw_frame(x + 9, y + 10, ui_data.gfx.planets.race[g->eto[pi].race], UI_SCREEN_W, ui_scale); if (d->tbl_gone[i]) { lbxfont_select_set_12_4(0, 0, 0, 0); lbxfont_print_str_center(x + 29, y + 23, game_str_ra_diplo, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(x + 29, y + 31, game_str_ra_gone, UI_SCREEN_W, ui_scale); } ui_draw_filled_rect(x + 9, y + 48, x + 48, y + 61, colortbl_races_banner[g->eto[pi].banner], ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_print_str_center(x + 29, y + 51, game_str_tbl_races[g->eto[pi].race], UI_SCREEN_W, ui_scale); { int spying, spyprod, spyspend, spies, spycost; spying = e->spying[pi]; ui_draw_filled_rect(x + 103, y + 44, x + 128, y + 47, 0, ui_scale); lbxfont_select(2, 0, 0, 0); lbxfont_set_color_c_n(0x26, 5); spyprod = (e->total_production_bc * spying) / 1000; spyspend = spyprod + e->spyfund[pi]; spies = e->spies[pi]; spycost = e->tech.percent[TECH_FIELD_COMPUTER] * 2 + 25; if (e->race == RACE_DARLOK) { spycost /= 2; } if (spying != 0) { ui_draw_slider(x + 103, y + 45, spying, 4, -1, 0x73, ui_scale); } if (spies == 0) { lib_strcpy(buf, game_str_ra_nospies, sizeof(buf)); } else { lib_sprintf(buf, sizeof(buf), "%i %s", spies, (spies == 1) ? game_str_ra_spy : game_str_ra_spies); } lbxfont_select(2, 6, 0, 0); lbxfont_print_str_right(x + 91, y + 44, buf, UI_SCREEN_W, ui_scale); if (spycost <= spyspend) { spies = 0; while (spycost <= spyspend) { ++spies; spyspend -= spycost; spycost *= 2; } lib_sprintf(buf, sizeof(buf), "%i%c%s", spies, (spies == 1) ? ' ' : '/', game_str_y); } else { if (spyprod == 0) { lib_strcpy(buf, game_str_st_none, sizeof(buf)); } else { int left, years; left = spycost - spyspend; years = left / spyprod; if (left % spyprod) { ++years; } lib_sprintf(buf, sizeof(buf), "%i %s", years, game_str_y); } } lbxfont_print_str_right(x + 153, y + 44, buf, UI_SCREEN_W, ui_scale); } { const char *str; str = game_str_tbl_ra_treaty[e->treaty[pi]]; ui_draw_filled_rect(x + 57, y + 8, x + 157, y + 22, 0x5b, ui_scale); lbxfont_select(0, 6, 0, 0); lbxfont_print_str_normal(x + 61, y + 10, str, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0, 0, 0); lbxfont_set_color_c_n(0xe6, 5); lbxfont_print_str_normal(x + 60, y + 9, str, UI_SCREEN_W, ui_scale); } if (e->trade_bc[pi] != 0) { lib_sprintf(buf, sizeof(buf), "%s: %i %s%s", game_str_ra_trade, e->trade_bc[pi], game_str_bc, game_str_year0); } else { lib_strcpy(buf, game_str_ra_notrade, sizeof(buf)); } lbxfont_select(0, 6, 0, 0); lbxfont_print_str_normal(x + 61, y + 17, buf, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0, 0, 0); lbxfont_set_color_c_n(0xe6, 5); lbxfont_print_str_normal(x + 60, y + 16, buf, UI_SCREEN_W, ui_scale); { int rel; rel = e->relation1[pi] / 2; SETRANGE(rel, -50, 50); lbxfont_select_set_12_4(0, 6, 0, 0); lbxfont_select(2, 0xd, 0, 0); lbxgfx_draw_frame(x + 107 + rel, y + 34, ui_data.gfx.screens.race_pnt, UI_SCREEN_W, ui_scale); rel = e->relation1[pi] / 12 + 8; SETRANGE(rel, 0, 16); lbxfont_print_str_center(x + 107, y + 27, game_str_tbl_ra_relat[rel], UI_SCREEN_W, ui_scale); } } lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.status, 1); lbxgfx_draw_frame(165, 180, ui_data.gfx.screens.races_bu.status, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.report, 1); lbxgfx_draw_frame(205, 180, ui_data.gfx.screens.races_bu.report, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.audience, 1); lbxgfx_draw_frame(245, 180, ui_data.gfx.screens.races_bu.audience, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.ok, 1); lbxgfx_draw_frame(290, 180, ui_data.gfx.screens.races_bu.ok, UI_SCREEN_W, ui_scale); for (int i = 0; i < d->num; ++i) { int x, y; x = (i / 3) * 157; y = (i % 3) * 64; lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.hiding, (d->tbl_spymode[i] == SPYMODE_HIDE) ? 1 : 0); lbxgfx_draw_frame(x + 59, y + 55, ui_data.gfx.screens.races_bu.hiding, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.sabotage, (d->tbl_spymode[i] == SPYMODE_SABOTAGE) ? 1 : 0); lbxgfx_draw_frame(x + 77, y + 55, ui_data.gfx.screens.races_bu.sabotage, UI_SCREEN_W, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.races_bu.espionage, (d->tbl_spymode[i] == SPYMODE_ESPIONAGE) ? 1 : 0); lbxgfx_draw_frame(x + 114, y + 55, ui_data.gfx.screens.races_bu.espionage, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ int ui_races(struct game_s *g, player_id_t api) { struct races_data_s d; bool flag_done = false; int16_t oi_ok, oi_ok2, oi_audience, oi_report, oi_status, oi_sec_minus, oi_sec_plus, oi_tbl_oppon[PLAYER_NUM - 1], oi_tbl_spy_minus[PLAYER_NUM - 1], oi_tbl_spy_plus[PLAYER_NUM - 1] ; empiretechorbit_t *e = &(g->eto[api]); int ret = -1; d.g = g; d.api = api; races_data_load(&d); lbxgfx_apply_palette(d.gfx); game_update_production(g); game_update_empire_contact(g); d.num = 0; for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != api) && BOOLVEC_IS1(e->contact, pi) && IS_ALIVE(g, pi)) { d.tbl_ei[d.num++] = pi; } else { e->spying[pi] = 0; } } for (int i = 0; i < d.num; ++i) { d.tbl_gone[i] = game_diplo_is_gone(g, api, d.tbl_ei[i]); } d.cursor_mode = 0; #define UIOBJ_CLEAR_LOCAL() \ do { \ oi_ok = UIOBJI_INVALID; \ oi_ok2 = UIOBJI_INVALID; \ oi_audience = UIOBJI_INVALID; \ oi_report = UIOBJI_INVALID; \ oi_status = UIOBJI_INVALID; \ oi_sec_minus = UIOBJI_INVALID; \ oi_sec_plus = UIOBJI_INVALID; \ UIOBJI_SET_TBL3_INVALID(oi_tbl_oppon, oi_tbl_spy_minus, oi_tbl_spy_plus); \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(d.num ? 10 : 11); uiobj_set_callback_and_delay(races_draw_cb, &d, 1); uiobj_table_clear(); while (!flag_done) { int16_t oi; ui_cursor_setup_area(1, &ui_cursor_area_tbl[d.cursor_mode ? 8 : 0]); oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ok) || (oi == oi_ok2) || ((oi == UIOBJI_ESC) && !d.cursor_mode)) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if ((oi == UIOBJI_ESC) && d.cursor_mode) { ui_sound_play_sfx_06(); d.cursor_mode = 0; } else if (oi == oi_status) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_EMPIRESTATUS; } else if (oi == oi_report) { ui_sound_play_sfx_24(); d.cursor_mode = 4; } else if (oi == oi_audience) { ui_sound_play_sfx_24(); d.cursor_mode = 5; } else if (oi == oi_sec_minus) { if (kbd_is_modifier(MOO_MOD_ALT)) { e->security = 0; } else { int v; ui_sound_play_sfx_24(); v = e->security; v -= 10; SETMAX(v, 0); e->security = v; } } else if (oi == oi_sec_plus) { if (kbd_is_modifier(MOO_MOD_ALT)) { e->security = 200; } else { int v; ui_sound_play_sfx_24(); v = e->security; v += 10; SETMIN(v, 200); e->security = v; } } for (int i = 0; i < (PLAYER_NUM - 1); ++i) { if (oi == oi_tbl_spy_minus[i]) { if (kbd_is_modifier(MOO_MOD_ALT)) { e->spying[d.tbl_ei[i]] = 0; } else { int v; ui_sound_play_sfx_24(); v = e->spying[d.tbl_ei[i]]; v -= 4; SETMAX(v, 0); e->spying[d.tbl_ei[i]] = v; } } else if (oi == oi_tbl_spy_plus[i]) { if (kbd_is_modifier(MOO_MOD_ALT)) { e->spying[d.tbl_ei[i]] = 100; } else { int v; ui_sound_play_sfx_24(); v = e->spying[d.tbl_ei[i]]; v += 4; SETMIN(v, 100); e->spying[d.tbl_ei[i]] = v; } } else if (oi == oi_tbl_oppon[i]) { ui_sound_play_sfx_24(); if ((d.cursor_mode == 4) || (ui_extra_enabled && (d.cursor_mode == 0))) { flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_EMPIREREPORT; ret = d.tbl_ei[i]; d.cursor_mode = 0; } else if (d.cursor_mode == 5) { if (!d.tbl_gone[i]) { flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_AUDIENCE; ret = d.tbl_ei[i]; d.cursor_mode = 0; } } else { d.cursor_mode = 0; } } } UIOBJ_CLEAR_LOCAL(); for (int i = 0; i < d.num; ++i) { player_id_t pi; pi = d.tbl_ei[i]; d.tbl_spymode[i] = (int16_t)e->spymode[pi]; } if (!flag_done) { /* FIXME one of these copyings is redundant? */ for (int i = 0; i < d.num; ++i) { player_id_t pi; pi = d.tbl_ei[i]; e->spymode[pi] = (spymode_t)d.tbl_spymode[i]; } races_draw_cb(&d); uiobj_table_clear(); if (d.num > 0) { if (d.cursor_mode == 0) { oi_report = uiobj_add_t0(205, 180, "", ui_data.gfx.screens.races_bu.report, MOO_KEY_r); if (g->end == GAME_END_NONE) { oi_audience = uiobj_add_t0(245, 180, "", ui_data.gfx.screens.races_bu.audience, MOO_KEY_a); } } for (int i = 0; i < d.num; ++i) { int x, y, x1; x = (i / 3) * 157; y = (i % 3) * 64; if (d.cursor_mode == 0) { uiobj_add_t3(x + 59, y + 55, "", ui_data.gfx.screens.races_bu.hiding, &(d.tbl_spymode[i]), SPYMODE_HIDE, MOO_KEY_UNKNOWN); uiobj_add_t3(x + 77, y + 55, "", ui_data.gfx.screens.races_bu.sabotage, &(d.tbl_spymode[i]), SPYMODE_SABOTAGE, MOO_KEY_UNKNOWN); uiobj_add_t3(x + 114, y + 55, "", ui_data.gfx.screens.races_bu.espionage, &(d.tbl_spymode[i]), SPYMODE_ESPIONAGE, MOO_KEY_UNKNOWN); x1 = x + 54; } else { x1 = x + 157; } oi_tbl_oppon[i] = uiobj_add_mousearea(x + 4, y + 5, x1, y + 66, MOO_KEY_1 + i); } } if (d.cursor_mode == 0) { oi_status = uiobj_add_t0(165, 180, "", ui_data.gfx.screens.races_bu.status, MOO_KEY_s); oi_ok = uiobj_add_t0(290, 180, "", ui_data.gfx.screens.races_bu.ok, MOO_KEY_o); oi_ok2 = uiobj_add_inputkey(MOO_KEY_SPACE); if (d.num > 0) { uiobj_add_slider_int(238, 141, 0, 200, 45, 9, &e->security); oi_sec_minus = uiobj_add_mousearea(233, 139, 236, 147, MOO_KEY_UNKNOWN); oi_sec_plus = uiobj_add_mousearea(285, 139, 289, 147, MOO_KEY_UNKNOWN); } else { e->security = 0; } for (int i = 0; i < d.num; ++i) { int x, y; player_id_t pi; x = (i / 3) * 157; y = (i % 3) * 64; pi = d.tbl_ei[i]; uiobj_add_slider_int(x + 103, y + 44, 0, 100, 25, 9, &e->spying[pi]); oi_tbl_spy_minus[i] = uiobj_add_mousearea(x + 97, y + 42, x + 100, y + 50, MOO_KEY_UNKNOWN); oi_tbl_spy_plus[i] = uiobj_add_mousearea(x + 130, y + 42, x + 134, y + 50, MOO_KEY_UNKNOWN); } } ui_draw_finish(); ui_delay_ticks_or_click(1); } } for (int i = 0; i < d.num; ++i) { player_id_t pi; pi = d.tbl_ei[i]; e->spymode[pi] = (spymode_t)d.tbl_spymode[i]; } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); lbxpal_select(0, 104, 113); races_data_free(&d); return ret; } 1oom-1.11.2/src/ui/classic/uiraces.h000066400000000000000000000002371476061725400171160ustar00rootroot00000000000000#ifndef INC_1OOM_UIRACES_H #define INC_1OOM_UIRACES_H #include "game_types.h" struct game_s; extern int ui_races(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uisave.c000066400000000000000000000074431476061725400167600ustar00rootroot00000000000000#include "config.h" #include "uisave.h" #include "game_save.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct save_game_data_s { int selected; int tbl_savei[NUM_SAVES]; char tbl_savename[NUM_SAVES][SAVE_NAME_LEN + 10]; uint8_t *gfx_savegame; uint8_t *gfx_lg_gray; uint8_t *gfx_lg_green; }; static void load_sg_data(struct save_game_data_s *d) { d->gfx_savegame = lbxfile_item_get(LBXFILE_VORTEX, 4); d->gfx_lg_gray = lbxfile_item_get(LBXFILE_VORTEX, 7); d->gfx_lg_green = lbxfile_item_get(LBXFILE_VORTEX, 8); } static void free_sg_data(struct save_game_data_s *d) { lbxfile_item_release(LBXFILE_VORTEX, d->gfx_savegame); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_lg_gray); lbxfile_item_release(LBXFILE_VORTEX, d->gfx_lg_green); } static void save_game_draw_cb(void *vptr) { struct save_game_data_s *d = vptr; const int xoff = 0x76; const int yoff = 0xa; hw_video_copy_back_from_page2(); lbxgfx_draw_frame(0, 0, d->gfx_savegame, UI_SCREEN_W, ui_scale); for (int i = 0; i < NUM_SAVES; ++i) { lbxgfx_draw_frame(16 + xoff, 23 + yoff + 18 * i, (d->selected == i) ? d->gfx_lg_green : d->gfx_lg_gray, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ int ui_save_game(struct game_s *g) { struct save_game_data_s d; bool flag_done = false; const int xoff = 118; const int yoff = 10; int16_t oi_esc, oi_cancel, oi_ok, oi_save[NUM_SAVES]; const uint8_t ctbl[] = { 5, 6, 7, 8, 9, 10, 0, 0, 0, 0 }; load_sg_data(&d); for (int i = 0; i < NUM_SAVES; ++i) { lib_strcpy(d.tbl_savename[i], game_save_tbl_name[i], SAVE_NAME_LEN + 10); } ui_draw_erase_buf(); hw_video_copy_back_to_page2(); uiobj_set_callback_and_delay(save_game_draw_cb, &d, 2); uiobj_table_clear(); for (int i = 0; i < NUM_SAVES; ++i) { oi_save[i] = UIOBJI_INVALID; } d.selected = -1; oi_ok = UIOBJI_INVALID; oi_cancel = UIOBJI_INVALID; oi_esc = UIOBJI_INVALID; while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); for (int i = 0; i < NUM_SAVES; ++i) { if (oi == oi_save[i]) { d.selected = i; ui_sound_play_sfx_24(); } } if ((oi == oi_cancel) || (oi == oi_esc)) { ui_sound_play_sfx_06(); d.selected = -1; flag_done = true; } if ((oi == oi_ok) && (d.selected != -1)) { ui_sound_play_sfx_24(); game_save_do_save_i(d.selected, d.tbl_savename[d.selected], g); flag_done = true; } uiobj_table_clear(); for (int i = 0; i < NUM_SAVES; ++i) { lbxfont_select(0, (i == d.selected) ? 2 : 1, 0, 0); oi_save[i] = uiobj_add_textinput(149, 35 + i * 18, 106, &(d.tbl_savename[i][0]), SAVE_NAME_LEN - 1, 1, false, true, ctbl, MOO_KEY_UNKNOWN); uiobj_dec_y1(oi_save[i]); } oi_esc = uiobj_add_inputkey(MOO_KEY_ESCAPE); oi_cancel = uiobj_add_mousearea(20 + xoff, 135 + yoff, 74 + xoff, 152 + yoff, MOO_KEY_ESCAPE); oi_ok = uiobj_add_mousearea(84 + xoff, 135 + yoff, 138 + xoff, 152 + yoff, MOO_KEY_SPACE); if (!flag_done) { save_game_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(2); } } uiobj_unset_callback(); free_sg_data(&d); return d.selected; } 1oom-1.11.2/src/ui/classic/uisave.h000066400000000000000000000002471476061725400167600ustar00rootroot00000000000000#ifndef INC_1OOM_UISAVE_H #define INC_1OOM_UISAVE_H struct game_s; /* returns -1 on cancel or 0..5 on save game */ extern int ui_save_game(struct game_s *g); #endif 1oom-1.11.2/src/ui/classic/uisearch.c000066400000000000000000000124071476061725400172630ustar00rootroot00000000000000#include "config.h" #include #include #include #include "uisearch.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_cheat.h" #include "game_planet.h" #include "hw.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uispecs.h" #include "uistarmap.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define SEARCH_POS_X 6 #define SEARCH_POS_Y 169 static void search_draw_cb(void *vptr) { const int x = SEARCH_POS_X, y = SEARCH_POS_Y; ui_draw_filled_rect(x, y, x + 100, y + 8, 0x06, ui_scale); } static inline bool can_see_name(const struct game_s *g, player_id_t pi, const planet_t *p) { if (BOOLVEC_IS1(p->explored, pi)) { return true; } if (p->owner != PLAYER_NONE) { if (0 || BOOLVEC_IS1(p->within_srange, pi) || (pi == g->evn.planet_orion_i) || ((BOOLVEC_IS1(g->eto[pi].contact, p->owner) || (p->within_frange[pi] == 1))) ) { return true; } } return false; } static int search_planet(const struct game_s *g, player_id_t pi, const char *str) { for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (can_see_name(g, pi, p) && (strcasecmp(p->name, str) == 0)) { return i; } } { for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p; int pli; pli = (g->planet_focus_i[pi] + 1 + i) % g->galaxy_stars; p = &(g->planet[pli]); if (can_see_name(g, pi, p)) { for (int j = 0; (j < PLANET_NAME_LEN) && p->name[j]; ++j) { char cp, cs; cp = p->name[j]; cs = str[j]; if (cs == '\0') { return pli; } if (isupper(cp)) { cp = tolower(cp); } if (isupper(cs)) { cs = tolower(cs); } if (cp != cs) { break; } } } } return -1; } } /* -------------------------------------------------------------------------- */ int ui_search(struct game_s *g, player_id_t pi) { const int x = SEARCH_POS_X, y = SEARCH_POS_Y; int pli = -1; char buf[PLANET_NAME_LEN]; buf[0] = 0; ui_draw_copy_buf(); hw_video_copy_back_to_page2(); uiobj_finish_frame(); //ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); uiobj_table_clear(); uiobj_set_callback_and_delay(search_draw_cb, 0, 1); { const uint8_t ctbl[8] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; lbxfont_select(0, 0, 0, 0); if (uiobj_read_str(x + 2, y + 2, 90, buf, PLANET_NAME_LEN - 1, 0, false, ctbl)) { util_trim_whitespace(buf, sizeof(buf)); if (strcasecmp(buf, "/galaxy") == 0) { game_cheat_galaxy(g, pi); } else if (strcasecmp(buf, "/elections") == 0) { game_cheat_elections(g, pi); } else if (strcasecmp(buf, "/events") == 0) { game_cheat_events(g, pi); } else if (strcasecmp(buf, "/spyhint") == 0) { game_cheat_spy_hint(g, pi); } else if (strcasecmp(buf, "/stars") == 0) { game_cheat_stars(g, pi); } else if (strcasecmp(buf, "/techhint") == 0) { game_cheat_tech_hint(g, pi); } else if (strcasecmp(buf, "/p") == 0) { game_cheat_traits(g, pi); } else if (strcasecmp(buf, "/moola") == 0) { game_cheat_moola(g, pi); } else if (strcasecmp(buf, "/oracle0") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 0, true); } else if (strcasecmp(buf, "/oracle1") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 1, true); } else if (strcasecmp(buf, "/oracle2") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 2, true); } else if (strcasecmp(buf, "/oracle3") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 3, true); } else if (strcasecmp(buf, "/oracle4") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 4, true); } else if (strcasecmp(buf, "/oracle5") == 0) { ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); ui_specs(g, 5, true); } else if (buf[0] != 0) { pli = search_planet(g, pi, buf); } } } uiobj_unset_callback(); uiobj_table_clear(); hw_video_copy_back_from_page2(); uiobj_finish_frame(); return pli; } bool ui_search_set_pos(struct game_s *g, player_id_t pi) { int found = ui_search(g, pi); if (found >= 0) { g->planet_focus_i[pi] = found; ui_starmap_set_pos_focus(g, pi); return true; } return false; } 1oom-1.11.2/src/ui/classic/uisearch.h000066400000000000000000000003431476061725400172640ustar00rootroot00000000000000#ifndef INC_1OOM_UISEARCH_H #define INC_1OOM_UISEARCH_H #include "game_types.h" struct game_s; extern int ui_search(struct game_s *g, player_id_t pi); extern bool ui_search_set_pos(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uisound.c000066400000000000000000000024651476061725400171510ustar00rootroot00000000000000#include "config.h" #include #include "uisound.h" #include "hw.h" #include "lbx.h" #include "lib.h" #include "log.h" #include "types.h" #include "ui.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ void ui_sound_play_sfx(int sfxi) { if ((sfxi < 0) || (sfxi >= NUM_SOUNDS)) { log_error("uisound: invalid sfx num %i\n", sfxi); hw_audio_sfx_stop(); return; } hw_audio_sfx_play(sfxi); } void ui_sound_play_sfx_24(void) { ui_sound_play_sfx(0x24); } void ui_sound_play_sfx_06(void) { ui_sound_play_sfx(0x06); } void ui_sound_stop_sfx(void) { hw_audio_sfx_stop(); } void ui_sound_play_music(int musici) { if ((musici < 0) || (musici >= NUM_MUSICS)) { log_error("uisound: invalid music num %i\n", musici); return; } hw_audio_music_stop(); { uint8_t *n; uint32_t len; n = lbxfile_item_get_with_len(LBXFILE_MUSIC, musici, &len); if (ui_data.mus) { hw_audio_music_release(0); lbxfile_item_release(LBXFILE_MUSIC, ui_data.mus); } hw_audio_music_init(0, n, len); ui_data.mus = n; ui_data.music_i = musici; } hw_audio_music_play(0); } void ui_sound_stop_music(void) { hw_audio_music_stop(); } 1oom-1.11.2/src/ui/classic/uisound.h000066400000000000000000000004101476061725400171420ustar00rootroot00000000000000#ifndef INC_1OOM_UISOUND_H #define INC_1OOM_UISOUND_H extern void ui_sound_play_sfx_24(void); extern void ui_sound_play_sfx_06(void); extern void ui_sound_stop_sfx(void); extern void ui_sound_play_music(int musici); extern void ui_sound_stop_music(void); #endif 1oom-1.11.2/src/ui/classic/uispecs.c000066400000000000000000000277751476061725400171510ustar00rootroot00000000000000#include "config.h" #include #include #include "uispecs.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_parsed.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "util.h" /* -------------------------------------------------------------------------- */ struct specs_data_s { struct game_s *g; player_id_t api; int scrapi; int renamei; }; static void specs_print_weap(weapon_t wi, uint8_t wn, char *buf1, size_t buf1_size, char *buf2, size_t buf2_size) { lib_strcpy(buf1, *tbl_shiptech_weap[wi].nameptr, buf1_size); /* FIXME make plural form somehow modifiable */ if ((wn != 1) && (wi != WEAPON_DEATH_SPORES)) { lib_strcat(buf1, "s", buf1_size); } if (tbl_shiptech_weap[wi].numshots > 0) { lib_sprintf(buf2, buf2_size, "%i", tbl_shiptech_weap[wi].numshots); } else { buf2[0] = '\0'; } } static void specs_draw_cb1(void *vptr) { struct specs_data_s *d = vptr; struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); shipresearch_t *srd = &(g->srd[d->api]); ui_draw_color_buf(0x3a); lbxgfx_draw_frame(0, 0, ui_data.gfx.starmap.viewship, UI_SCREEN_W, ui_scale); for (int si = 0; si < e->shipdesigns_num; ++si) { shipparsed_t sp; const shipdesign_t *sd; int y; sd = &(srd->design[si]); game_parsed_from_design(&sp, sd, 1); y = (si << 5) + 5; lbxgfx_draw_frame(44, y - 1, ui_data.gfx.starmap.viewshp2, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(6, y, 37, y + 29, 0, ui_scale); ui_draw_stars(6, y + 1, si * 5, 32, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.ships[sp.look]); for (int f = 0; f <= ui_data.starmap.frame_ship; ++f) { lbxgfx_draw_frame(6, y + 3, ui_data.gfx.ships[sp.look], UI_SCREEN_W, ui_scale); } lbxgfx_set_new_frame(ui_data.gfx.starmap.viewshbt, 1); lbxgfx_draw_frame(106, y + 1, ui_data.gfx.starmap.viewshbt, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(35, y + 22, srd->shipcount[si], UI_SCREEN_W, ui_scale); if (d->renamei != si) { lbxfont_print_str_normal(49, y + 2, sp.name, UI_SCREEN_W, ui_scale); } lbxfont_select(2, 0xb, 0, 0); lbxfont_print_num_right(86, y + 13, sp.defense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(86, y + 23, sp.misdefense, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(126, y + 13, sp.complevel, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(126, y + 23, sp.hp, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(163, y + 3, sp.absorb, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(163, y + 13, sp.engine + 1, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(163, y + 23, sp.man, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xa, 0, 0); for (int wi = 0; wi < WEAPON_SLOT_NUM; ++wi) { if (sp.wpnn[wi] != 0) { char buf1[64]; char buf2[12]; lbxfont_print_num_right(176, y + 3 + wi * 7, sp.wpnn[wi], UI_SCREEN_W, ui_scale); specs_print_weap(sp.wpnt[wi], sp.wpnn[wi], buf1, sizeof(buf1), buf2, sizeof(buf2)); lbxfont_print_str_normal(180, y + 3 + wi * 7, buf1, UI_SCREEN_W, ui_scale); if (buf2[0] != '\0') { lbxfont_print_str_right(250, y + 3 + wi * 7, buf2, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(252, y + 3 + wi * 7, "&", UI_SCREEN_W, ui_scale); } } } if (sp.special[0] == 0) { lbxfont_select(2, 0xa, 0, 0); } else { lbxfont_set_color_c_n(0xb5, 5); } lbxfont_print_str_center(285, y + 2, game_str_tbl_st_specsh[sp.special[0]], UI_SCREEN_W, ui_scale); if (sp.special[1] != 0) { lbxfont_print_str_center(285, y + 9, game_str_tbl_st_specsh[sp.special[1]], UI_SCREEN_W, ui_scale); } if (sp.special[2] != 0) { lbxfont_print_str_center(285, y + 16, game_str_tbl_st_specsh[sp.special[2]], UI_SCREEN_W, ui_scale); } lbxfont_select(2, 0xa, 0, 0); lbxfont_print_str_normal(262, y + 23, game_str_sp_cost, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(305, y + 23, game_str_bc, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(295, y + 23, sd->cost, UI_SCREEN_W, ui_scale); } ui_draw_set_stars_xoffs(false); ui_data.starmap.frame_ship = (ui_data.starmap.frame_ship + 1) % 5; } static void specs_before_draw_cb(void *vptr) { struct specs_data_s *d = vptr; specs_draw_cb1(d); lbxgfx_apply_colortable(0, 0, UI_VGA_W - 1, UI_VGA_H - 1, 0, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(67, 73, ui_data.gfx.starmap.dismiss, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_1(3, 0, 0, 0); lbxfont_print_str_split(74, 83, 174, game_str_sp_before, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } static void specs_mustscrap_draw_cb(void *vptr) { struct specs_data_s *d = vptr; struct game_s *g = d->g; shipresearch_t *srd = &(g->srd[d->api]); uint8_t *gfx = ui_data.gfx.ships[srd->design[d->scrapi].look]; hw_video_copy_back_from_page2(); lbxgfx_draw_frame(107, 50, ui_data.gfx.starmap.scrap, UI_SCREEN_W, ui_scale); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_split(117, 58, 90, game_str_sp_only6, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(114, 102, gfx, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(143, 119, srd->shipcount[d->scrapi], UI_SCREEN_W, ui_scale); lbxfont_select(0, 0, 0, 0); lbxfont_print_str_split(150, 107, 60, game_str_sp_wantscrap, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_specs_before(struct game_s *g, player_id_t active_player) { struct specs_data_s d; bool flag_done = false; int16_t oi_ma; game_update_maint_costs(g); d.g = g; d.api = active_player; d.renamei = -1; ui_data.starmap.frame_ship = 0; ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; oi_ma = UIOBJI_INVALID; uiobj_set_callback_and_delay(specs_before_draw_cb, &d, 2); uiobj_table_clear(); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ma) || (oi == UIOBJI_ESC)) { flag_done = true; } specs_before_draw_cb(&d); uiobj_table_clear(); oi_ma = uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); ui_draw_finish(); ui_delay_ticks_or_click(3); } uiobj_unset_callback(); uiobj_table_clear(); } void ui_specs_mustscrap(struct game_s *g, player_id_t active_player, int scrapi) { struct specs_data_s d; bool flag_done = false; int16_t oi_no = UIOBJI_INVALID, oi_yes = UIOBJI_INVALID; d.g = g; d.api = active_player; ui_data.starmap.frame_ship = 0; d.scrapi = scrapi; d.renamei = -1; uiobj_set_callback_and_delay(specs_mustscrap_draw_cb, &d, 2); uiobj_table_clear(); ui_draw_copy_buf(); lbxgfx_apply_colortable(0, 0, UI_VGA_W - 1, UI_VGA_H - 1, 0, UI_SCREEN_W, ui_scale); hw_video_copy_back_to_page2(); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_no) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_06(); ui_data.ui_main_loop_action = ui_data.ui_main_loop_action_next; flag_done = true; } else if (oi == oi_yes) { ui_sound_play_sfx_24(); game_design_scrap(g, active_player, scrapi, ui_data.flag_scrap_for_new_design); ui_data.ui_main_loop_action = ui_data.ui_main_loop_action_prev; flag_done = true; } if (!flag_done) { specs_mustscrap_draw_cb(&d); uiobj_table_clear(); oi_no = uiobj_add_t0(116, 132, "", ui_data.gfx.starmap.scrapbut_no, MOO_KEY_n); oi_yes = uiobj_add_t0(165, 132, "", ui_data.gfx.starmap.scrapbut_yes, MOO_KEY_y); ui_draw_finish(); ui_delay_ticks_or_click(2); } } uiobj_unset_callback(); uiobj_table_clear(); } int ui_specs(struct game_s *g, player_id_t active_player, bool flag_cheat) { struct specs_data_s d; bool flag_done = false; int16_t oi_ma, oi_tbl_scrap[NUM_SHIPDESIGNS], oi_tbl_rename[NUM_SHIPDESIGNS]; int scrapi = -1; game_update_maint_costs(g); d.g = g; d.api = active_player; d.renamei = -1; ui_data.starmap.frame_ship = 0; ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; oi_ma = UIOBJI_INVALID; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { oi_tbl_scrap[i] = UIOBJI_INVALID; oi_tbl_rename[i] = UIOBJI_INVALID; } uiobj_set_help_id(35); uiobj_set_callback_and_delay(specs_draw_cb1, &d, 2); uiobj_table_clear(); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ma) || (oi == UIOBJI_ESC)) { if (!flag_cheat) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_FLEET; ui_data.flag_scrap_for_new_design = false; } flag_done = true; } for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (oi == oi_tbl_scrap[i]) { ui_sound_play_sfx_24(); scrapi = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_MUSTSCRAP; if (!ui_data.flag_scrap_for_new_design) { ui_data.ui_main_loop_action_prev = UI_MAIN_LOOP_SPECS; ui_data.ui_main_loop_action_next = UI_MAIN_LOOP_SPECS; } else { ui_specs_mustscrap(g, active_player, scrapi); } flag_done = true; } if (oi == oi_tbl_rename[i]) { const uint8_t ctbl[8] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; shipresearch_t *srd = &(g->srd[active_player]); char buf[SHIP_NAME_LEN]; lib_strcpy(buf, srd->design[i].name, sizeof(buf)); lbxfont_select(0, 0xd, 0, 0); d.renamei = i; if (uiobj_read_str(49, (i << 5) + 7, 55, buf, SHIP_NAME_LEN - 1, 0, false, ctbl)) { util_trim_whitespace(buf, sizeof(buf)); if (buf[0] != 0) { lib_strcpy(srd->design[i].name, buf, SHIP_NAME_LEN); } } d.renamei = -1; flag_done = true; } } if (!flag_done) { int sd_num; sd_num = g->eto[active_player].shipdesigns_num; specs_draw_cb1(&d); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { oi_tbl_scrap[i] = UIOBJI_INVALID; oi_tbl_rename[i] = UIOBJI_INVALID; } uiobj_table_clear(); if ((sd_num > 1) && !flag_cheat) { for (int i = 0; i < sd_num; ++i) { oi_tbl_scrap[i] = uiobj_add_t0(106, (i << 5) + 6, "", ui_data.gfx.starmap.viewshbt, MOO_KEY_1 + i); } } if (!flag_cheat) { for (int i = 0; i < sd_num; ++i) { oi_tbl_rename[i] = uiobj_add_mousearea(46, (i << 5) + 6, 103, (i << 5) + 13, MOO_KEY_UNKNOWN); } } oi_ma = uiobj_add_mousearea_all(MOO_KEY_o); ui_draw_finish(); ui_delay_ticks_or_click(3); } } uiobj_unset_callback(); uiobj_set_help_id(-1); uiobj_table_clear(); return scrapi; } 1oom-1.11.2/src/ui/classic/uispecs.h000066400000000000000000000004751476061725400171420ustar00rootroot00000000000000#ifndef INC_1OOM_UISPECS_H #define INC_1OOM_UISPECS_H #include "game_types.h" struct game_s; extern int ui_specs(struct game_s *g, player_id_t pi, bool flag_cheat); extern void ui_specs_before(struct game_s *g, player_id_t pi); extern void ui_specs_mustscrap(struct game_s *g, player_id_t pi, int scrapi); #endif 1oom-1.11.2/src/ui/classic/uispy_esp.c000066400000000000000000000154441476061725400175040ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "game_tech.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uisound.h" #include "uiswitch.h" #include "uiempirereport.h" /* -------------------------------------------------------------------------- */ struct steal_data_s { struct game_s *g; player_id_t spy; player_id_t target; uint8_t flags_field; uint8_t *gfx_espionag; void *gmap; }; static void steal_load_data(struct steal_data_s *d) { d->gfx_espionag = lbxfile_item_get(LBXFILE_BACKGRND, 0xd); } static void steal_free_data(struct steal_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_espionag); } static void steal_draw_cb(void *vptr) { struct steal_data_s *d = vptr; struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->target]); char buf[0xe0]; hw_video_copy_back_from_page3(); ui_gmap_basic_draw_frame(d->gmap, d->spy); lbxgfx_draw_frame(6, 24, d->gfx_espionag, UI_SCREEN_W, ui_scale); { char rbuf[0x20], *p, c; bool usean = false; lib_strcpy(rbuf, game_str_tbl_race[e->race], sizeof(rbuf)); p = rbuf; while ((c = *p) != '\0') { if (islower(c)) { c = toupper(c); *p = c; } if ((c == 'A') || (c == 'E') || (c == 'I') || (c == 'O') || (c == 'U')) { usean = true; } ++p; } lib_sprintf(buf, sizeof(buf), "%s%s %s %s", game_str_es_youresp1, usean ? "N" : "", rbuf, game_str_es_youresp2); } lbxfont_select_set_12_1(0, 8, 0, 0); lbxfont_print_str_center(118, 30, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(23, 83, game_str_es_youresp3, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(102, 43, ui_data.gfx.planets.race[e->race], UI_SCREEN_W, ui_scale); for (int i = 0; i < TECH_FIELD_NUM; ++i) { if (d->flags_field & (1 << i)) { int x, y; x = (i / 3) * 102 + 20; y = (i % 3) * 22 + 97; ui_draw_filled_rect(x, y, x + 86, y + 11, 4, ui_scale); lbxfont_select(5, 0xe, 0, 0); lbxfont_print_str_center(x + 43, y + 3, game_str_tbl_te_field[i], UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ struct stolen_data_s { struct game_s *g; player_id_t api; player_id_t spy; tech_field_t field; uint8_t tech; uint8_t *gfx; void *gmap; }; static void stolen_load_data(struct stolen_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 0xe); } static void stolen_free_data(struct stolen_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void stolen_draw_cb(void *vptr) { struct stolen_data_s *d = vptr; const struct game_s *g = d->g; const char *s; uint8_t fontparam; char buf[0x80]; if (d->spy != PLAYER_NONE) { const empiretechorbit_t *e = &(g->eto[d->spy]); s = game_str_tbl_race[e->race]; fontparam = tbl_banner_fontparam[e->banner]; } else { s = game_str_es_unkn; fontparam = 2; } hw_video_copy_back_from_page2(); ui_gmap_basic_draw_frame(d->gmap, d->api); ui_draw_filled_rect(31, 62, 202, 103, 0x36, ui_scale); lbxgfx_draw_frame(31, 62, d->gfx, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %s", s, game_str_es_thesp1); lbxfont_select_set_12_1(5, fontparam, 0, 0); lbxfont_print_str_center(116, 70, buf, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %s ", s, game_str_es_thesp2); lbxfont_print_str_center(118, 84, buf, UI_SCREEN_W, ui_scale); game_tech_get_name(g->gaux, d->field, d->tech, buf, sizeof(buf)); lbxfont_print_str_center(118, 94, buf, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ int ui_spy_steal(struct game_s *g, int spy, int target, uint8_t flags_field) { struct steal_data_s d; bool flag_done = false; int16_t oi_tbl_field[TECH_FIELD_NUM]; int16_t oi_report = UIOBJI_INVALID; int selected = -1; ui_switch_1(g, spy); ui_sound_play_music(0xf); hw_video_copy_back_from_page2(); hw_video_copy_back_to_page3(); d.g = g; d.spy = spy; d.target = target; d.flags_field = flags_field; d.gmap = ui_gmap_basic_init(g, true); steal_load_data(&d); restart: uiobj_table_clear(); for (int i = 0; i < TECH_FIELD_NUM; ++i) { if (flags_field & (1 << i)) { int x, y; x = (i / 3) * 102 + 20; y = (i % 3) * 22 + 97; oi_tbl_field[i] = uiobj_add_mousearea(x - 2, y - 2, x + 88, y + 13, MOO_KEY_UNKNOWN); } else { oi_tbl_field[i] = UIOBJI_INVALID; } } if (g->gaux->flag_cheat_spy_hint) { oi_report = uiobj_add_mousearea(18, 43, 210, 76, MOO_KEY_UNKNOWN); } uiobj_set_callback_and_delay(steal_draw_cb, &d, 4); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi == UIOBJI_ESC) { ui_sound_play_sfx_24(); selected = -1; flag_done = true; } else if (oi == oi_report) { ui_empirereport(g, spy, target); goto restart; } for (int i = 0; i < TECH_FIELD_NUM; ++i) { if (oi == oi_tbl_field[i]) { ui_sound_play_sfx_24(); selected = i; flag_done = true; } } if (!flag_done) { steal_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } } ui_sound_stop_music(); uiobj_unset_callback(); uiobj_table_clear(); steal_free_data(&d); hw_video_copy_back_from_page3(); hw_video_copy_back_to_page2(); return selected; } void ui_spy_stolen(struct game_s *g, int pi, int spy, int field, uint8_t tech) { struct stolen_data_s d; bool flag_done = false; ui_switch_1(g, pi); d.g = g; d.api = pi; d.spy = spy; d.field = field; d.tech = tech; d.gmap = ui_gmap_basic_init(g, true); stolen_load_data(&d); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } stolen_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(3); } uiobj_table_clear(); stolen_free_data(&d); } 1oom-1.11.2/src/ui/classic/uispy_sab.c000066400000000000000000000360471476061725400174640ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uigmap.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct sabotage_data_s { struct game_s *g; player_id_t api; player_id_t spy; player_id_t target; player_id_t other1; player_id_t other2; ui_sabotage_t act; int snum; uint8_t planet; uint8_t *gfx_saboback; uint8_t *gfx_sabobac2; uint8_t *gfx_butt_revolt; uint8_t *gfx_butt_bases; uint8_t *gfx_butt_ind; uint8_t *gfx_basexplo; uint8_t *gfx_ind_expl; uint8_t *gfx_framing; uint8_t *gfx_contbutt; uint8_t *gfx_contback; uint8_t *gfx_colony; void *gmap; }; static void sabotage_load_data(struct sabotage_data_s *d) { d->gfx_saboback = lbxfile_item_get(LBXFILE_BACKGRND, 0x5); d->gfx_sabobac2 = lbxfile_item_get(LBXFILE_BACKGRND, 0x32); d->gfx_butt_revolt = lbxfile_item_get(LBXFILE_BACKGRND, 0x33); d->gfx_butt_bases = lbxfile_item_get(LBXFILE_BACKGRND, 0x6); d->gfx_butt_ind = lbxfile_item_get(LBXFILE_BACKGRND, 0xa); d->gfx_basexplo = lbxfile_item_get(LBXFILE_BACKGRND, 0x7); d->gfx_ind_expl = lbxfile_item_get(LBXFILE_BACKGRND, 0x8); d->gfx_framing = lbxfile_item_get(LBXFILE_BACKGRND, 0x9); d->gfx_contbutt = lbxfile_item_get(LBXFILE_BACKGRND, 0xc); d->gfx_contback = lbxfile_item_get(LBXFILE_BACKGRND, 0xb); d->gfx_colony = lbxfile_item_get(LBXFILE_COLONIES, d->g->planet[d->planet].type * 2 + 1); } static void sabotage_free_data(struct sabotage_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_saboback); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_sabobac2); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_butt_revolt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_butt_bases); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_butt_ind); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_basexplo); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_ind_expl); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_framing); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_contbutt); lbxfile_item_release(LBXFILE_BACKGRND, d->gfx_contback); lbxfile_item_release(LBXFILE_COLONIES, d->gfx_colony); } static void sabotage_draw_cb(void *vptr) { struct sabotage_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->target]); const planet_t *p = &(g->planet[d->planet]); int pop, bases, fact; hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_sabobac2, UI_SCREEN_W, ui_scale); ui_starmap_draw_planetinfo_2(g, d->api, d->target, d->planet); /*set_limits(228, 110, 309, 143);*/ lbxgfx_draw_frame_offs(228, 70, d->gfx_colony, 228, 110, 309, 143, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(228, 58, 309, 68, tbl_banner_color2[e->banner], ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_print_str_center(269, 60, game_str_tbl_races[e->race], UI_SCREEN_W, ui_scale); ui_draw_filled_rect(227, 73, 310, 105, 0, ui_scale); ui_draw_filled_rect(228, 74, 309, 104, 7, ui_scale); lbxfont_select_set_12_1(5, 0, 0, 0); lbxfont_print_str_split(228, 79, 80, game_str_sb_choose, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); /*game_update_visibility();*/ ui_gmap_basic_draw_frame(d->gmap, d->api); lbxfont_select_set_12_4(0, 0xa, 0, 0); if (BOOLVEC_IS1(p->within_srange, d->api)) { pop = p->pop; bases = p->missile_bases; fact = p->factories; } else { pop = g->seen[d->api][d->planet].pop; bases = g->seen[d->api][d->planet].bases; fact = g->seen[d->api][d->planet].factories; lbxfont_print_str_normal(230, 111, game_str_sb_lastrep, UI_SCREEN_W, ui_scale); } /*6d2b8*/ if (pop > 0) { lbxfont_print_str_normal(230, 120, game_str_sb_pop, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(305, 120, pop, UI_SCREEN_W, ui_scale); } if (fact > 0) { lbxfont_print_str_normal(230, 128, game_str_sb_fact, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(305, 128, fact, UI_SCREEN_W, ui_scale); } if (bases > 0) { lbxfont_print_str_normal(230, 136, game_str_sb_bases, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(305, 136, bases, UI_SCREEN_W, ui_scale); } ui_gmap_draw_planet_border(g, d->planet); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == d->target) { int x, y; x = (p->x * 215) / g->galaxy_maxx + 5 + 3; y = (p->y * 171) / g->galaxy_maxy + 5 - 2; lbxgfx_draw_frame(x, y, ui_data.gfx.starmap.smalflag[e->banner], UI_SCREEN_W, ui_scale); } } } static void sabotage_draw_anim(uint8_t *gfx, bool anim, int soundframe) { int frame = anim ? lbxgfx_get_frame(gfx) : 0; lbxgfx_set_frame_0(gfx); for (int f = 0; f <= frame; ++f) { lbxgfx_draw_frame(227, 73, gfx, UI_SCREEN_W, ui_scale); } if (frame == soundframe) { ui_sound_play_sfx(0x11); } } static void sabotage_done_draw_cb(void *vptr) { struct sabotage_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->target]); const planet_t *p = &(g->planet[d->planet]); char *buf = ui_data.strbuf; struct strbuild_s strbuild = strbuild_init(buf, UI_STRBUF_SIZE); hw_video_copy_back_from_page2(); ui_draw_filled_rect(222, 4, 314, 179, 0, ui_scale); lbxgfx_draw_frame(222, 4, d->gfx_saboback, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(222, 159, d->gfx_contback, UI_SCREEN_W, ui_scale); /*set_limits(228, 110, 309, 158);*/ lbxgfx_draw_frame_offs(228, 70, d->gfx_colony, 228, 110, 309, 158, UI_SCREEN_W, ui_scale); switch (d->act) { case UI_SABOTAGE_FACT: /*0*/ sabotage_draw_anim(d->gfx_ind_expl, (d->snum > 0), 11); break; case UI_SABOTAGE_BASES: /*1*/ sabotage_draw_anim(d->gfx_basexplo, (d->snum > 0), 5); break; case UI_SABOTAGE_REVOLT: /*2*/ sabotage_draw_anim(d->gfx_ind_expl, false, 100); break; default: break; } ui_starmap_draw_planetinfo_2(g, d->api, d->target, d->planet); ui_draw_filled_rect(228, 58, 309, 68, tbl_banner_color2[e->banner], ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_print_str_center(269, 60, game_str_tbl_races[e->race], UI_SCREEN_W, ui_scale); if (d->spy == PLAYER_NONE) { strbuild_catf(&strbuild, "%s ", game_str_sb_unkn); } else { strbuild_catf(&strbuild, "%s %s ", (d->spy == d->api) ? game_str_sb_your : game_str_tbl_race[g->eto[d->spy].race], game_str_sb_spies); } if (d->snum > 0) { switch (d->act) { default: case UI_SABOTAGE_FACT: /*0*/ strbuild_catf(&strbuild, "%s %i %s", game_str_sb_destr, d->snum, (d->snum == 1) ? game_str_sb_fact2 : game_str_sb_facts); break; case UI_SABOTAGE_BASES: /*1*/ strbuild_catf(&strbuild, "%s %i %s", game_str_sb_destr, d->snum, (d->snum == 1) ? game_str_sb_mbase : game_str_sb_mbases); break; case UI_SABOTAGE_REVOLT: /*2*/ if (p->unrest == PLANET_UNREST_REBELLION) { strbuild_catf(&strbuild, "%s", game_str_sb_increv); } else { int v = (p->pop == 0) ? 0 : ((p->rebels * 100) / p->pop); strbuild_catf(&strbuild, "%s %i %s %i%%.", game_str_sb_inc1, d->snum, game_str_sb_inc2, v); } break; } } else { /*6da9e*/ strbuild_catf(&strbuild, "%s", game_str_sb_failed); switch (d->act) { default: case UI_SABOTAGE_FACT: /*0*/ if (p->factories == 0) { lib_sprintf(buf, UI_STRBUF_SIZE, "%s", game_str_sb_nofact); } break; case UI_SABOTAGE_BASES: /*1*/ if (p->missile_bases == 0) { lib_sprintf(buf, UI_STRBUF_SIZE, "%s", game_str_sb_nobases); } break; case UI_SABOTAGE_REVOLT: /*2*/ lib_strcat(buf, game_str_sb_noinc, UI_STRBUF_SIZE); /* FIXME never happens? */ break; } } /*6db14*/ lbxfont_select_set_12_4(5, 5, 0, 0); lbxfont_print_str_split(228, 118, 84, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); ui_gmap_basic_draw_frame(d->gmap, d->api); ui_gmap_draw_planet_border(g, d->planet); lbxgfx_set_new_frame(d->gfx_contbutt, 1); lbxgfx_draw_frame(227, 163, d->gfx_contbutt, UI_SCREEN_W, ui_scale); if (d->other2 != PLAYER_NONE) { ui_draw_filled_rect(31, 62, 202, 125, 0xbb, ui_scale); ui_draw_filled_rect(37, 68, 196, 91, 0xba, ui_scale); lbxgfx_draw_frame(31, 62, d->gfx_framing, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(50, 106, 110, 120, 0x00, ui_scale); ui_draw_filled_rect(51, 107, 109, 119, tbl_banner_color2[g->eto[d->other1].banner], ui_scale); ui_draw_filled_rect(122, 106, 183, 120, 0x00, ui_scale); ui_draw_filled_rect(123, 107, 182, 119, tbl_banner_color2[g->eto[d->other2].banner], ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_print_str_center(80, 110, game_str_tbl_races[g->eto[d->other1].race], UI_SCREEN_W, ui_scale); lbxfont_print_str_center(152, 110, game_str_tbl_races[g->eto[d->other2].race], UI_SCREEN_W, ui_scale); lbxfont_select(5, 6, 0, 0); lbxfont_set_gap_h(2); lbxfont_print_str_split(40, 70, 154, game_str_sb_frame, 3, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxfont_select(0, 0, 0, 0); lbxfont_print_str_center(115, 96, game_str_nt_victim, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ ui_sabotage_t ui_spy_sabotage_ask(struct game_s *g, int spy, int target, uint8_t *planetptr) { struct sabotage_data_s d; int16_t oi_bases, oi_ind, oi_revolt, oi_planet[PLANETS_MAX]; bool flag_done = false; ui_sabotage_t action = UI_SABOTAGE_NONE; ui_switch_1(g, spy); d.g = g; d.api = spy; d.spy = spy; d.target = target; d.planet = PLANET_NONE; d.gmap = ui_gmap_basic_init(g, true); for (int i = 0; i < g->galaxy_stars; ++i) { if (g->planet[i].owner == target) { d.planet = i; break; } } if (d.planet == PLANET_NONE) { *planetptr = 0; return UI_SABOTAGE_NONE; } sabotage_load_data(&d); ui_sound_play_music(0x10); uiobj_table_clear(); oi_bases = UIOBJI_INVALID; oi_ind = UIOBJI_INVALID; oi_revolt = UIOBJI_INVALID; UIOBJI_SET_TBL_INVALID(oi_planet); uiobj_set_callback_and_delay(sabotage_draw_cb, &d, 4); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { ui_sound_play_sfx_24(); } if (oi == UIOBJI_ESC) { flag_done = true; action = UI_SABOTAGE_NONE; } if (oi == oi_bases) { flag_done = true; action = UI_SABOTAGE_BASES; } if (oi == oi_ind) { flag_done = true; action = UI_SABOTAGE_FACT; } if (oi == oi_revolt) { flag_done = true; action = UI_SABOTAGE_REVOLT; } for (int i = 0; i < g->galaxy_stars; ++i) { if (oi == oi_planet[i]) { d.planet = i; lbxfile_item_release(LBXFILE_COLONIES, d.gfx_colony); d.gfx_colony = lbxfile_item_get(LBXFILE_COLONIES, g->planet[i].type * 2 + 1); break; } } uiobj_table_clear(); oi_bases = uiobj_add_t0(227, 147, "", d.gfx_butt_bases, MOO_KEY_b); oi_ind = uiobj_add_t0(267, 147, "", d.gfx_butt_ind, MOO_KEY_f); if (g->planet[d.planet].unrest == PLANET_UNREST_NORMAL) { oi_revolt = uiobj_add_t0(227, 163, "", d.gfx_butt_revolt, MOO_KEY_i); } else { oi_revolt = UIOBJI_INVALID; } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == target) { int x, y; x = (p->x * 215) / g->galaxy_maxx + 5; y = (p->y * 171) / g->galaxy_maxy + 5; oi_planet[i] = uiobj_add_mousearea(x - 1, y - 1, x + 7, y + 7, MOO_KEY_UNKNOWN); } else { oi_planet[i] = UIOBJI_INVALID; } } sabotage_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } uiobj_unset_callback(); uiobj_table_clear(); ui_sound_stop_music(); sabotage_free_data(&d); *planetptr = d.planet; return action; } int ui_spy_sabotage_done(struct game_s *g, int pi, int spy, int target, ui_sabotage_t act, int other1, int other2, uint8_t planet, int snum) { struct sabotage_data_s d; int16_t oi_cont, oi_cont2, oi_other1, oi_other2; bool flag_done = false; int other = PLAYER_NONE; ui_switch_1(g, pi); d.g = g; d.api = pi; d.spy = spy; d.target = target; d.other1 = other1; d.other2 = other2; d.planet = planet; d.act = act; d.snum = snum; d.gmap = ui_gmap_basic_init(g, true); sabotage_load_data(&d); if (snum > 0) { ui_sound_play_music(0x11); } lbxgfx_set_frame_0(d.gfx_basexplo); lbxgfx_set_frame_0(d.gfx_ind_expl); uiobj_table_clear(); oi_cont = UIOBJI_INVALID; oi_cont2 = UIOBJI_INVALID; oi_other1 = UIOBJI_INVALID; oi_other2 = UIOBJI_INVALID; if (other2 == PLAYER_NONE) { oi_cont = uiobj_add_t0(227, 163, "", d.gfx_contbutt, MOO_KEY_c); oi_cont2 = uiobj_add_inputkey(MOO_KEY_SPACE); } else { oi_other1 = uiobj_add_mousearea(50, 106, 110, 120, MOO_KEY_UNKNOWN); oi_other2 = uiobj_add_mousearea(122, 106, 183, 120, MOO_KEY_UNKNOWN); } uiobj_set_callback_and_delay(sabotage_done_draw_cb, &d, 4); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if ((oi == UIOBJI_ESC) || (oi == oi_cont) || (oi == oi_cont2)) { ui_sound_play_sfx_24(); flag_done = true; } if (oi == oi_other1) { ui_sound_play_sfx_24(); flag_done = true; other = other1; } if (oi == oi_other2) { ui_sound_play_sfx_24(); flag_done = true; other = other2; } sabotage_done_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(4); } uiobj_unset_callback(); uiobj_table_clear(); ui_sound_stop_music(); sabotage_free_data(&d); return other; } 1oom-1.11.2/src/ui/classic/uistarmap.c000066400000000000000000000746321476061725400174750ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_cheat.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_save.h" #include "game_str.h" #include "game_tech.h" #include "game_techtypes.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uidialog.h" #include "uihelp.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void ui_starmap_draw_cb1(void *vptr) { struct starmap_data_s *d = vptr; ui_starmap_draw_basic(d); if (d->g->gaux->flag_cheat_events) { ui_draw_text_overlay(0, 0, game_str_no_events); } if (d->g->gaux->flag_cheat_elections) { ui_draw_text_overlay(0, 10, game_str_no_elections); } } static void ui_starmap_planet_slider_cb(void *ctx, uint8_t i, int16_t value) { struct starmap_data_s *d = ctx; struct game_s *g = d->g; planet_t *p = &g->planet[g->planet_focus_i[d->api]]; if (!p->slider_lock[i]) { game_adjust_slider_group(p->slider, i, p->slider[i], PLANET_SLIDER_NUM, p->slider_lock); } } bool ui_starmap_remove_build_finished(struct game_s *g, player_id_t api, planet_t *p) { int num = g->evn.build_finished_num[api]; if (num) { g->evn.build_finished_num[api] = --num; for (planet_finished_t i = 0; i < FINISHED_SHIP; ++i) { if (BOOLVEC_IS1(p->finished, i)) { BOOLVEC_SET0(p->finished, i); break; } } if (!num) { return true; } } return false; } static void ui_starmap_fill_oi_slider(struct starmap_data_s *d, planet_t *p) { const struct game_s *g = d->g; d->sm.oi_ship = UIOBJI_INVALID; d->sm.oi_reloc = UIOBJI_INVALID; d->sm.oi_trans = UIOBJI_INVALID; UIOBJI_SET_TBL3_INVALID(d->sm.oi_tbl_slider_lock, d->sm.oi_tbl_slider_minus, d->sm.oi_tbl_slider_plus); if ((p->owner == d->api) && (p->unrest != PLANET_UNREST_REBELLION)) { for (planet_slider_i_t i = PLANET_SLIDER_SHIP; i < PLANET_SLIDER_NUM; ++i) { int y0; y0 = 81 + i * 11; if (!p->slider_lock[i]) { uiobj_add_slider_func(253, y0 + 3, 0, 100, 25, 9, &p->slider[i], ui_starmap_planet_slider_cb, d, i); d->sm.oi_tbl_slider_minus[i] = uiobj_add_mousearea(247, y0 + 1, 251, y0 + 8, MOO_KEY_UNKNOWN); d->sm.oi_tbl_slider_plus[i] = uiobj_add_mousearea(280, y0 + 1, 283, y0 + 8, MOO_KEY_UNKNOWN); } d->sm.oi_tbl_slider_lock[i] = uiobj_add_mousearea(226, y0, 245, y0 + 9, MOO_KEY_UNKNOWN); } d->sm.oi_ship = uiobj_add_t0(282, 140, "", ui_data.gfx.starmap.col_butt_ship, MOO_KEY_s); if (p->buildship != BUILDSHIP_STARGATE) { d->sm.oi_reloc = uiobj_add_t0(282, 152, "", ui_data.gfx.starmap.col_butt_reloc, (ui_illogical_hotkey_fix ? MOO_KEY_r : MOO_KEY_l)); } if (g->evn.have_plague && (g->evn.plague_planet_i == g->planet_focus_i[d->api])) { lbxgfx_set_frame(ui_data.gfx.starmap.col_butt_trans, 1); lbxgfx_draw_frame(282, 164, ui_data.gfx.starmap.col_butt_trans, UI_SCREEN_W, ui_scale); } else { d->sm.oi_trans = uiobj_add_t0(282, 164, "", ui_data.gfx.starmap.col_butt_trans, MOO_KEY_x); } } } static void ui_starmap_do_help(struct game_s *g, player_id_t api) { const empiretechorbit_t *e = &(g->eto[api]); const shipresearch_t *srd = &(g->srd[api]); const planet_t *p = &(g->planet[g->evn.home[api]]); if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 0) && (g->year == 1)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 0); ui_help(0x00); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 2) && ((e->contact[0] & (~(1 << api))) != 0)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 2); ui_help(0x13); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 1) && (p->missile_bases == 0) && (p->pop >= 70)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 1); ui_help(0x12); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 3) && (g->year >= 70)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 3); ui_help(0x14); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 4) && (g->year >= 30)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 4); ui_help(0x16); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 5)) { for (int i = 1; i < e->tech.completed[TECH_FIELD_WEAPON]; ++i) { if (srd->researchcompleted[TECH_FIELD_WEAPON][i] != 2) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 5); ui_help(0x17); return; } } } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 6) && (g->year < 70)) { bool have_explored = false, can_colonize = true; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p2 = &(g->planet[i]); if ((p2 != p) && BOOLVEC_IS1(p2->explored, api)) { have_explored = true; if ((p2->type < e->have_colony_for) || (p2->owner == api)) { can_colonize = false; break; } } } if (have_explored && can_colonize) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 6); ui_help(0x19); return; } } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 8) && (p->factories >= 50) && (e->race != RACE_SILICOID)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 8); ui_help(0x1a); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 9)) { for (int i = 0; i < 8; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_PROPULSION, TECH_PROP_NUCLEAR_ENGINES + i * 6, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 9); ui_help(0x18); return; } } } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 10)) { for (int i = 0; i < 4; ++i) { if (game_tech_player_has_tech(g, TECH_FIELD_FORCE_FIELD, TECH_FFLD_CLASS_V_PLANETARY_SHIELD + i * 10, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 10); ui_help(0x1c); return; } } } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 11) && game_tech_player_has_tech(g, TECH_FIELD_PLANETOLOGY, TECH_PLAN_SOIL_ENRICHMENT, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 11); ui_help(0x1d); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 12) && game_tech_player_has_tech(g, TECH_FIELD_PLANETOLOGY, TECH_PLAN_ATMOSPHERIC_TERRAFORMING, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 12); ui_help(0x1e); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 13) && game_tech_player_has_tech(g, TECH_FIELD_PLANETOLOGY, TECH_PLAN_ADVANCED_SOIL_ENRICHMENT, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 13); ui_help(0x1f); return; } if (BOOLVEC_TBL_IS0(g->evn.help_shown, api, 14) && game_tech_player_has_tech(g, TECH_FIELD_PROPULSION, TECH_PROP_INTERGALACTIC_STAR_GATES, api)) { BOOLVEC_TBL_SET1(g->evn.help_shown, api, 14); ui_help(0x20); return; } } /* -------------------------------------------------------------------------- */ void ui_starmap_do(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_b, oi_c, oi_starview1, oi_starview2, oi_shippic, oi_finished, oi_equals, oi_hash, oi_f2, oi_f3, oi_f4, oi_f5, oi_f6, oi_f7, oi_f8, oi_f9, oi_f10, oi_alt_galaxy, oi_alt_p, oi_alt_events, oi_wheelname, oi_wheelshippic, oi_search, oi_rename, oi_adj[PLANET_SLIDER_NUM]; int16_t scrollmisc = 0; struct starmap_data_s d; ui_starmap_common_init(g, &d, active_player); ui_delay_1(); ui_sound_stop_music(); /* or fade? */ uiobj_set_downcount(1); game_update_production(g); game_update_visibility(g); ui_data.gfx.colonies.current = NULL; uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ STARMAP_UIOBJ_CLEAR_FX(); \ oi_b = UIOBJI_INVALID; \ oi_c = UIOBJI_INVALID; \ oi_starview1 = UIOBJI_INVALID; \ oi_starview2 = UIOBJI_INVALID; \ oi_shippic = UIOBJI_INVALID; \ oi_finished = UIOBJI_INVALID; \ oi_equals = UIOBJI_INVALID; \ oi_hash = UIOBJI_INVALID; \ oi_wheelname = UIOBJI_INVALID; \ oi_wheelshippic = UIOBJI_INVALID; \ oi_rename = UIOBJI_INVALID; \ d.sm.oi_ship = UIOBJI_INVALID; \ d.sm.oi_reloc = UIOBJI_INVALID; \ d.sm.oi_trans = UIOBJI_INVALID; \ UIOBJI_SET_TBL3_INVALID(d.sm.oi_tbl_slider_lock, d.sm.oi_tbl_slider_minus, d.sm.oi_tbl_slider_plus); \ UIOBJI_SET_TBL_INVALID(oi_adj); \ } while (0) UIOBJ_CLEAR_LOCAL(); oi_alt_galaxy = uiobj_add_alt_str("galaxy"); oi_alt_p = uiobj_add_alt_str("p"); oi_alt_events = uiobj_add_alt_str("events"); uiobj_set_callback_and_delay(ui_starmap_draw_cb1, &d, STARMAP_DELAY); while (!flag_done) { planet_t *p; int16_t oi1, oi2; p = &g->planet[g->planet_focus_i[active_player]]; uiobj_set_help_id((p->owner == active_player) ? 0 : 3); scrollmisc = 0; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if ((oi1 == d.sm.oi_ship) && ui_sm_ships_enabled) { ui_sound_play_sfx_24(); ui_data.ui_main_loop_action = UI_MAIN_LOOP_PLANET_SHIPS; flag_done = true; oi1 = 0; } else if (oi1 == d.sm.oi_reloc) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_RELOC; flag_done = true; ui_sound_play_sfx_24(); } else if (oi1 == d.sm.oi_trans) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANS; flag_done = true; ui_sound_play_sfx_24(); } else if (((oi1 == oi_starview1) && BOOLVEC_IS1(p->explored, active_player)) || (oi1 == oi_starview2)) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARVIEW; flag_done = true; ui_sound_play_sfx_24(); } else if (oi1 == oi_b) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_SCRAP_BASES; flag_done = true; ui_sound_play_sfx_24(); } else if (oi1 == oi_c) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_SPIES_CAUGHT; flag_done = true; ui_sound_play_sfx_24(); } else if ((oi1 == oi_finished) || ((oi1 == UIOBJI_ESC) && (oi_finished != UIOBJI_INVALID))) { if (ui_starmap_remove_build_finished(g, active_player, p)) { if (ui_extra_enabled) { g->planet_focus_i[active_player] = ui_data.start_planet_focus_i; ui_starmap_set_pos_focus(g, active_player); } } ui_sound_play_sfx_24(); flag_done = true; ui_delay_1(); } else if (oi1 == oi_alt_galaxy) { if (game_cheat_galaxy(g, active_player)) { ui_sound_play_sfx_24(); } } else if (oi1 == oi_alt_events) { if (game_cheat_events(g, active_player)) { ui_sound_play_sfx_24(); } } else if (oi1 == oi_f10) { game_save_do_save_i(GAME_SAVE_I_CONTINUE, "Continue", g); } else if (oi1 == oi_alt_p) { game_cheat_traits(g, active_player); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); ui_search_set_pos(g, active_player); flag_done = true; } for (int i = 0; i < g->enroute_num; ++i) { if (oi1 == d.oi_tbl_enroute[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ENROUTE_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->transport_num; ++i) { if (oi1 == d.oi_tbl_transport[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANSPORT_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (oi1 == d.oi_tbl_pl_stars[j][i]) { g->planet_focus_i[active_player] = i; ui_data.starmap.orbit_player = j; ui_data.ui_main_loop_action = (j == active_player) ? UI_MAIN_LOOP_ORBIT_OWN_SEL : UI_MAIN_LOOP_ORBIT_EN_SEL; ui_sound_play_sfx_24(); flag_done = true; j = g->players; i = g->galaxy_stars; } } } if (0 || ((oi1 == d.sm.oi_ship) && !ui_sm_ships_enabled) || (oi1 == oi_shippic) || ((oi1 == oi_wheelshippic) && (scrollmisc < 0)) ) { int n; ui_sound_play_sfx_24(); n = p->buildship + 1; if (n >= g->eto[active_player].shipdesigns_num) { if (n >= (NUM_SHIPDESIGNS + 1)) { n = 0; } else if (g->eto[active_player].have_stargates && !p->have_stargate) { n = BUILDSHIP_STARGATE; } else { n = 0; } } p->buildship = n; } if ((oi1 == oi_wheelshippic) && (scrollmisc > 0)) { int n; n = p->buildship - 1; if (n >= g->eto[active_player].shipdesigns_num) { n = g->eto[active_player].shipdesigns_num - 1; } else if (n < 0) { if (g->eto[active_player].have_stargates && !p->have_stargate) { n = BUILDSHIP_STARGATE; } else { n = g->eto[active_player].shipdesigns_num - 1; } } p->buildship = n; } for (planet_slider_i_t i = 0; i < PLANET_SLIDER_NUM; ++i) { if (oi1 == d.sm.oi_tbl_slider_lock[i]) { char buf[0x96]; if (kbd_is_modifier(MOO_MOD_CTRL)) { lib_strcpy(buf, game_str_adj_set, sizeof(buf)); lib_strcat(buf, game_str_adj_slider[i], sizeof(buf)); lib_strcat(buf, game_str_adj_lock, sizeof(buf)); if (ui_dialog_yesno(g, active_player, buf, 50, 30, 0)) { bool locked = p->slider_lock[i]; for (uint8_t pi = 0; pi < g->galaxy_stars; ++pi) { if (g->planet[pi].owner == active_player) { g->planet[pi].slider_lock[i] = !locked; } } } flag_done = true; } else if (kbd_is_modifier(MOO_MOD_ALT)) { lib_strcpy(buf, game_str_adj_set, sizeof(buf)); lib_strcat(buf, game_str_adj_slider[i], sizeof(buf)); lib_strcat(buf, game_str_adj_lock2, sizeof(buf)); lib_strcat(buf, game_str_adj_special[p->special], sizeof(buf)); lib_strcat(buf, game_str_adj_colonies, sizeof(buf)); if (ui_dialog_yesno(g, active_player, buf, 50, 30, 0)) { bool locked = p->slider_lock[i]; planet_special_t special = p->special; for (uint8_t pi = 0; pi < g->galaxy_stars; ++pi) { if ((g->planet[pi].owner == active_player) && g->planet[pi].special == special) { g->planet[pi].slider_lock[i] = !locked; } } } flag_done = true; } else { p->slider_lock[i] = !p->slider_lock[i]; ui_sound_play_sfx_24(); } } else if (!p->slider_lock[i]) { bool do_adj = false; int v; if (oi1 == d.sm.oi_tbl_slider_minus[i]) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_CTRL)) v = p->slider[i] - 1; else v = p->slider[i] - 4; SETMAX(v, 0); p->slider[i] = v; do_adj = true; } else if (oi1 == d.sm.oi_tbl_slider_plus[i]) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_ALT)) { game_planet_adjust_percent2(g, g->planet_focus_i[active_player], i, 100, true); } else { if (kbd_is_modifier(MOO_MOD_CTRL)) v = p->slider[i] + 1; else v = p->slider[i] + 4; SETMIN(v, 100); p->slider[i] = v; do_adj = true; } } if (do_adj) { game_adjust_slider_group(p->slider, i, p->slider[i], PLANET_SLIDER_NUM, p->slider_lock); } } } ui_starmap_handle_oi_ctrl(&d, oi1); if (oi1 == oi_f2) { int i; i = g->planet_focus_i[active_player]; do { if (--i < 0) { i = g->galaxy_stars - 1; } } while (g->planet[i].owner != active_player); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); } else if (oi1 == oi_f3) { int i; i = g->planet_focus_i[active_player]; do { i = (i + 1) % g->galaxy_stars; } while (g->planet[i].owner != active_player); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); } else if (oi1 == oi_equals || oi1 == oi_hash) { uint32_t old_reserve = p->reserve; if (ui_extra_enabled) { g->eto[active_player].reserve_bc += p->reserve; p->total_prod -= p->reserve; p->reserve = 0; game_update_production(g); } if (p->prod_after_maint < p->reserve) { ui_sound_play_sfx_06(); } else if (g->eto[active_player].reserve_bc == 0) { ui_sound_play_sfx_06(); } else { int v = p->prod_after_maint; if (v > g->eto[active_player].reserve_bc) { v = g->eto[active_player].reserve_bc; } v -= p->reserve; p->reserve = v; g->eto[active_player].reserve_bc -= v; p->total_prod += v; if (ui_extra_enabled) { if (old_reserve == p->reserve) { g->eto[active_player].reserve_bc += p->reserve; p->total_prod -= p->reserve; p->reserve = 0; } game_update_production(g); } ui_sound_play_sfx_24(); } } else if (oi1 == oi_f6) { int i; i = ui_starmap_newship_next(g, active_player, g->planet_focus_i[active_player]); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); if (BOOLVEC_IS1(g->eto[active_player].orbit[i].visible, active_player)) { ui_data.starmap.orbit_player = active_player; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ORBIT_OWN_SEL; flag_done = true; } } else if (oi1 == oi_f7) { int i; i = ui_starmap_newship_prev(g, active_player, g->planet_focus_i[active_player]); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); if (BOOLVEC_IS1(g->eto[active_player].orbit[i].visible, active_player)) { ui_data.starmap.orbit_player = active_player; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ORBIT_OWN_SEL; flag_done = true; } } else if (((oi1 == oi_f8) || (oi1 == oi_f9)) && g->eto[active_player].have_ia_scanner) { int i, pi; ui_sound_play_sfx_24(); pi = g->planet_focus_i[active_player]; i = ui_starmap_enemy_incoming(g, active_player, pi, (oi1 == oi_f8)); if (i != pi) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); } } else if (oi1 == oi_f4) { bool found; int i, pi; i = pi = g->planet_focus_i[active_player]; found = false; do { i = (i + 1) % g->galaxy_stars; for (int j = 0; j < g->eto[active_player].shipdesigns_num; ++j) { if (g->eto[active_player].orbit[i].ships[j]) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); ui_data.starmap.orbit_player = active_player; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ORBIT_OWN_SEL; flag_done = true; } } else if (oi1 == oi_f5) { bool found; int i, pi; i = pi = g->planet_focus_i[active_player]; found = false; do { if (--i < 0) { i = g->galaxy_stars - 1; } for (int j = 0; j < g->eto[active_player].shipdesigns_num; ++j) { if (g->eto[active_player].orbit[i].ships[j]) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); ui_data.starmap.orbit_player = active_player; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ORBIT_OWN_SEL; flag_done = true; } } else if (oi1 == oi_wheelname) { int i; i = g->planet_focus_i[active_player]; i += scrollmisc; if (i < 0) { i = g->galaxy_stars - 1; } else if (i >= g->galaxy_stars) { i = 0; } g->planet_focus_i[active_player] = i; } else if (oi1 == oi_rename) { const uint8_t ctbl[8] = { 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34, 0x34 }; char buf[PLANET_NAME_LEN]; lib_strcpy(buf, p->name, sizeof(buf)); lbxfont_select_set_12_4(4, 0xf, 0, 0); d.planet_draw_name = false; if (uiobj_read_str(239, 10, 65, buf, PLANET_NAME_LEN - 1, 0, false, ctbl)) { util_trim_whitespace(buf, sizeof(buf)); if (buf[0] != 0) { lib_strcpy(p->name, buf, PLANET_NAME_LEN); } } d.planet_draw_name = true; flag_done = true; } for (int i = 0; i < PLANET_SLIDER_NUM; ++i) { if (oi1 == oi_adj[i]) { char buf[0x96]; if (kbd_is_modifier(MOO_MOD_CTRL)) { int button; lib_strcpy(buf, game_str_nt_inc, sizeof(buf)); lib_strcat(buf, game_str_adj_slider[i], sizeof(buf)); lib_strcat(buf, game_str_adj_ratios, sizeof(buf)); button = ui_dialog_choose(g, active_player, buf, 50, 30, 0); if (button) { for (uint8_t pi = 0; pi < g->galaxy_stars; ++pi) { if (g->planet[pi].owner == active_player) { game_planet_adjust_percent2(g, pi, i, game_num_tbl_tech_autoadj[button], true); } } } flag_done = true; break; } else if (kbd_is_modifier(MOO_MOD_ALT)) { lib_strcpy(buf, game_str_adj_set, sizeof(buf)); lib_strcat(buf, game_str_adj_slider[i], sizeof(buf)); lib_strcat(buf, game_str_adj_max, sizeof(buf)); if (ui_dialog_yesno(g, active_player, buf, 50, 30, 0)) { for (uint8_t pi = 0; pi < g->galaxy_stars; ++pi) { if (g->planet[pi].owner == active_player) { game_planet_adjust_percent2(g, pi, i, 100, true); } } } flag_done = true; break; } } } for (int i = 0; i < g->galaxy_stars; ++i) { if ((oi1 == d.oi_tbl_stars[i]) && !g->evn.build_finished_num[active_player]) { g->planet_focus_i[active_player] = i; ui_sound_play_sfx_24(); break; } } p = &(g->planet[g->planet_focus_i[active_player]]); ui_starmap_common_update_mouse_hover(&d, oi2); if (!flag_done) { ui_starmap_draw_cb1(&d); uiobj_table_set_last(oi_alt_events); UIOBJ_CLEAR_LOCAL(); if (p->owner == active_player) { oi_equals = uiobj_add_mousearea(227, 70, 312, 78, MOO_KEY_EQUALS); oi_hash = uiobj_add_inputkey(MOO_KEY_HASH); } STARMAP_UIOBJ_FILL_FX(); if ((p->owner == active_player) && p->missile_bases) { oi_b = uiobj_add_mousearea(272, 59, 312, 67, MOO_KEY_b); } oi_c = uiobj_add_inputkey(MOO_KEY_c); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); if (g->evn.build_finished_num[active_player]) { oi_finished = uiobj_add_mousearea(6, 6, 225, 180, MOO_KEY_SPACE); } if ((p->owner == active_player) || (ui_extra_enabled && BOOLVEC_IS1(p->explored, active_player))) { oi_starview2 = uiobj_add_mousearea(227, 24, 310, 53, MOO_KEY_UNKNOWN); } if (p->owner == active_player) { oi_shippic = uiobj_add_mousearea(228, 139, 275, 175, MOO_KEY_UNKNOWN); oi_wheelshippic = uiobj_add_mousewheel(228, 139, 275, 175, &scrollmisc); oi_rename = uiobj_add_mousearea(227, 8, 310, 20, MOO_KEY_UNKNOWN); } oi_wheelname = uiobj_add_mousewheel(227, 8, 310, 20, &scrollmisc); if (ui_extra_enabled) { int y0 = 82; for (int i = 0; i < PLANET_SLIDER_NUM; ++i) { oi_adj[i] = uiobj_add_mousearea( 288, y0, 312, y0 + 6, MOO_KEY_UNKNOWN ); y0 += 11; } } ui_starmap_fill_oi_tbls(&d); if (!ui_sm_no_question_mark_cursor && BOOLVEC_IS1(p->explored, active_player)) { int x0, y0; x0 = (p->x - ui_data.starmap.x) * 2 + 6; y0 = (p->y - ui_data.starmap.y) * 2 + 6; oi_starview1 = uiobj_add_mousearea_limited(x0, y0, x0 + 16, y0 + 16, starmap_scale, MOO_KEY_UNKNOWN); } ui_starmap_fill_oi_tbl_stars(&d); if (ui_sm_no_question_mark_cursor && BOOLVEC_IS1(p->explored, active_player)) { oi_starview1 = d.oi_tbl_stars[g->planet_focus_i[active_player]]; } ui_starmap_fill_oi_slider(&d, p); oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); if (1) { int x0, y0, x1, y1; x0 = ((p->x - ui_data.starmap.x) * 2 + 6) * starmap_scale; y0 = ((p->y - ui_data.starmap.y) * 2 + 6) * starmap_scale; x1 = x0 + 16 * starmap_scale; y1 = y0 + 16 * starmap_scale; ui_cursor_area_tbl[7].x0 = x0; ui_cursor_area_tbl[7].x1 = x1; ui_cursor_area_tbl[7].y0 = y0; ui_cursor_area_tbl[7].y1 = y1; if (!ui_sm_no_question_mark_cursor && BOOLVEC_IS1(p->explored, active_player) && (x0 >= 7 * ui_scale) && (x1 <= 221 * ui_scale) && (y0 >= 7 * ui_scale) && (y1 <= 177 * ui_scale) ) { /* FIXME why were these here? these only seem to break stuff */ /* SETMAX(ui_cursor_area_tbl[5].x0, 7); SETMIN(ui_cursor_area_tbl[5].x1, 221); SETMAX(ui_cursor_area_tbl[5].y0, 7); SETMIN(ui_cursor_area_tbl[5].y1, 177); */ ui_cursor_setup_area(3, &ui_cursor_area_tbl[5]); } else { ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); } } if (g->evn.build_finished_num[active_player]) { ui_cursor_setup_area(2, &ui_cursor_area_tbl[0]); } ui_draw_finish(); if (g->difficulty < DIFFICULTY_AVERAGE) { ui_starmap_do_help(g, active_player); } game_rng_step(g); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_table_clear(); uiobj_unset_callback(); uiobj_set_help_id(-1); ui_delay_1(); } 1oom-1.11.2/src/ui/classic/uistarmap.h000066400000000000000000000016701476061725400174720ustar00rootroot00000000000000#ifndef INC_1OOM_UISTARMAP_H #define INC_1OOM_UISTARMAP_H #include "game_types.h" #include "game_planet.h" struct game_s; extern void ui_starmap_set_pos_focus(const struct game_s *g, player_id_t pi); extern void ui_starmap_set_pos(const struct game_s *g, int x, int y); extern bool ui_starmap_remove_build_finished(struct game_s *g, player_id_t api, planet_t *p); extern void ui_starmap_do(struct game_s *g, player_id_t pi); extern void ui_starmap_orbit_own(struct game_s *g, player_id_t pi); extern void ui_starmap_orbit_en(struct game_s *g, player_id_t pi); extern void ui_starmap_enroute(struct game_s *g, player_id_t pi); extern void ui_starmap_reloc(struct game_s *g, player_id_t pi); extern void ui_starmap_ships(struct game_s *g, player_id_t pi); extern void ui_starmap_trans(struct game_s *g, player_id_t pi); /* "trans" button pressed */ extern void ui_starmap_transport(struct game_s *g, player_id_t pi); /* transport selected */ #endif 1oom-1.11.2/src/ui/classic/uistarmap_common.c000066400000000000000000001361541476061725400210430ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap_common.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "game_tech.h" #include "kbd.h" #include "mouse.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "rnd.h" #include "types.h" #include "ui.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap.h" /* -------------------------------------------------------------------------- */ const uint8_t colortbl_textbox[5] = { 0x18, 0x17, 0x16, 0x15, 0x14 }; const uint8_t colortbl_line_red[5] = { 0x44, 0x43, 0x42, 0x41, 0x40 }; const uint8_t colortbl_line_reloc[5] = { 0x14, 0x15, 0x16, 0x17, 0x18 }; const uint8_t colortbl_line_green[5] = { 0xb0, 0xb1, 0xb2, 0xb3, 0xb4 }; static uint8_t ui_starmap_cursor_on_star(const struct starmap_data_s *d, int16_t oi) { if (oi == 0) { return PLANET_NONE; } for (int i = 0; i < d->g->galaxy_stars; ++i) { if (oi == d->oi_tbl_stars[i]) { return i; } } return PLANET_NONE; } /* -------------------------------------------------------------------------- */ static void ui_starmap_draw_planetinfo_do(const struct game_s *g, player_id_t api, uint8_t planet_i, bool explored, bool show_plus, bool draw_name) { const planet_t *p = &g->planet[planet_i]; if (explored || (ui_extra_enabled && g->gaux->flag_cheat_stars)) { if (draw_name) { lbxfont_select_set_12_4(4, 0xf, 0, 0); lbxfont_print_str_center(269, 10, p->name, UI_SCREEN_W, ui_scale); } /* stars in nebulas get a purple instead of a red frame */ if (ui_extra_enabled && p->battlebg==0) { ui_draw_box1(228, 25, 309, 52, 0xd3, 0xd3, ui_scale); } if (p->type == PLANET_TYPE_NOT_HABITABLE) { lbxfont_select(0, 0xe, 0, 0); lbxfont_print_str_center(269, 32, game_str_sm_nohabit, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(269, 41, game_str_sm__planets, UI_SCREEN_W, ui_scale); } else { const char *str = NULL; lbxgfx_draw_frame(229, 27, ui_data.gfx.planets.planet[p->infogfx], UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_str_right(305, 28, game_str_tbl_sm_pltype[p->type], UI_SCREEN_W, ui_scale); if (g->evn.have_plague && (g->evn.plague_planet_i == planet_i)) { str = game_str_sm_plague; } else if (g->evn.have_nova && (g->evn.nova_planet_i == planet_i)) { str = game_str_sm_nova; } else if (g->evn.have_comet && (g->evn.comet_planet_i == planet_i)) { str = game_str_sm_comet; } else if (g->evn.have_pirates && (g->evn.pirates_planet_i == planet_i)) { str = game_str_sm_pirates; } else if (p->unrest == PLANET_UNREST_REBELLION) { str = game_str_sm_rebellion; } else if (p->unrest == PLANET_UNREST_UNREST) { str = game_str_sm_unrest; } else if (g->evn.have_accident && (g->evn.accident_planet_i == planet_i)) { str = game_str_sm_accident; } if (str) { lbxfont_select(5, 5, 0, 0); lbxfont_print_str_right(305, 40, str, UI_SCREEN_W, ui_scale); } else { int x, xp, max_pop = p->max_pop3; lbxfont_select(0, 1, 0, 0); if (p->special == PLANET_SPECIAL_NORMAL) { str = game_str_tbl_sm_pgrowth[p->growth]; } else { str = game_str_tbl_sm_pspecial[p->special]; } lbxfont_print_str_right(305, 36, str, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xe, 0, 0); if (show_plus && ((p->owner == api) || (ui_extra_enabled && g->gaux->flag_cheat_stars)) && game_planet_can_terraform(g, p, p->owner, ui_extra_enabled)) { lbxfont_print_str_normal(289, 44, "+", UI_SCREEN_W, ui_scale); x = 287; xp = x - 22; } else { x = 291; xp = x - 23; } lbxfont_print_str_normal(xp, 45, game_str_sm_pop, UI_SCREEN_W, ui_scale); lbxfont_print_str_normal(295, 45, game_str_sm_max, UI_SCREEN_W, ui_scale); if ((!show_plus) || (g->eto[api].race != RACE_SILICOID)) { max_pop -= p->waste; } SETMAX(max_pop, 10); lbxfont_print_num_right(x, 45, max_pop, UI_SCREEN_W, ui_scale); } } } else { lbxfont_select(5, 0xe, 0, 0); lbxfont_print_str_center(269, show_plus ? 27 : 35, game_str_sm_unexplored, UI_SCREEN_W, ui_scale); } } static void ui_starmap_draw_range_parsec(struct starmap_data_s *d, int y) { const struct game_s *g = d->g; int dist = game_get_min_dist(g, d->api, g->planet_focus_i[d->api]); char buf[64]; lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_range, dist, (dist == 1) ? game_str_sm_parsec : game_str_sm_parsecs); lbxfont_select_set_12_4(0, 4, 0, 0); lbxfont_print_str_center(269, y, buf, UI_SCREEN_W, ui_scale); } static void ui_starmap_draw_sliders_and_prod(struct starmap_data_s *d) { const struct game_s *g = d->g; const planet_t *p = &g->planet[g->planet_focus_i[d->api]]; int x = 311; char buf[64]; for (planet_slider_i_t i = PLANET_SLIDER_SHIP; i < PLANET_SLIDER_NUM; ++i) { ui_draw_filled_rect(227, 81 + 11 * i, 244, 90 + 11 * i, p->slider_lock[i] ? 0x22 : 0, ui_scale); } lbxgfx_draw_frame(224, 5, ui_data.gfx.starmap.yourplnt, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0xe, 0); lib_sprintf(buf, sizeof(buf), "%i \x02(%i)\x01", p->prod_after_maint, p->total_prod); lbxfont_print_str_right(x, 72, buf, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0, 0); lbxfont_print_num_right(265, 61, p->pop, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x, 61, p->missile_bases, UI_SCREEN_W, ui_scale); for (planet_slider_i_t i = PLANET_SLIDER_SHIP; i < PLANET_SLIDER_NUM; ++i) { ui_draw_filled_rect(253, 84 + 11 * i, 278, 84 + 11 * i + 3, 0x2f, ui_scale); if (p->slider[i] != 0) { ui_draw_slider(253, 84 + 11 * i + 1, p->slider[i], 4, -1, p->slider_lock[i] ? 0x22 : 0x73, ui_scale); } } lbxfont_select(2, 0xa, 0, 0); if (p->buildship == BUILDSHIP_STARGATE) { ui_draw_filled_rect(229, 141, 274, 166, 0, ui_scale); lbxgfx_draw_frame(229, 141, ui_data.gfx.starmap.stargate, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(251, 169, game_str_sm_stargate, UI_SCREEN_W, ui_scale); } else { const shipdesign_t *sd = &g->srd[p->owner].design[p->buildship]; uint8_t *gfx = ui_data.gfx.ships[sd->look]; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(236, 142, gfx, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(252, 169, sd->name, UI_SCREEN_W, ui_scale); } lbxfont_select(2, 6, 0, 0); { int v; v = game_planet_get_slider_text(g, p, PLANET_SLIDER_SHIP, buf, sizeof(buf)); lbxfont_print_str_right(x, 83, buf, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); if (v >= 0) { lbxfont_print_num_right(271, 160, v, UI_SCREEN_W, ui_scale); } } lbxfont_select(2, 6, 0, 0); game_planet_get_slider_text(g, p, PLANET_SLIDER_DEF, buf, sizeof(buf)); lbxfont_print_str_right(x, 94, buf, UI_SCREEN_W, ui_scale); game_planet_get_slider_text(g, p, PLANET_SLIDER_IND, buf, sizeof(buf)); lbxfont_print_str_right(x, 105, buf, UI_SCREEN_W, ui_scale); { int v; v = game_planet_get_slider_text_eco(g, p, ui_extra_enabled, buf, sizeof(buf)); lbxfont_print_str_right(x, 116, buf, UI_SCREEN_W, ui_scale); if (v >= 0) { if (ui_extra_enabled) { if (v < 100) { lib_sprintf(buf, sizeof(buf), "%i.%i", v / 10, v % 10); /* "+0.X" does not fit the box */ } else { lib_sprintf(buf, sizeof(buf), "+%i", v / 10); } } else { lib_sprintf(buf, sizeof(buf), "+%i", v); } lbxfont_print_str_right(297, 116, buf, UI_SCREEN_W, ui_scale); } } { int v; v = game_planet_get_slider_text(g, p, PLANET_SLIDER_TECH, buf, sizeof(buf)); if (v > 9999) { ui_draw_filled_rect(288, 127, 312, 132, 7, ui_scale); } else { x -= 9; } lbxfont_print_str_right(x, 127, buf, UI_SCREEN_W, ui_scale); } } static void ui_starmap_draw_textbox_finished(const struct game_s *g, player_id_t api, int pi) { const planet_t *p = &g->planet[pi]; char *buf = ui_data.strbuf; planet_finished_t i; for (i = 0; i < FINISHED_NUM; ++i) { if (BOOLVEC_IS1(p->finished, i)) { break; } } game_planet_get_finished_text(g, p, i, buf, UI_STRBUF_SIZE); int y = ui_extra_enabled ? 45 : 54; ui_draw_textbox_2str("", buf, y, ui_scale); ui_draw_textbox_2str("", game_str_sm_planratio, 110, ui_scale); } static void ui_starmap_add_oi_enroute(struct starmap_data_s *d, bool want_prio) { const struct game_s *g = d->g; const int x = ui_data.starmap.x; const int y = ui_data.starmap.y; for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (BOOLVEC_IS1(r->visible, d->api) && (BOOLVEC_IS1(ui_data.starmap.select_prio_fleet, i) == want_prio)) { int x0 = (r->x - x) * 2 + 8; int y0 = (r->y - y) * 2 + 8; d->oi_tbl_enroute[i] = uiobj_add_mousearea_limited(x0, y0, x0 + 8, y0 + 4, starmap_scale, MOO_KEY_UNKNOWN); } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (BOOLVEC_IS1(r->visible, d->api) && (BOOLVEC_IS1(ui_data.starmap.select_prio_trans, i) == want_prio)) { int x0 = (r->x - x) * 2 + 8; int y0 = (r->y - y) * 2 + 8; d->oi_tbl_transport[i] = uiobj_add_mousearea_limited(x0, y0, x0 + 8, y0 + 4, starmap_scale, MOO_KEY_UNKNOWN); } } } static int ui_starmap_scrollkey_accel(int zh) { int v = zh; if (zh < 0) { v = -v; } v = 1 + (v / 4); if (v > 8) v = 8; v *= ui_sm_scroll_speed / 2 + 1; if (zh < 0) { v = -v; } return v; } /* -------------------------------------------------------------------------- */ void ui_starmap_draw_basic(struct starmap_data_s *d) { const struct game_s *g = d->g; const planet_t *p = &g->planet[g->planet_focus_i[d->api]]; ui_starmap_draw_starmap(d); ui_starmap_draw_button_text(d, true); ui_draw_filled_rect(224, 5, 314, 178, 0, ui_scale); if (BOOLVEC_IS0(p->explored, d->api) && !(ui_extra_enabled && g->gaux->flag_cheat_stars)) { lbxgfx_draw_frame(224, 5, ui_data.gfx.starmap.unexplor, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, 1, 0, 0); lbxfont_print_str_split(232, 74, 76, game_str_tbl_sm_stinfo[p->star_type], 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); ui_starmap_draw_range_parsec(d, 165); } else { player_id_t owner = p->owner; int pi = g->planet_focus_i[d->api]; if (BOOLVEC_IS0(p->within_srange, d->api) && !(ui_extra_enabled && g->gaux->flag_cheat_stars) && ((owner == PLAYER_NONE) || BOOLVEC_IS0(g->eto[d->api].contact, owner))) { owner = g->seen[d->api][pi].owner; } if (owner == PLAYER_NONE) { lbxgfx_draw_frame(224, 5, ui_data.gfx.starmap.no_colny, UI_SCREEN_W, ui_scale); ui_data.gfx.colonies.current = ui_data.gfx.colonies.d[p->type * 2]; lbxgfx_draw_frame(227, 73, ui_data.gfx.colonies.current, UI_SCREEN_W, ui_scale); ui_draw_box1(227, 73, 310, 174, 0, 0, ui_scale); ui_starmap_draw_range_parsec(d, 80); } else if (((owner != d->api) && !(ui_extra_enabled && g->gaux->flag_cheat_stars)) || (p->unrest == PLANET_UNREST_REBELLION)) { char buf[64]; int pop, bases, range_y; lbxgfx_draw_frame(224, 5, ui_data.gfx.starmap.en_colny, UI_SCREEN_W, ui_scale); ui_data.gfx.colonies.current = ui_data.gfx.colonies.d[p->type * 2 + 1]; lbxgfx_draw_frame(227, 73, ui_data.gfx.colonies.current, UI_SCREEN_W, ui_scale); ui_draw_box1(227, 73, 310, 174, 0, 0, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_race[g->eto[owner].race], game_str_sm_colony); if (BOOLVEC_IS1(p->within_srange, d->api)) { lbxfont_select_set_12_4(5, tbl_banner_fontparam[g->eto[owner].banner], 0, 0); lbxfont_print_str_center(270, 84, buf, UI_SCREEN_W, ui_scale); pop = p->pop; bases = p->missile_bases; range_y = 95; } else { lbxfont_select_set_12_4(0, tbl_banner_fontparam[g->eto[owner].banner], 0, 0); lbxfont_print_str_center(269, 75, game_str_sm_lastrep, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(268, 83, buf, UI_SCREEN_W, ui_scale); /* TODO combine with above */ pop = g->seen[d->api][pi].pop; bases = g->seen[d->api][pi].bases; range_y = 92; } lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(265, 61, pop, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(310, 61, bases, UI_SCREEN_W, ui_scale); ui_starmap_draw_range_parsec(d, range_y); } else { ui_starmap_draw_sliders_and_prod(d); lbxgfx_set_frame_0(ui_data.gfx.starmap.col_butt_ship); lbxgfx_set_frame_0(ui_data.gfx.starmap.col_butt_reloc); if (p->buildship == BUILDSHIP_STARGATE) { lbxgfx_set_frame(ui_data.gfx.starmap.col_butt_reloc, 1); } if ((g->evn.have_plague == 0) || (g->evn.plague_planet_i != g->planet_focus_i[d->api])) { lbxgfx_set_frame_0(ui_data.gfx.starmap.col_butt_trans); } else { lbxgfx_set_frame(ui_data.gfx.starmap.col_butt_trans, 1); } lbxgfx_draw_frame(282, 140, ui_data.gfx.starmap.col_butt_ship, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(282, 152, ui_data.gfx.starmap.col_butt_reloc, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(282, 164, ui_data.gfx.starmap.col_butt_trans, UI_SCREEN_W, ui_scale); } } ui_starmap_draw_planetinfo(g, d->api, g->planet_focus_i[d->api], d->planet_draw_name); if (g->evn.build_finished_num[d->api]) { ui_starmap_draw_textbox_finished(g, d->api, g->planet_focus_i[d->api]); } } void ui_starmap_draw_starmap(struct starmap_data_s *d) { const struct game_s *g = d->g; int x, y, tx, ty; char str[16]; STARMAP_LIM_INIT(); { int v, step; step = STARMAP_SCROLLSTEP; v = ui_data.starmap.x2; x = ui_data.starmap.x; if (v != x) { if (step == 0) { x = v; } else { if (v < x) { x -= STARMAP_SCROLLSTEP; SETMAX(x, v); } else { x += STARMAP_SCROLLSTEP; SETMIN(x, v); } } ui_data.starmap.x = x; } v = ui_data.starmap.y2; y = ui_data.starmap.y; if (v != y) { if (step == 0) { y = v; } else { if (v < y) { y -= STARMAP_SCROLLSTEP; SETMAX(y, v); } else { y += STARMAP_SCROLLSTEP; SETMIN(y, v); } } ui_data.starmap.y = y; } } if (++d->anim_delay >= STARMAP_ANIM_DELAY) { d->anim_delay = 0; } ui_draw_filled_rect(6, 6, 222 - 1, 178 - 1, 0, ui_scale); lbxgfx_draw_frame(0, 0, ui_data.gfx.starmap.mainview, UI_SCREEN_W, ui_scale); uiobj_set_limits(STARMAP_LIMITS); { uint8_t *gfx1, *gfx2; int x0, y0, x1, y1, lx, ly; x0 = (-x / 4) + 6; y0 = (-y / 4) + 6; x1 = ((-x + 1) / 2) + 6; y1 = ((-y + 1) / 2) + 6; gfx1 = ui_fixbugs_enabled ? ui_data.gfx.starmap.starbak2 : ui_data.gfx.starmap.starback; gfx2 = ui_fixbugs_enabled ? ui_data.gfx.starmap.starback : ui_data.gfx.starmap.starbak2; lx = 222 * ui_scale - 1; ly = 178 * ui_scale - 1; for (int yb = y0; yb < ly; yb += 200) { for (int xb = x0; xb < lx; xb += 320) { lbxgfx_draw_frame_offs(xb, yb, gfx1, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } } for (int yb = y1; yb < ly; yb += 200) { for (int xb = x1; xb < lx; xb += 320) { lbxgfx_draw_frame_offs(xb, yb, gfx2, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } } } for (int i = 0; i < g->nebula_num; ++i) { int tx, ty; tx = (g->nebula_x[i] - x) * 2 + 7; ty = (g->nebula_y[i] - y) * 2 + 7; lbxgfx_draw_frame_offs(tx, ty, ui_data.gfx.starmap.nebula[i], STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } if (ui_data.starmap.flag_show_grid) { int x0, y0, x1, y1; for (y0 = 10; y0 < g->galaxy_maxy; y0 += 50) { int ty; x0 = (-x) * 2 + 6; x1 = (g->galaxy_maxx - x) * 2 + 6; ty = (y0 - y) * 2 + 6; ui_draw_line_limit(x0, ty, x1, ty, 4, starmap_scale); } for (x0 = 10; x0 < g->galaxy_maxx; x0 += 50) { int tx; y0 = (-y) * 2 + 6; y1 = (g->galaxy_maxy - y) * 2 + 6; tx = (x0 - x) * 2 + 6; ui_draw_line_limit(tx, y0, tx, y1, 4, starmap_scale); } } for (int pi = 0; pi < g->galaxy_stars; ++pi) { const planet_t *p = &g->planet[pi]; if ((p->owner == d->api) && (p->reloc != pi)) { const planet_t *p2 = &g->planet[p->reloc]; int x0, y0, x1, y1; x0 = (p->x - x) * 2 + 14; x1 = (p2->x - x) * 2 + 14; y0 = (p->y - y) * 2 + 14; y1 = (p2->y - y) * 2 + 14; ui_draw_line_limit_ctbl(x0, y0, x1, y1, colortbl_line_reloc, 5, ui_data.starmap.line_anim_phase, starmap_scale); } } for (int pi = 0; pi < g->galaxy_stars; ++pi) { const planet_t *p = &g->planet[pi]; uint8_t *gfx = ui_data.gfx.starmap.stars[p->star_type + p->look]; uint8_t anim_frame = ui_data.star_frame[pi]; bool explored = BOOLVEC_IS1(p->explored, d->api); bool visible = BOOLVEC_IS1(p->within_srange, d->api); bool done = false; lbxgfx_set_new_frame(gfx, (anim_frame < 4) ? anim_frame : 0); gfx_aux_draw_frame_to(gfx, &ui_data.starmap.star_aux); if (p->look > 0) { tx = (p->x - x) * 2 + 8; ty = (p->y - y) * 2 + 9; } else { tx = (p->x - x) * 2 + 11; ty = (p->y - y) * 2 + 11; } gfx_aux_draw_frame_from_limit(tx, ty, &ui_data.starmap.star_aux, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); if (d->anim_delay == 0) { if (anim_frame == 4) { anim_frame = rnd_0_nm1(50, &ui_data.seed); } else { anim_frame = (anim_frame + 1) % 50; } ui_data.star_frame[pi] = anim_frame; } tx = (p->x - x) * 2 + 14; ty = (p->y - y) * 2 + 22; if (p->owner == PLAYER_NONE) { lbxfont_select(2, 7, 0, 0); } else if (visible || (pi == g->evn.planet_orion_i)) { lbxfont_select(2, tbl_banner_fontparam[g->eto[p->owner].banner], 0, 0); } else if (BOOLVEC_IS1(g->eto[d->api].contact, p->owner) || (p->within_frange[d->api] == 1)) { lbxfont_select(2, 0, 0, 0); lbxfont_set_color0(tbl_banner_color[g->eto[p->owner].banner]); } else { lbxfont_select(2, 7, 0, 0); } if (ui_extra_enabled && explored && ui_data.starmap.star_text_type != UI_SM_STAR_TEXT_NAME) { if (p->type == PLANET_TYPE_NOT_HABITABLE) { lbxfont_print_str_center_limit(tx, ty, "0/0", STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); done = true; } else if (visible && ui_data.starmap.star_text_type == UI_SM_STAR_TEXT_POPULATION) { int max_pop = p->max_pop3; if (g->eto[d->api].race != RACE_SILICOID) { max_pop -= p->waste; } if (game_planet_can_terraform(g, p, d->api, true)) { lib_sprintf(str, sizeof(str), "%i/%i+", p->pop, max_pop); } else { lib_sprintf(str, sizeof(str), "%i/%i", p->pop, max_pop); } lbxfont_print_str_center_limit(tx, ty, str, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); done = true; } else if (ui_data.starmap.star_text_type == UI_SM_STAR_TEXT_ENVIRONMENT) { lib_sprintf(str, sizeof(str), "%s", game_str_tbl_sm_pltype[p->type]); lbxfont_print_str_center_limit(tx, ty, str, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); done = true; } else if (ui_data.starmap.star_text_type == UI_SM_STAR_TEXT_SPECIAL) { if (p->special == PLANET_SPECIAL_NORMAL) { lib_sprintf(str, sizeof(str), "%s", "Normal"); } else { lib_sprintf(str, sizeof(str), "%s", game_str_tbl_sm_pspecial[p->special]); } lbxfont_print_str_center_limit(tx, ty, str, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); done = true; } } if (ui_data.starmap.star_text_type == UI_SM_STAR_TEXT_DISTANCE) { if (p->owner != d->api) { lib_sprintf(str, sizeof(str), "%d parsecs", game_get_min_dist(g, d->api, pi)); lbxfont_print_str_center_limit(tx, ty, str, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); done = true; } } if (!done) { bool do_print = visible || (pi == g->evn.planet_orion_i) || (BOOLVEC_IS1(g->eto[d->api].contact, p->owner)) || (p->within_frange[d->api] == 1); if (p->owner != PLAYER_NONE && do_print) { lbxfont_print_str_center_limit(tx, ty, p->name, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); } } } if (1 && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_RELOC) && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_TRANS) && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_ORBIT_OWN_SEL) && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_TRANSPORT_SEL) && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_ENROUTE_SEL) && (ui_data.ui_main_loop_action != UI_MAIN_LOOP_ORBIT_EN_SEL) ) { const planet_t *p = &g->planet[g->planet_focus_i[d->api]]; tx = (p->x - x) * 2 + 8; ty = (p->y - y) * 2 + 8; lbxgfx_draw_frame_offs_delay(tx, ty, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } if (d->anim_delay == 0) { if (--ui_data.starmap.line_anim_phase < 0) { ui_data.starmap.line_anim_phase = 4; } } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &g->enroute[i]; if (BOOLVEC_IS1(r->visible, d->api)) { uint8_t *gfx = ui_data.gfx.starmap.smalship[g->eto[r->owner].banner]; const planet_t *p = &g->planet[r->dest]; tx = (r->x - x) * 2 + 8; ty = (r->y - y) * 2 + 8; if (p->x < r->x) { lbxgfx_set_new_frame(gfx, 1); } else { lbxgfx_set_frame_0(gfx); } p = &g->planet[g->planet_focus_i[d->api]]; if (g->eto[d->api].have_ia_scanner && (p->owner == d->api) && (r->owner != d->api) && (r->dest == g->planet_focus_i[d->api])) { ui_draw_line_limit_ctbl(tx + 5, ty + 2, (p->x - x) * 2 + 14, (p->y - y) * 2 + 14, colortbl_line_red, 5, ui_data.starmap.line_anim_phase, starmap_scale); } if (ui_extra_enabled && ui_data.starmap.flag_show_own_routes && d->show_planet_focus) { if ((r->owner == d->api) && (r->dest == g->planet_focus_i[d->api])) { ui_draw_line_limit_ctbl(tx + 5, ty + 2, (p->x - x) * 2 + 14, (p->y - y) * 2 + 14, colortbl_line_green, 5, ui_data.starmap.line_anim_phase, starmap_scale); } } lbxgfx_draw_frame_offs(tx, ty, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } } for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &g->transport[i]; if (BOOLVEC_IS1(r->visible, d->api)) { uint8_t *gfx = ui_data.gfx.starmap.smaltran[g->eto[r->owner].banner]; const planet_t *p = &g->planet[r->dest]; tx = (r->x - x) * 2 + 8; ty = (r->y - y) * 2 + 8; if (p->x < r->x) { lbxgfx_set_new_frame(gfx, 1); } else { lbxgfx_set_frame_0(gfx); } p = &g->planet[g->planet_focus_i[d->api]]; if (g->eto[d->api].have_ia_scanner && (p->owner == d->api) && (r->owner != d->api) && (r->dest == g->planet_focus_i[d->api])) { ui_draw_line_limit_ctbl(tx + 5, ty + 2, (p->x - x) * 2 + 14, (p->y - y) * 2 + 14, colortbl_line_red, 5, ui_data.starmap.line_anim_phase, starmap_scale); } if (ui_extra_enabled && ui_data.starmap.flag_show_own_routes && d->show_planet_focus) { if ((r->owner == d->api) && (r->dest == g->planet_focus_i[d->api])) { ui_draw_line_limit_ctbl(tx + 5, ty + 2, (p->x - x) * 2 + 14, (p->y - y) * 2 + 14, colortbl_line_green, 5, ui_data.starmap.line_anim_phase, starmap_scale); } } lbxgfx_draw_frame_offs(tx, ty, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } } if (g->evn.crystal.exists && (g->evn.crystal.killer == PLAYER_NONE)) { tx = (g->evn.crystal.x - x) * 2 + 8; ty = (g->evn.crystal.y - y) * 2 + 8; lbxgfx_draw_frame_offs(tx, ty, ui_data.gfx.planets.smonster, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); lbxfont_select(2, 8, 0, 0); lbxfont_print_str_center_limit(tx + 2, ty + 5, game_str_sm_crystal, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); } if ((g->evn.amoeba.exists != 0) && (g->evn.amoeba.killer == PLAYER_NONE)) { tx = (g->evn.amoeba.x - x) * 2 + 8; ty = (g->evn.amoeba.y - y) * 2 + 8; lbxgfx_draw_frame_offs(tx, ty, ui_data.gfx.planets.smonster, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); lbxfont_select(2, 8, 0, 0); lbxfont_print_str_center_limit(tx + 2, ty + 5, game_str_sm_amoeba, STARMAP_TEXT_LIMITS, UI_SCREEN_W, starmap_scale); } for (int pi = 0; pi < g->galaxy_stars; ++pi) { const planet_t *p = &g->planet[pi]; if (BOOLVEC_IS1(p->within_srange, d->api) || BOOLVEC_IS1(g->eto[d->api].orbit[pi].visible, d->api)) { player_id_t tblorbit[PLAYER_NUM]; player_id_t num; num = 0; for (player_id_t i = PLAYER_0; i < g->players; ++i) { const empiretechorbit_t *e = &g->eto[i]; if (BOOLVEC_IS0(p->within_srange, d->api) && (i != d->api)) { continue; } for (int j = 0; j < e->shipdesigns_num; ++j) { if (e->orbit[pi].ships[j]) { tblorbit[num++] = i; break; } } } tx = (p->x - x) * 2 + 25; if (p->have_stargate) { lbxgfx_draw_frame_offs(tx, (p->y - y) * 2 + 7, ui_data.gfx.starmap.stargate2, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } ++tx; for (player_id_t i = PLAYER_0; i < num; ++i) { player_id_t i2 = tblorbit[i]; uint8_t *gfx = ui_data.gfx.starmap.smalship[g->eto[i2].banner]; lbxgfx_set_frame_0(gfx); ty = (p->y - y) * 2 + i * 6 + 8; lbxgfx_draw_frame_offs(tx, ty, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } } } } void ui_starmap_draw_button_text(struct starmap_data_s *d, bool highlight) { lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 0)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(10, 184, game_str_sm_game, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 1)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(44, 184, game_str_sm_design, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 2)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(83, 184, game_str_sm_fleet, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 3)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(119, 184, game_str_sm_map, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 4)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(147, 184, game_str_sm_races, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 5)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(184, 184, game_str_sm_planets, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 6)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(230, 184, game_str_sm_tech, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(5, (highlight && (d->bottom_highlight == 7)) ? 0 : 2, 0, 0); lbxfont_print_str_normal(263, 184, game_str_sm_next_turn, UI_SCREEN_W, ui_scale); } static void ui_starmap_clamp_xy(const struct game_s *g, int *x, int *y) { if (!ui_sm_expanded_scroll) { SETRANGE(*x, 0, g->galaxy_maxx - ((108 * ui_scale) / starmap_scale)); SETRANGE(*y, 0, g->galaxy_maxy - ((86 * ui_scale) / starmap_scale)); } else { SETRANGE(*x, -((54 * ui_scale) / starmap_scale), g->galaxy_maxx - ((54 * ui_scale) / starmap_scale)); SETRANGE(*y, -((43 * ui_scale) / starmap_scale), g->galaxy_maxy - ((43 * ui_scale) / starmap_scale)); } } void ui_starmap_set_pos_focus(const struct game_s *g, player_id_t active_player) { const planet_t *p = &g->planet[g->planet_focus_i[active_player]]; ui_starmap_set_pos(g, p->x, p->y); } void ui_starmap_set_pos(const struct game_s *g, int x, int y) { x -= (54 * ui_scale) / starmap_scale; y -= (43 * ui_scale) / starmap_scale; ui_starmap_clamp_xy(g, &x, &y); ui_data.starmap.x = x; ui_data.starmap.x2 = x; ui_data.starmap.y = y; ui_data.starmap.y2 = y; } static void ui_starmap_select_target(struct starmap_data_s *d, uint8_t planet_i) { if (!d->controllable || (planet_i == PLANET_NONE)) { return; } d->g->planet_focus_i[d->api] = planet_i; if (ui_data.ui_main_loop_action == UI_MAIN_LOOP_TRANS) { d->tr.other = true; } } void ui_starmap_handle_oi_ctrl(struct starmap_data_s *d, int16_t oi) { #define XSTEP 0x1b #define YSTEP 0x15 const struct game_s *g = d->g; bool changed = false; int x, y; if (g->evn.build_finished_num[d->api]) { return; } x = ui_data.starmap.x; y = ui_data.starmap.y; if (oi == d->oi_scroll) { if (d->scrollx >= 0) { x += d->scrollx - 54; y += d->scrolly - 43; changed = true; } else { starmap_scale = d->scrollz; d->set_pos_focus(g, g->active_player); } } else if (oi == d->oi_ctrl_ul) { x -= XSTEP; y -= YSTEP; changed = true; } else if ((oi == d->oi_ctrl_up) || (oi == d->oi_ctrl_u2)) { y -= YSTEP; changed = true; } else if (oi == d->oi_ctrl_ur) { x += XSTEP; y -= YSTEP; changed = true; } else if ((oi == d->oi_ctrl_left) || (oi == d->oi_ctrl_l2)) { x -= XSTEP; changed = true; } else if ((oi == d->oi_ctrl_right) || (oi == d->oi_ctrl_r2)) { x += XSTEP; changed = true; } else if (oi == d->oi_ctrl_dl) { x -= XSTEP; y += YSTEP; changed = true; } else if ((oi == d->oi_ctrl_down) || (oi == d->oi_ctrl_d2)) { y += YSTEP; changed = true; } else if (oi == d->oi_ctrl_dr) { x += XSTEP; y += YSTEP; changed = true; } else if (oi == d->oi_pgdown) { --d->scrollz; SETMAX(d->scrollz, 1); starmap_scale = d->scrollz; ui_starmap_set_pos_focus(g, g->active_player); } else if (oi == d->oi_pgup) { ++d->scrollz; SETMIN(d->scrollz, ui_scale); starmap_scale = d->scrollz; ui_starmap_set_pos_focus(g, g->active_player); } if (changed) { ui_starmap_clamp_xy(g, &x, &y); ui_data.starmap.x2 = x; ui_data.starmap.y2 = y; } #undef XSTEP #undef YSTEP } void ui_starmap_handle_scrollkeys(struct starmap_data_s *d, int16_t oi) { const struct game_s *g = d->g; int x, y, xh, yh; if (oi != 0) { ui_data.starmap.xhold = 0; ui_data.starmap.yhold = 0; return; } if (g->evn.build_finished_num[d->api]) { return; } x = ui_data.starmap.x; y = ui_data.starmap.y; xh = ui_data.starmap.xhold; yh = ui_data.starmap.yhold; if (0 || (ui_sm_uhjk_scroll && kbd_is_pressed(MOO_KEY_u, 0, MOO_MOD_SHIFT | MOO_MOD_ALT | MOO_MOD_CTRL)) || (ui_sm_mouse_scroll && (moouse_y <= 0))) { if (yh > 0) { yh = 0; } --yh; } else if (0 || (ui_sm_uhjk_scroll && kbd_is_pressed(MOO_KEY_j, 0, MOO_MOD_SHIFT | MOO_MOD_ALT | MOO_MOD_CTRL)) || (ui_sm_mouse_scroll && (moouse_y >= UI_SCREEN_H - 1))) { if (yh < 0) { yh = 0; } ++yh; } else { yh = 0; } if (yh) { y += ui_starmap_scrollkey_accel(yh); } if (0 || (ui_sm_uhjk_scroll && kbd_is_pressed(MOO_KEY_h, 0, MOO_MOD_SHIFT | MOO_MOD_ALT | MOO_MOD_CTRL)) || (ui_sm_mouse_scroll && (moouse_x <= 0))) { if (xh > 0) { xh = 0; } --xh; } else if (0 || (ui_sm_uhjk_scroll && kbd_is_pressed(MOO_KEY_k, 0, MOO_MOD_SHIFT | MOO_MOD_ALT | MOO_MOD_CTRL)) || (ui_sm_mouse_scroll && (moouse_x >= UI_SCREEN_W - 1))) { if (xh < 0) { xh = 0; } ++xh; } else { xh = 0; } if (xh) { x += ui_starmap_scrollkey_accel(xh); } if (xh || yh) { ui_starmap_clamp_xy(g, &x, &y); ui_data.starmap.x2 = x; ui_data.starmap.y2 = y; ui_data.starmap.x = x; ui_data.starmap.y = y; } ui_data.starmap.xhold = xh; ui_data.starmap.yhold = yh; } void ui_starmap_add_oi_bottom_buttons(struct starmap_data_s *d) { d->oi_gameopts = uiobj_add_mousearea(5, 181, 36, 194, MOO_KEY_g); d->oi_design = uiobj_add_mousearea(40, 181, 75, 194, MOO_KEY_d); d->oi_fleet = uiobj_add_mousearea(79, 181, 111, 194, MOO_KEY_f); d->oi_map = uiobj_add_mousearea(115, 181, 139, 194, MOO_KEY_m); d->oi_races = uiobj_add_mousearea(143, 181, 176, 194, (ui_illogical_hotkey_fix ? MOO_KEY_a : MOO_KEY_r)); d->oi_planets = uiobj_add_mousearea(180, 181, 221, 194, MOO_KEY_p); d->oi_tech = uiobj_add_mousearea(225, 181, 254, 194, MOO_KEY_t); d->oi_next_turn = uiobj_add_mousearea(258, 181, 314, 194, MOO_KEY_n); } bool ui_starmap_handle_oi_bottom_buttons(struct starmap_data_s *d, int16_t oi) { ui_main_loop_action_t action = UI_MAIN_LOOP_NUM; if (oi == d->oi_gameopts) { action = UI_MAIN_LOOP_GAMEOPTS; } else if (oi == d->oi_design) { action = UI_MAIN_LOOP_DESIGN; } else if (oi == d->oi_fleet) { action = UI_MAIN_LOOP_FLEET; } else if (oi == d->oi_map) { action = UI_MAIN_LOOP_MAP; } else if (oi == d->oi_races) { action = UI_MAIN_LOOP_RACES; } else if (oi == d->oi_planets) { action = UI_MAIN_LOOP_PLANETS; } else if (oi == d->oi_tech) { action = UI_MAIN_LOOP_TECH; } else if (oi == d->oi_next_turn) { action = UI_MAIN_LOOP_NEXT_TURN; } if (action != UI_MAIN_LOOP_NUM) { ui_data.ui_main_loop_action = action; return true; } return false; } void ui_starmap_add_oi_misc(struct starmap_data_s *d) { d->oi_alt_c = uiobj_add_inputkey(MOO_KEY_c | MOO_MOD_ALT); d->oi_alt_m = uiobj_add_inputkey(MOO_KEY_m | MOO_MOD_ALT); if (d->show_planet_focus) { d->oi_alt_r = uiobj_add_inputkey(MOO_KEY_r | MOO_MOD_ALT); d->oi_ctrl_r = uiobj_add_inputkey(MOO_KEY_r | MOO_MOD_CTRL); } if (ui_extra_enabled) { d->oi_alt_f = uiobj_add_inputkey(MOO_KEY_f | MOO_MOD_ALT); d->oi_alt_o = uiobj_add_inputkey(MOO_KEY_o | MOO_MOD_ALT); } } bool ui_starmap_handle_oi_misc(struct starmap_data_s *d, int16_t oi) { bool match = false; struct game_s *g = d->g; uint8_t planet_focus_i = g->planet_focus_i[d->api]; if (oi == d->oi_alt_m) { ui_data.starmap.flag_show_grid = !ui_data.starmap.flag_show_grid; match = true; } else if (oi == d->oi_alt_c) { d->set_pos_focus(d->g, d->api); match = true; } else if (oi == d->oi_alt_f) { ui_data.starmap.flag_show_own_routes = !ui_data.starmap.flag_show_own_routes; match = true; } else if (oi == d->oi_alt_o) { ui_data.starmap.star_text_type = (ui_data.starmap.star_text_type + 1) % UI_SM_STAR_TEXT_NUM; match = true; } else if ((oi == d->oi_alt_r) && game_reloc_dest_ok(g, planet_focus_i, d->api)) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if ((p->owner == d->api) && (p->reloc != i)) { p->reloc = planet_focus_i; } } match = true; } else if ((oi == d->oi_ctrl_r) && game_reloc_dest_ok(g, planet_focus_i, d->api)) { int count = 0; for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if ((p->owner == d->api) && (p->reloc != planet_focus_i)) { p->reloc = planet_focus_i; ++count; } } if (count == 0) { for (int i = 0; i < g->galaxy_stars; ++i) { planet_t *p = &(g->planet[i]); if (p->owner == d->api) { p->reloc = i; } } } match = true; } return match; } void ui_starmap_fill_oi_tbls(struct starmap_data_s *d) { const struct game_s *g = d->g; const int x = ui_data.starmap.x; const int y = ui_data.starmap.y; STARMAP_LIM_INIT(); uiobj_set_limits(STARMAP_LIMITS); UIOBJI_SET_TBL_INVALID(d->oi_tbl_enroute); UIOBJI_SET_TBL_INVALID(d->oi_tbl_transport); ui_starmap_add_oi_enroute(d, false); for (int i = 0; i < g->galaxy_stars; ++i) { for (int j = 0; j < g->players; ++j) { d->oi_tbl_pl_stars[j][i] = UIOBJI_INVALID; } } for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (BOOLVEC_IS1(p->within_srange, d->api) || BOOLVEC_IS1(g->eto[d->api].orbit[i].visible, d->api)) { int numorbits, x0, y0; player_id_t tblpl[PLAYER_NUM]; numorbits = 0; for (int j = 0; j < g->players; ++j) { const fleet_orbit_t *r = &(g->eto[j].orbit[i]); if (BOOLVEC_IS0(p->within_srange, d->api) && (j != d->api)) { continue; } for (int k = 0; k < g->eto[j].shipdesigns_num; ++k) { if (r->ships[k]) { tblpl[numorbits++] = j; break; } } } x0 = (p->x - x) * 2 + 26; y0 = (p->y - y) * 2 + 8; for (int j = 0; j < numorbits; ++j, y0 += 6) { d->oi_tbl_pl_stars[tblpl[j]][i] = uiobj_add_mousearea_limited(x0, y0, x0 + 8, y0 + 4, starmap_scale, MOO_KEY_UNKNOWN); } } } ui_starmap_add_oi_enroute(d, true); } void ui_starmap_fill_oi_tbl_stars(struct starmap_data_s *d) { const struct game_s *g = d->g; const int x = ui_data.starmap.x; const int y = ui_data.starmap.y; STARMAP_LIM_INIT(); uiobj_set_limits(STARMAP_LIMITS); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); int x0, y0; x0 = (p->x - x) * 2 + 8; y0 = (p->y - y) * 2 + 8; d->oi_tbl_stars[i] = uiobj_add_mousearea_limited(x0, y0, x0 + 13, y0 + 13, starmap_scale, MOO_KEY_UNKNOWN); } } void ui_starmap_fill_oi_tbl_stars_own(struct starmap_data_s *d, player_id_t owner) { const struct game_s *g = d->g; const int x = ui_data.starmap.x; const int y = ui_data.starmap.y; STARMAP_LIM_INIT(); uiobj_set_limits(STARMAP_LIMITS); for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == owner) { int x0, y0; x0 = (p->x - x) * 2 + 8; y0 = (p->y - y) * 2 + 8; d->oi_tbl_stars[i] = uiobj_add_mousearea_limited(x0, y0, x0 + 13, y0 + 13, starmap_scale, MOO_KEY_UNKNOWN); } } } void ui_starmap_clear_oi_ctrl(struct starmap_data_s *d) { d->oi_scroll = UIOBJI_INVALID; d->oi_ctrl_left = UIOBJI_INVALID; d->oi_ctrl_l2 = UIOBJI_INVALID; d->oi_ctrl_right = UIOBJI_INVALID; d->oi_ctrl_r2 = UIOBJI_INVALID; d->oi_ctrl_ul = UIOBJI_INVALID; d->oi_ctrl_ur = UIOBJI_INVALID; d->oi_ctrl_up = UIOBJI_INVALID; d->oi_ctrl_u2 = UIOBJI_INVALID; d->oi_ctrl_dl = UIOBJI_INVALID; d->oi_ctrl_down = UIOBJI_INVALID; d->oi_ctrl_d2 = UIOBJI_INVALID; d->oi_ctrl_dr = UIOBJI_INVALID; d->oi_pgup = UIOBJI_INVALID; d->oi_pgdown = UIOBJI_INVALID; } void ui_starmap_fill_oi_ctrl(struct starmap_data_s *d) { d->oi_scroll = uiobj_add_tb(6, 6, 2, 2, 108, 86, &d->scrollx, &d->scrolly, &d->scrollz, ui_scale); d->oi_ctrl_left = uiobj_add_inputkey(MOO_KEY_LEFT | MOO_MOD_CTRL); if (MOO_KEY_LEFT != MOO_KEY_KP4) { d->oi_ctrl_l2 = uiobj_add_inputkey(MOO_KEY_KP4 | MOO_MOD_CTRL); } d->oi_ctrl_right = uiobj_add_inputkey(MOO_KEY_RIGHT | MOO_MOD_CTRL); if (MOO_KEY_RIGHT != MOO_KEY_KP6) { d->oi_ctrl_r2 = uiobj_add_inputkey(MOO_KEY_KP6 | MOO_MOD_CTRL); } d->oi_ctrl_ul = uiobj_add_inputkey(MOO_KEY_KP7 | MOO_MOD_CTRL); d->oi_ctrl_ur = uiobj_add_inputkey(MOO_KEY_KP9 | MOO_MOD_CTRL); d->oi_ctrl_up = uiobj_add_inputkey(MOO_KEY_UP | MOO_MOD_CTRL); if (MOO_KEY_UP != MOO_KEY_KP8) { d->oi_ctrl_u2 = uiobj_add_inputkey(MOO_KEY_KP8 | MOO_MOD_CTRL); } d->oi_ctrl_dl = uiobj_add_inputkey(MOO_KEY_KP1 | MOO_MOD_CTRL); d->oi_ctrl_down = uiobj_add_inputkey(MOO_KEY_DOWN | MOO_MOD_CTRL); if (MOO_KEY_DOWN != MOO_KEY_KP2) { d->oi_ctrl_d2 = uiobj_add_inputkey(MOO_KEY_KP2 | MOO_MOD_CTRL); } d->oi_ctrl_dr = uiobj_add_inputkey(MOO_KEY_KP3 | MOO_MOD_CTRL); d->oi_pgup = uiobj_add_inputkey(MOO_KEY_PAGEUP); d->oi_pgdown = uiobj_add_inputkey(MOO_KEY_PAGEDOWN); } void ui_starmap_sn0_setup(struct shipnon0_s *sn0, int sd_num, const shipcount_t *ships) { int num = 0; for (int i = 0; i < sd_num; ++i) { shipcount_t n; n = ships[i]; sn0->ships[num] = n; if (n) { sn0->type[num++] = i; } } sn0->num = num; } void ui_starmap_update_reserve_fuel(struct game_s *g, struct shipnon0_s *sn0, const shipcount_t *ships, player_id_t pi) { const bool *hrf = &(g->srd[pi].have_reserve_fuel[0]); for (int i = 0; i < sn0->num; ++i) { int st; st = sn0->type[i]; if ((!hrf[st]) && (ships[st] != 0)) { sn0->have_reserve_fuel = false; return; } } sn0->have_reserve_fuel = true; } void ui_starmap_draw_planetinfo(const struct game_s *g, player_id_t api, int planet_i, bool draw_name) { const planet_t *p = &(g->planet[planet_i]); ui_starmap_draw_planetinfo_do(g, api, planet_i, BOOLVEC_IS1(p->explored, api), true, draw_name); } void ui_starmap_draw_planetinfo_2(const struct game_s *g, int p1, int p2, int planet_i) { const planet_t *p = &(g->planet[planet_i]); player_id_t api = (p1 < PLAYER_NUM) ? p1 : p2; bool explored = true; if (0 || (IS_HUMAN(g, p1) && BOOLVEC_IS0(p->explored, p1)) || (IS_HUMAN(g, p2) && BOOLVEC_IS0(p->explored, p2)) ) { explored = false; } ui_starmap_draw_planetinfo_do(g, api, planet_i, explored, false, true); } int ui_starmap_newship_next(const struct game_s *g, player_id_t pi, int i) { int t = i; const planet_t *p; do { i = (i + 1) % g->galaxy_stars; p = &(g->planet[i]); } while ((!((p->owner == pi) && BOOLVEC_IS1(p->finished, FINISHED_SHIP))) && (i != t)); return i; } int ui_starmap_newship_prev(const struct game_s *g, player_id_t pi, int i) { int t = i; const planet_t *p; do { if (--i < 0) { i = g->galaxy_stars - 1; } p = &(g->planet[i]); } while ((!((p->owner == pi) && BOOLVEC_IS1(p->finished, FINISHED_SHIP))) && (i != t)); return i; } int ui_starmap_enemy_incoming(const struct game_s *g, player_id_t pi, int i, bool next) { int t = i; do { if (next) { i = (i + 1) % g->galaxy_stars; } else { if (--i < 0) { i = g->galaxy_stars - 1; } } if (g->planet[i].owner == pi) { for (int j = 0; j < g->enroute_num; ++j) { const fleet_enroute_t *r = &(g->enroute[j]); if (BOOLVEC_IS1(r->visible, pi) && (r->owner != pi) && (r->dest == i)) { return i; } } for (int j = 0; j < g->transport_num; ++j) { const transport_t *r = &(g->transport[j]); if (BOOLVEC_IS1(r->visible, pi) && (r->owner != pi) && (r->dest == i)) { return i; } } } } while (i != t); return i; } void ui_starmap_common_init(struct game_s *g, struct starmap_data_s *d, player_id_t active_player) { d->set_pos_focus = ui_starmap_set_pos_focus; d->g = g; d->api = active_player; d->controllable = false; d->show_planet_focus = true; d->anim_delay = 0; d->planet_draw_name = true; d->scrollx = 0; d->scrolly = 0; d->scrollz = starmap_scale; } void ui_starmap_common_update_mouse_hover(struct starmap_data_s *d, int16_t oi) { d->bottom_highlight = -1; if (oi == d->oi_gameopts) { d->bottom_highlight = 0; } else if (oi == d->oi_design) { d->bottom_highlight = 1; } else if (oi == d->oi_fleet) { d->bottom_highlight = 2; } else if (oi == d->oi_map) { d->bottom_highlight = 3; } else if (oi == d->oi_races) { d->bottom_highlight = 4; } else if (oi == d->oi_planets) { d->bottom_highlight = 5; } else if (oi == d->oi_tech) { d->bottom_highlight = 6; } else if (oi == d->oi_next_turn) { d->bottom_highlight = 7; } if (ui_sm_mouseover_focus && d->controllable) { ui_starmap_select_target(d, ui_starmap_cursor_on_star(d, oi)); } } 1oom-1.11.2/src/ui/classic/uistarmap_common.h000066400000000000000000000161731476061725400210460ustar00rootroot00000000000000#ifndef INC_1OOM_UISTARMAP_COMMON_H #define INC_1OOM_UISTARMAP_COMMON_H #include "game.h" #include "types.h" #include "uidraw.h" #include "uiobj.h" #define STARMAP_DELAY (ui_sm_smoother_scrolling ? 1 : 3) #define STARMAP_ANIM_DELAY (ui_sm_smoother_scrolling ? 3 : 1) #define STARMAP_SCROLLSTEP (ui_sm_smoother_scrolling ? ui_sm_scroll_speed : 10) #define STARMAP_LIM_INIT() const int slx0 = (6 * ui_scale) / starmap_scale, sly0 = (6 * ui_scale) / starmap_scale, slx1 = (222 * ui_scale) / starmap_scale - 1, sly1 = (178 * ui_scale) / starmap_scale - 1 #define STARMAP_TEXT_LIMITS 6 * ui_scale, 6 * ui_scale, 222 * ui_scale - 1, 178 * ui_scale - 1 #define STARMAP_LIMITS slx0, sly0, slx1, sly1 struct shipnon0_s { shipcount_t ships[NUM_SHIPDESIGNS]; uint8_t type[NUM_SHIPDESIGNS]; uint8_t num; /* number of ship types on orbit with nonzero amount */ bool have_reserve_fuel; }; struct starmap_data_s { void (*set_pos_focus) (const struct game_s *, player_id_t); struct game_s *g; /* FIXME non-const only for ui_starmap_draw_cb1 */ player_id_t api; bool controllable; bool show_planet_focus; int bottom_highlight; int anim_delay; int16_t scrollx; int16_t scrolly; uint8_t scrollz; int16_t oi_gameopts; int16_t oi_design; int16_t oi_fleet; int16_t oi_map; int16_t oi_races; int16_t oi_planets; int16_t oi_tech; int16_t oi_next_turn; int16_t oi_alt_c; int16_t oi_alt_f; int16_t oi_alt_m; int16_t oi_alt_r; int16_t oi_ctrl_r; int16_t oi_alt_o; int16_t oi_tbl_stars[PLANETS_MAX]; int16_t oi_scroll; int16_t oi_ctrl_left; int16_t oi_ctrl_l2; int16_t oi_ctrl_right; int16_t oi_ctrl_r2; int16_t oi_ctrl_ul; int16_t oi_ctrl_ur; int16_t oi_ctrl_up; int16_t oi_ctrl_u2; int16_t oi_ctrl_dl; int16_t oi_ctrl_down; int16_t oi_ctrl_d2; int16_t oi_ctrl_dr; int16_t oi_pgup; int16_t oi_pgdown; int16_t oi_tbl_enroute[FLEET_ENROUTE_MAX]; int16_t oi_tbl_transport[TRANSPORT_MAX]; int16_t oi_tbl_pl_stars[PLAYER_NUM][PLANETS_MAX]; uint8_t from; bool planet_draw_name; union { struct { int16_t oi_ship; int16_t oi_reloc; int16_t oi_trans; int16_t oi_tbl_slider_lock[PLANET_SLIDER_NUM]; int16_t oi_tbl_slider_minus[PLANET_SLIDER_NUM]; int16_t oi_tbl_slider_plus[PLANET_SLIDER_NUM]; } sm; /* starmap_do */ struct { int16_t num; bool other; bool blink; } tr; /* trans */ struct { bool in_frange; } ts; /* transport */ struct { shipcount_t ships[NUM_SHIPDESIGNS]; uint8_t shiptypenon0numsel; /* number of ship types selected with nonzero amount */ struct shipnon0_s sn0; } oo; /* orbit_own */ struct { shipcount_t ships[NUM_SHIPDESIGNS]; struct shipnon0_s sn0; player_id_t player; int yoff; } oe; /* orbit_en */ struct { struct shipnon0_s sn0; uint8_t pon; } en; /* enroute */ }; }; #define STARMAP_UIOBJ_CLEAR_COMMON() \ do { \ d.oi_gameopts = UIOBJI_INVALID; \ d.oi_design = UIOBJI_INVALID; \ d.oi_fleet = UIOBJI_INVALID; \ d.oi_map = UIOBJI_INVALID; \ d.oi_races = UIOBJI_INVALID; \ d.oi_planets = UIOBJI_INVALID; \ d.oi_tech = UIOBJI_INVALID; \ d.oi_next_turn = UIOBJI_INVALID; \ d.oi_alt_c = UIOBJI_INVALID; \ d.oi_alt_f = UIOBJI_INVALID; \ d.oi_alt_m = UIOBJI_INVALID; \ d.oi_alt_o = UIOBJI_INVALID; \ d.oi_alt_r = UIOBJI_INVALID; \ d.oi_ctrl_r = UIOBJI_INVALID; \ for (int i = 0; i < g->galaxy_stars; ++i) { \ d.oi_tbl_stars[i] = UIOBJI_INVALID; \ } \ UIOBJI_SET_TBL_INVALID(d.oi_tbl_enroute); \ UIOBJI_SET_TBL_INVALID(d.oi_tbl_transport); \ for (int i = 0; i < g->galaxy_stars; ++i) { \ for (int j = 0; j < g->players; ++j) { \ d.oi_tbl_pl_stars[j][i] = UIOBJI_INVALID; \ } \ } \ oi_search = UIOBJI_INVALID; \ ui_starmap_clear_oi_ctrl(&d); \ } while (0) #define STARMAP_UIOBJ_FILL_FX() \ do { \ oi_f2 = uiobj_add_inputkey(MOO_KEY_F2); \ oi_f3 = uiobj_add_inputkey(MOO_KEY_F3); \ oi_f4 = uiobj_add_inputkey(MOO_KEY_F4); \ oi_f5 = uiobj_add_inputkey(MOO_KEY_F5); \ oi_f6 = uiobj_add_inputkey(MOO_KEY_F6); \ oi_f7 = uiobj_add_inputkey(MOO_KEY_F7); \ oi_f8 = uiobj_add_inputkey(MOO_KEY_F8); \ oi_f9 = uiobj_add_inputkey(MOO_KEY_F9); \ oi_f10 = uiobj_add_inputkey(MOO_KEY_F10); \ } while (0) #define STARMAP_UIOBJ_CLEAR_FX() \ do { \ oi_f2 = UIOBJI_INVALID; \ oi_f3 = UIOBJI_INVALID; \ oi_f4 = UIOBJI_INVALID; \ oi_f5 = UIOBJI_INVALID; \ oi_f6 = UIOBJI_INVALID; \ oi_f7 = UIOBJI_INVALID; \ oi_f8 = UIOBJI_INVALID; \ oi_f9 = UIOBJI_INVALID; \ oi_f10 = UIOBJI_INVALID; \ } while (0) extern const uint8_t colortbl_textbox[5]; extern const uint8_t colortbl_line_red[5]; extern const uint8_t colortbl_line_reloc[5]; extern const uint8_t colortbl_line_green[5]; extern void ui_starmap_fill_oi_ctrl(struct starmap_data_s *d); extern void ui_starmap_clear_oi_ctrl(struct starmap_data_s *d); extern void ui_starmap_fill_oi_tbls(struct starmap_data_s *d); extern void ui_starmap_fill_oi_tbl_stars(struct starmap_data_s *d); extern void ui_starmap_fill_oi_tbl_stars_own(struct starmap_data_s *d, player_id_t owner); extern void ui_starmap_add_oi_bottom_buttons(struct starmap_data_s *d); extern bool ui_starmap_handle_oi_bottom_buttons(struct starmap_data_s *d, int16_t oi); extern void ui_starmap_add_oi_misc(struct starmap_data_s *d); extern bool ui_starmap_handle_oi_misc(struct starmap_data_s *d, int16_t oi); extern void ui_starmap_handle_oi_ctrl(struct starmap_data_s *d, int16_t oi); extern void ui_starmap_handle_scrollkeys(struct starmap_data_s *d, int16_t oi); extern void ui_starmap_draw_basic(struct starmap_data_s *d); extern void ui_starmap_draw_starmap(struct starmap_data_s *d); extern void ui_starmap_draw_button_text(struct starmap_data_s *d, bool highlight); extern void ui_starmap_sn0_setup(struct shipnon0_s *sn0, int sd_num, const shipcount_t *ships); extern void ui_starmap_update_reserve_fuel(struct game_s *g, struct shipnon0_s *sn0, const shipcount_t *ships, player_id_t pi); extern void ui_starmap_draw_planetinfo(const struct game_s *g, player_id_t api, int planet_i, bool draw_name); extern void ui_starmap_draw_planetinfo_2(const struct game_s *g, int p1, int p2, int planet_i); extern int ui_starmap_newship_next(const struct game_s *g, player_id_t pi, int i); extern int ui_starmap_newship_prev(const struct game_s *g, player_id_t pi, int i); extern int ui_starmap_enemy_incoming(const struct game_s *g, player_id_t pi, int i, bool next); extern void ui_starmap_common_init(struct game_s *g, struct starmap_data_s *d, player_id_t active_player); extern void ui_starmap_common_update_mouse_hover(struct starmap_data_s *d, int16_t oi); #endif 1oom-1.11.2/src/ui/classic/uistarmap_enroute.c000066400000000000000000000351451476061725400212320ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" #include "util.h" /* -------------------------------------------------------------------------- */ static inline bool ui_starmap_enroute_in_frange(struct starmap_data_s *d) { uint8_t pi = d->g->planet_focus_i[d->api]; const planet_t *p = &d->g->planet[pi]; return ((p->within_frange[d->api] == 1) || ((p->within_frange[d->api] == 2) && d->en.sn0.have_reserve_fuel)); } static inline bool ui_starmap_enroute_locked_by_retreat(struct starmap_data_s *d, uint8_t planet_i) { const fleet_enroute_t *r = &(d->g->enroute[ui_data.starmap.fleet_selected]); return (game_num_retreat_redir_fix && r->retreat && !d->g->eto[d->api].have_hyperspace_comm && (planet_i == d->en.pon)); } static void ui_starmap_enroute_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const fleet_enroute_t *r = &(g->enroute[ui_data.starmap.fleet_selected]); const empiretechorbit_t *e = &(g->eto[r->owner]); uint8_t pto = g->planet_focus_i[d->api]; const planet_t *pt = &g->planet[pto]; char buf[0x80]; STARMAP_LIM_INIT(); ui_starmap_draw_basic(d); { int x, y; x = (r->x - ui_data.starmap.x) * 2 + 5; y = (r->y - ui_data.starmap.y) * 2 + 5; lbxgfx_draw_frame_offs_delay(x, y, !d->anim_delay, ui_data.gfx.starmap.shipbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } ui_draw_filled_rect(225, 8, 314, 180, 7, ui_scale); lbxgfx_draw_frame(224, 4, ui_data.gfx.starmap.movextr2, UI_SCREEN_W, ui_scale); if (d->controllable) { lbxgfx_draw_frame(224, 160, ui_data.gfx.starmap.movextr3, UI_SCREEN_W, ui_scale); } ui_draw_filled_rect(227, 8, 310, 39, 0, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.scanner); for (int f = 0; f <= ui_data.starmap.frame_scanner; ++f) { lbxgfx_draw_frame(227, 8, ui_data.gfx.starmap.scanner, UI_SCREEN_W, ui_scale); } lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_race[e->race], game_str_sm_fleet); lbxfont_select_set_12_4(5, tbl_banner_fontparam[e->banner], 0, 0); lbxfont_print_str_center(267, 10, buf, UI_SCREEN_W, ui_scale); if (d->show_planet_focus) { const planet_t *pd = &(g->planet[r->dest]); uint8_t *gfx; int x0, y0, x1, y1, dist; x1 = (pt->x - ui_data.starmap.x) * 2 + 8; y1 = (pt->y - ui_data.starmap.y) * 2 + 8; lbxgfx_draw_frame_offs_delay(x1, y1, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); x0 = (r->x - ui_data.starmap.x) * 2 + 8; y0 = (r->y - ui_data.starmap.y) * 2 + 8; { const uint8_t *ctbl; ctbl = (d->controllable && !ui_starmap_enroute_in_frange(d)) ? colortbl_line_red : colortbl_line_green; ui_draw_line_limit_ctbl(x0 + 4, y0 + 1, x1 + 6, y1 + 6, ctbl, 5, ui_data.starmap.line_anim_phase, starmap_scale); } if (ui_extra_enabled && ui_data.starmap.flag_show_own_routes && (r->owner == d->api)) { int x2, y2; x2 = (pd->x - ui_data.starmap.x) * 2 + 8; y2 = (pd->y - ui_data.starmap.y) * 2 + 8; ui_draw_line_limit_ctbl(x0 + 4, y0 + 1, x2 + 6, y2 + 6, colortbl_line_green, 5, ui_data.starmap.line_anim_phase, starmap_scale); } gfx = ui_data.gfx.starmap.smalship[e->banner]; if (pd->x < r->x) { lbxgfx_set_new_frame(gfx, 1); } else { lbxgfx_set_frame_0(gfx); } lbxgfx_draw_frame_offs(x0, y0, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); dist = game_get_min_dist(g, r->owner, g->planet_focus_i[d->api]); if (d->controllable && !ui_starmap_enroute_in_frange(d)) { /* FIXME use proper positioning for varying str length */ lib_sprintf(buf, sizeof(buf), " %s %i %s.", game_str_sm_outsr, dist - e->fuel_range, game_str_sm_parsecs2); lbxfont_select_set_12_4(2, 0, 0, 0); lbxfont_set_gap_h(2); lbxfont_print_str_split(230, 26, 80, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else { int eta = game_calc_eta_ship(g, game_fleet_get_speed(g, r, d->en.pon, pto), pt->x, pt->y, r->x, r->y); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); lbxfont_select_set_12_4(0, 0, 0, 0); lbxfont_print_str_center(268, 32, buf, UI_SCREEN_W, ui_scale); } } for (int i = 0; i < d->en.sn0.num; ++i) { const shipdesign_t *sd = &(g->srd[r->owner].design[0]); uint8_t *gfx; int st, x, y; x = (i & 1) * 43 + 228; y = (i / 2) * 40 + 44; ui_draw_filled_rect(x, y, x + 38, y + 24, 0, ui_scale); ui_draw_filled_rect(x, y + 28, x + 38, y + 34, 0x1c, ui_scale); ui_draw_stars(x, y, 0, 38, ui_scale); st = d->en.sn0.type[i]; gfx = ui_data.gfx.ships[sd[st].look]; lbxgfx_set_frame_0(gfx); for (int f = 0; f <= ui_data.starmap.frame_ship; ++f) { lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); } lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(x + 35, y + 19, d->en.sn0.ships[i], UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xa, 0, 0); lbxfont_print_str_center(x + 19, y + 29, sd[st].name, UI_SCREEN_W, ui_scale); } if (1 && d->controllable && (!ui_starmap_enroute_in_frange(d) || ui_starmap_enroute_locked_by_retreat(d, pto)) ) { lbxgfx_set_new_frame(ui_data.gfx.starmap.reloc_bu_accept, 1); lbxgfx_draw_frame(271, 163, ui_data.gfx.starmap.reloc_bu_accept, UI_SCREEN_W, ui_scale); } if (!d->anim_delay) { if (ui_data.starmap.scanner_delay == 0) { ui_data.starmap.frame_scanner = (ui_data.starmap.frame_scanner + 1) % 20; ++ui_data.starmap.scanner_delay; } else { ui_data.starmap.scanner_delay = 0; } ui_data.starmap.frame_ship = (ui_data.starmap.frame_ship + 1) % 5; ui_draw_set_stars_xoffs(false); } } /* -------------------------------------------------------------------------- */ static void ui_starmap_enroute_set_pos_focus(const struct game_s *g, player_id_t player_i) { const fleet_enroute_t *r = &g->enroute[ui_data.starmap.fleet_selected]; ui_starmap_set_pos(g, r->x, r->y); } static int ui_starmap_enroute_next(const struct game_s *g, player_id_t pi, int i) { const fleet_enroute_t *r = &g->enroute[i]; player_id_t owner = r->owner; int start = i; do { i = (i + 1) % g->enroute_num; r = &g->enroute[i]; if (r->owner == owner && BOOLVEC_IS1(r->visible, pi)) { return i; } } while (i != start); return g->enroute_num; } static int ui_starmap_enroute_prev(const struct game_s *g, player_id_t pi, int i) { const fleet_enroute_t *r = &g->enroute[i]; player_id_t owner = r->owner; int start = i; do { if (--i < 0) { i = g->enroute_num - 1; } r = &g->enroute[i]; if (r->owner == owner && BOOLVEC_IS1(r->visible, pi)) { return i; } } while (i != start); return g->enroute_num; } void ui_starmap_enroute(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_cancel, oi_accept, oi_search; int16_t oi_f4, oi_f5; struct starmap_data_s d; fleet_enroute_t *r; ui_starmap_common_init(g, &d, active_player); d.set_pos_focus = ui_starmap_enroute_set_pos_focus; r = &(g->enroute[ui_data.starmap.fleet_selected]); d.show_planet_focus = ((r->owner == d.api) || (g->eto[d.api].have_ia_scanner)); d.en.pon = PLANET_NONE; for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p; p = &g->planet[i]; if ((p->x == r->x) && (p->y == r->y)) { d.en.pon = i; break; } } d.controllable = (g->eto[active_player].have_hyperspace_comm || d.en.pon != PLANET_NONE) && (r->owner == active_player); d.from = g->planet_focus_i[active_player]; ui_data.starmap.frame_scanner = 0; ui_data.starmap.scanner_delay = 0; ui_data.starmap.frame_ship = 0; g->planet_focus_i[active_player] = r->dest; ui_starmap_sn0_setup(&d.en.sn0, g->eto[r->owner].shipdesigns_num, r->ships); ui_starmap_update_reserve_fuel(g, &d.en.sn0, r->ships, active_player); uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ oi_accept = UIOBJI_INVALID; \ oi_cancel = UIOBJI_INVALID; \ oi_f4 = UIOBJI_INVALID;\ oi_f5 = UIOBJI_INVALID;\ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(3); uiobj_set_callback_and_delay(ui_starmap_enroute_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { planet_t *p; int16_t oi1, oi2; p = &g->planet[g->planet_focus_i[active_player]]; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); if (ui_search_set_pos(g, active_player)) { if (!d.controllable) { d.from = g->planet_focus_i[active_player]; flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } } } else if ((oi1 == oi_cancel) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_f4) { int i = ui_starmap_enroute_next(g, active_player, ui_data.starmap.fleet_selected); if (i != g->enroute_num) { ui_data.starmap.fleet_selected = i; flag_done = true; ui_sound_play_sfx_24(); } } else if (oi1 == oi_f5) { int i = ui_starmap_enroute_prev(g, active_player, ui_data.starmap.fleet_selected); if (i != g->enroute_num) { ui_data.starmap.fleet_selected = i; flag_done = true; ui_sound_play_sfx_24(); } } else if (oi1 == oi_accept) { do_accept: ui_sound_play_sfx_24(); //BUG: Always true, but otherwise leads to undefined behavior if (p->within_frange[active_player] != 0) { game_fleet_redirect(g, r, d.en.pon, g->planet_focus_i[active_player]); flag_done = true; } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } for (int i = 0; i < g->enroute_num; ++i) { if (oi1 == d.oi_tbl_enroute[i]) { ui_data.starmap.fleet_selected = i; ui_sound_play_sfx_24(); flag_done = true; break; } } if (!d.controllable || ui_sm_explicit_cursor_context) { for (int i = 0; i < g->transport_num; ++i) { if (oi1 == d.oi_tbl_transport[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANSPORT_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (oi1 == d.oi_tbl_pl_stars[j][i]) { g->planet_focus_i[active_player] = i; d.from = i; ui_data.starmap.orbit_player = j; ui_data.ui_main_loop_action = (j == active_player) ? UI_MAIN_LOOP_ORBIT_OWN_SEL : UI_MAIN_LOOP_ORBIT_EN_SEL; ui_sound_play_sfx_24(); flag_done = true; j = g->players; i = g->galaxy_stars; } } } } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if (oi1 == d.oi_tbl_stars[i]) { if (ui_extra_enabled && (oi_accept != UIOBJI_INVALID) && (g->planet_focus_i[active_player] == i)) { oi1 = oi_accept; goto do_accept; } g->planet_focus_i[active_player] = i; if (!d.controllable) { d.from = i; flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } break; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_enroute_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); oi_f4 = uiobj_add_inputkey(MOO_KEY_F4); oi_f5 = uiobj_add_inputkey(MOO_KEY_F5); if (!ui_sm_explicit_cursor_context || kbd_is_modifier(MOO_MOD_ALT) || !d.controllable) { ui_starmap_fill_oi_tbls(&d); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); } else { ui_cursor_setup_area(2, &ui_cursor_area_tbl[1]); } ui_starmap_fill_oi_tbl_stars(&d); if (d.controllable) { oi_cancel = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); if (ui_starmap_enroute_in_frange(&d) && !ui_starmap_enroute_locked_by_retreat(&d, g->planet_focus_i[active_player])) { oi_accept = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); } } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); g->planet_focus_i[active_player] = d.from; } 1oom-1.11.2/src/ui/classic/uistarmap_orbit_en.c000066400000000000000000000223401476061725400213430ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_save.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" /* -------------------------------------------------------------------------- */ static void ui_starmap_orbit_en_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *p = &g->planet[d->from]; const empiretechorbit_t *e = &(g->eto[d->oe.player]); char buf[0x80]; STARMAP_LIM_INIT(); ui_starmap_draw_basic(d); { int x, y; x = (p->x - ui_data.starmap.x) * 2 + 23; y = (p->y - ui_data.starmap.y) * 2 + 5 + d->oe.yoff; lbxgfx_draw_frame_offs_delay(x, y, !d->anim_delay, ui_data.gfx.starmap.shipbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } ui_draw_filled_rect(225, 8, 314, 180, 7, ui_scale); lbxgfx_draw_frame(224, 4, ui_data.gfx.starmap.movextr2, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(227, 8, 310, 39, 0, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.scanner); for (int f = 0; f <= ui_data.starmap.frame_scanner; ++f) { lbxgfx_draw_frame(227, 8, ui_data.gfx.starmap.scanner, UI_SCREEN_W, ui_scale); } lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_race[e->race], game_str_sm_fleet); lbxfont_select_set_12_4(5, tbl_banner_fontparam[e->banner], 0, 0); lbxfont_print_str_center(267, 10, buf, UI_SCREEN_W, ui_scale); lbxfont_select_set_12_4(0, 0, 0, 0); lbxfont_print_str_center(268, 33, game_str_sm_inorbit, UI_SCREEN_W, ui_scale); for (int i = 0; i < d->oe.sn0.num; ++i) { const shipdesign_t *sd = &(g->srd[d->oe.player].design[0]); uint8_t *gfx; int st, x, y; x = 228 + (i % 2) * 43; y = 44 + (i / 2) * 40; ui_draw_filled_rect(x, y, x + 38, y + 24, 0, ui_scale); ui_draw_filled_rect(x, y + 28, x + 38, y + 34, 0x1c, ui_scale); ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; ui_draw_stars(x, y, 0, 38, ui_scale); st = d->oe.sn0.type[i]; gfx = ui_data.gfx.ships[sd[st].look]; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(x + 35, y + 19, d->oe.ships[st], UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xa, 0, 0); lbxfont_print_str_center(x + 19, y + 29, sd[st].name, UI_SCREEN_W, ui_scale); } if (!d->anim_delay) { if (ui_data.starmap.scanner_delay == 0) { ui_data.starmap.frame_scanner = (ui_data.starmap.frame_scanner + 1) % 20; ++ui_data.starmap.scanner_delay; } else { ui_data.starmap.scanner_delay = 0; } } } /* -------------------------------------------------------------------------- */ void ui_starmap_orbit_en(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_search; int16_t oi_f4, oi_f5; struct starmap_data_s d; shipcount_t *os; ui_starmap_common_init(g, &d, active_player); ui_data.starmap.frame_scanner = 0; ui_data.starmap.scanner_delay = 0; d.from = g->planet_focus_i[active_player]; d.oe.player = ui_data.starmap.orbit_player; os = &(g->eto[d.oe.player].orbit[d.from].ships[0]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { d.oe.ships[i] = os[i]; } ui_starmap_sn0_setup(&d.oe.sn0, NUM_SHIPDESIGNS, d.oe.ships); { int n = 0; for (player_id_t i = PLAYER_0; i < d.oe.player; ++i) { os = &(g->eto[i].orbit[d.from].ships[0]); for (int j = 0; j < g->eto[i].shipdesigns_num; ++j) { if (os[j] != 0) { ++n; break; } } } d.oe.yoff = n * 6; } uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ oi_f4 = UIOBJI_INVALID; \ oi_f5 = UIOBJI_INVALID; \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_callback_and_delay(ui_starmap_orbit_en_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); ui_search_set_pos(g, active_player); } for (int i = 0; i < g->enroute_num; ++i) { if (oi1 == d.oi_tbl_enroute[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ENROUTE_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->transport_num; ++i) { if (oi1 == d.oi_tbl_transport[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANSPORT_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (oi1 == d.oi_tbl_pl_stars[j][i]) { g->planet_focus_i[active_player] = i; d.from = i; ui_data.starmap.orbit_player = j; ui_data.ui_main_loop_action = (j == active_player) ? UI_MAIN_LOOP_ORBIT_OWN_SEL : UI_MAIN_LOOP_ORBIT_EN_SEL; ui_sound_play_sfx_24(); flag_done = true; j = g->players; i = g->galaxy_stars; } } } if (oi1 == UIOBJI_ESC) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_f4) { bool found; int i, pi; i = pi = d.from; found = false; do { i = (i + 1) % g->galaxy_stars; for (int j = 0; j < g->eto[ui_data.starmap.orbit_player].shipdesigns_num; ++j) { if (g->eto[ui_data.starmap.orbit_player].orbit[i].ships[j] && BOOLVEC_IS1(g->planet[i].within_srange, d.api)) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); flag_done = true; } } else if (oi1 == oi_f5) { bool found; int i, pi; i = pi = d.from; found = false; do { if (--i < 0) { i = g->galaxy_stars - 1; } for (int j = 0; j < g->eto[ui_data.starmap.orbit_player].shipdesigns_num; ++j) { if (g->eto[ui_data.starmap.orbit_player].orbit[i].ships[j] && BOOLVEC_IS1(g->planet[i].within_srange, d.api)) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); flag_done = true; } } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if ((oi1 == d.oi_tbl_stars[i]) && !g->evn.build_finished_num[active_player]) { g->planet_focus_i[active_player] = i; ui_sound_play_sfx_24(); ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; flag_done = true; break; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_orbit_en_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); oi_f4 = uiobj_add_inputkey(MOO_KEY_F4); oi_f5 = uiobj_add_inputkey(MOO_KEY_F5); ui_starmap_fill_oi_tbls(&d); ui_starmap_fill_oi_tbl_stars(&d); oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_table_clear(); } 1oom-1.11.2/src/ui/classic/uistarmap_orbit_own.c000066400000000000000000000466631476061725400215620ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_save.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" /* -------------------------------------------------------------------------- */ static inline bool ui_starmap_orbit_own_in_frange(struct starmap_data_s *d) { uint8_t pi = d->g->planet_focus_i[d->api]; const planet_t *p = &d->g->planet[pi]; return (p->within_frange[d->api] == 1) || ((p->within_frange[d->api] == 2) && d->oo.sn0.have_reserve_fuel); } static void ui_starmap_orbit_own_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *pf = &g->planet[d->from]; const planet_t *pt = &g->planet[g->planet_focus_i[d->api]]; char buf[0x80]; STARMAP_LIM_INIT(); ui_starmap_draw_basic(d); { int x, y; x = (pf->x - ui_data.starmap.x) * 2 + 23; y = (pf->y - ui_data.starmap.y) * 2 + 5; lbxgfx_draw_frame_offs_delay(x, y, !d->anim_delay, ui_data.gfx.starmap.shipbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } ui_draw_filled_rect(225, 8, 314, 192, 7, ui_scale); lbxgfx_draw_frame(224, 5, ui_data.gfx.starmap.move_shi, UI_SCREEN_W, ui_scale); if (d->oo.sn0.num < NUM_SHIPDESIGNS) { lbxgfx_draw_frame(224, 151, ui_data.gfx.starmap.movextra, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(228, 155, 309, 175, 7, ui_scale); } lbxfont_select_set_12_4(0, 5, 0, 0); lbxfont_print_str_center(268, 11, game_str_sm_fleetdep, UI_SCREEN_W, ui_scale); if (g->planet_focus_i[d->api] != d->from) { int dist = game_get_min_dist(g, d->api, g->planet_focus_i[d->api]); int x0, y0, x1, y1; const uint8_t *ctbl; uint8_t *gfx; x1 = (pt->x - ui_data.starmap.x) * 2 + 8; y1 = (pt->y - ui_data.starmap.y) * 2 + 8; lbxgfx_draw_frame_offs_delay(x1, y1, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); x0 = (pf->x - ui_data.starmap.x) * 2 + 26; y0 = (pf->y - ui_data.starmap.y) * 2 + 8; ctbl = ui_starmap_orbit_own_in_frange(d) ? colortbl_line_green : colortbl_line_red; ui_draw_line_limit_ctbl(x0 + 3, y0 + 1, x1 + 6, y1 + 6, ctbl, 5, ui_data.starmap.line_anim_phase, starmap_scale); gfx = ui_data.gfx.starmap.smalship[g->eto[d->api].banner]; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame_offs(x0, y0, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); if (!ui_starmap_orbit_own_in_frange(d)) { if (d->oo.sn0.num < NUM_SHIPDESIGNS) { /* WASBUG MOO1 compares to 7, resulting in text below last ship */ lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_destoor, dist, game_str_sm_parsfromcc); lbxfont_select(2, 0, 0, 0); lbxfont_set_gap_h(2); lbxfont_print_str_split(228, 156, 81, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else { lib_sprintf(buf, sizeof(buf), "%s (%i)", game_str_sm_destoor2, dist); ui_draw_filled_rect(228, 9, 309, 17, 7, ui_scale); lbxfont_print_str_center(268, 11, buf, UI_SCREEN_W, ui_scale); } } else { if ((pt->owner == d->api) && (pf->owner == d->api) && pt->have_stargate && pf->have_stargate) { lib_strcpy(buf, game_str_sm_stargate, sizeof(buf)); } else if (d->oo.shiptypenon0numsel > 0) { const shipdesign_t *sd = &(g->srd[d->api].design[0]); int eta, speed = 20; for (int i = 0; i < d->oo.sn0.num; ++i) { int st; st = d->oo.sn0.type[i]; if (d->oo.ships[st] > 0) { SETMIN(speed, sd[st].engine); } } ++speed; eta = game_calc_eta_ship(g, speed, pt->x, pt->y, pf->x, pf->y); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } else { buf[0] = '\0'; } lbxfont_select_set_12_4(0, 0, 0, 0); if (d->oo.sn0.num >= NUM_SHIPDESIGNS) { ui_draw_filled_rect(228, 9, 309, 17, 7, ui_scale); lbxfont_print_str_center(268, 11, buf, UI_SCREEN_W, ui_scale); } else { lbxfont_print_str_center(268, 163, buf, UI_SCREEN_W, ui_scale); } } } else { if (d->oo.sn0.num < NUM_SHIPDESIGNS) { lbxfont_select_set_12_4(2, 0xe, 0, 0); lbxfont_print_str_split(230, 159, 80, game_str_sm_chdest, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } } for (int i = 0; i < d->oo.sn0.num; ++i) { const shipdesign_t *sd = &(g->srd[d->api].design[0]); uint8_t *gfx; int st; ui_draw_filled_rect(227, 22 + i * 26, 259, 46 + i * 26, 0, ui_scale); ui_draw_filled_rect(264, 34 + i * 26, 310, 46 + i * 26, 0, ui_scale); ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; ui_draw_stars(227, 22 + i * 26, 0, 32, ui_scale); st = d->oo.sn0.type[i]; gfx = ui_data.gfx.ships[sd[st].look]; lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(227, 22 + i * 26, gfx, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); { int y; y = 40 + i * 26; lbxfont_print_num_right(258, y, d->oo.ships[st], UI_SCREEN_W, ui_scale); if (ui_extra_enabled) { y = 24 + i * 26; lbxfont_select(0, 0x7, 0, 0); lbxfont_print_num_right(258, y, d->oo.sn0.ships[i], UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); } } lbxfont_select_set_12_1(2, 0, 0, 0); lbxfont_print_str_center(287, 25 + i * 26, sd[st].name, UI_SCREEN_W, ui_scale); } lbxgfx_set_new_frame(ui_data.gfx.starmap.reloc_bu_accept, 1); lbxgfx_draw_frame(271, 180, ui_data.gfx.starmap.reloc_bu_accept, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_starmap_orbit_own(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_cancel, oi_accept, oi_search, oi_f2, oi_f3, oi_f4, oi_f5, oi_f6, oi_f7, oi_f8, oi_f9, oi_f10, oi_tbl_p[NUM_SHIPDESIGNS], oi_tbl_m[NUM_SHIPDESIGNS], oi_tbl_a[NUM_SHIPDESIGNS], oi_tbl_n[NUM_SHIPDESIGNS], oi_tbl_s[NUM_SHIPDESIGNS] ; int16_t scrollship = 0; struct starmap_data_s d; const fleet_orbit_t *r; const shipcount_t *os; const uint8_t shiptypes[NUM_SHIPDESIGNS] = { 0, 1, 2, 3, 4, 5 }; ui_starmap_common_init(g, &d, active_player); d.from = g->planet_focus_i[active_player]; d.controllable = true; r = &(g->eto[active_player].orbit[d.from]); if (BOOLVEC_IS_CLEAR(r->visible, PLAYER_NUM)) { ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; return; } os = &(r->ships[0]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { d.oo.ships[i] = os[i]; } ui_starmap_sn0_setup(&d.oo.sn0, NUM_SHIPDESIGNS, d.oo.ships); uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ STARMAP_UIOBJ_CLEAR_FX(); \ oi_accept = UIOBJI_INVALID; \ oi_cancel = UIOBJI_INVALID; \ UIOBJI_SET_TBL5_INVALID(oi_tbl_p, oi_tbl_m, oi_tbl_a, oi_tbl_n, oi_tbl_s); \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(16); uiobj_set_callback_and_delay(ui_starmap_orbit_own_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; ui_starmap_update_reserve_fuel(g, &d.oo.sn0, d.oo.ships, active_player); oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); ui_search_set_pos(g, active_player); } else if (oi1 == oi_f2) { int i; i = d.from; do { if (--i < 0) { i = g->galaxy_stars - 1; } } while (g->planet[i].owner != active_player); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); d.from = i; /* flag_have_colony_lbx = false */ flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_f3) { int i; i = d.from; do { i = (i + 1) % g->galaxy_stars; } while (g->planet[i].owner != active_player); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); ui_sound_play_sfx_24(); d.from = i; /* flag_have_colony_lbx = false */ flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (((oi1 == oi_f8) || (oi1 == oi_f9)) && g->eto[active_player].have_ia_scanner) { int i, pi; ui_sound_play_sfx_24(); pi = g->planet_focus_i[active_player]; i = ui_starmap_enemy_incoming(g, active_player, pi, (oi1 == oi_f8)); if (i != pi) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; /* flag_have_colony_lbx = false */ flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } } else if (oi1 == oi_f10) { game_save_do_save_i(GAME_SAVE_I_CONTINUE, "Continue", g); } else if (oi1 == oi_f4) { bool found; int i, pi; i = pi = d.from; found = false; do { i = (i + 1) % g->galaxy_stars; for (int j = 0; j < g->eto[active_player].shipdesigns_num; ++j) { if (g->eto[active_player].orbit[i].ships[j]) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); ui_data.starmap.orbit_player = active_player; flag_done = true; } } else if (oi1 == oi_f5) { bool found; int i, pi; i = pi = d.from; found = false; do { if (--i < 0) { i = g->galaxy_stars - 1; } for (int j = 0; j < g->eto[active_player].shipdesigns_num; ++j) { if (g->eto[active_player].orbit[i].ships[j]) { found = true; break; } } } while ((!found) && (i != pi)); if (found) { g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); ui_data.starmap.orbit_player = active_player; flag_done = true; } } else if (oi1 == oi_f6) { int i; i = ui_starmap_newship_next(g, active_player, d.from); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); if (BOOLVEC_IS1(g->eto[active_player].orbit[i].visible, active_player)) { ui_data.starmap.orbit_player = active_player; } else { ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } flag_done = true; } else if (oi1 == oi_f7) { int i; i = ui_starmap_newship_prev(g, active_player, d.from); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); d.from = i; ui_sound_play_sfx_24(); if (BOOLVEC_IS1(g->eto[active_player].orbit[i].visible, active_player)) { ui_data.starmap.orbit_player = active_player; } else { ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } flag_done = true; } for (int i = 0; i < g->enroute_num; ++i) { if (oi1 == d.oi_tbl_enroute[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ENROUTE_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->transport_num; ++i) { if (oi1 == d.oi_tbl_transport[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANSPORT_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (oi1 == d.oi_tbl_pl_stars[j][i]) { g->planet_focus_i[active_player] = i; /* not done on MOO1! */ d.from = i; ui_data.starmap.orbit_player = j; ui_data.ui_main_loop_action = (j == active_player) ? UI_MAIN_LOOP_ORBIT_OWN_SEL : UI_MAIN_LOOP_ORBIT_EN_SEL; ui_sound_play_sfx_24(); flag_done = true; j = g->players; i = g->galaxy_stars; } } } if ((oi1 == oi_cancel) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_accept) { do_accept: ui_sound_play_sfx_24(); if (ui_starmap_orbit_own_in_frange(&d)) { game_send_fleet_from_orbit(g, active_player, d.from, g->planet_focus_i[active_player], d.oo.ships, shiptypes, 6); game_update_visibility(g); } if ((!kbd_is_modifier(MOO_MOD_SHIFT)) || BOOLVEC_IS_CLEAR(r->visible, PLAYER_NUM)) { flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else { ui_starmap_sn0_setup(&d.oo.sn0, NUM_SHIPDESIGNS, os); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { SETMIN(d.oo.ships[i], os[i]); } g->planet_focus_i[active_player] = d.from; } } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if (oi1 == d.oi_tbl_stars[i]) { if (ui_extra_enabled && (oi_accept != UIOBJI_INVALID) && (g->planet_focus_i[active_player] == i)) { oi1 = oi_accept; goto do_accept; } g->planet_focus_i[active_player] = i; ui_sound_play_sfx_24(); break; } } for (int i = 0; i < d.oo.sn0.num; ++i) { int si, per10num; si = d.oo.sn0.type[i]; per10num = os[si] / 10; if (kbd_is_modifier(MOO_MOD_CTRL)) { per10num = 1; } SETMAX(per10num, 1); if ((oi1 == oi_tbl_p[i]) || ((oi1 == oi_tbl_s[i]) && ((scrollship > 0) != ui_mwi_counter))) { shipcount_t t; t = d.oo.ships[si] + per10num; SETMIN(t, os[si]); d.oo.ships[si] = t; if (scrollship) { scrollship = 0; } else { ui_sound_play_sfx_24(); } break; } else if ((oi1 == oi_tbl_m[i]) || ((oi1 == oi_tbl_s[i]) && ((scrollship < 0) != ui_mwi_counter))) { shipcount_t t; t = d.oo.ships[si]; t = (t < per10num) ? 0 : (t - per10num); d.oo.ships[si] = t; ui_sound_play_sfx_24(); if (scrollship) { scrollship = 0; } else { ui_sound_play_sfx_24(); } break; } else if (oi1 == oi_tbl_a[i]) { d.oo.ships[si] = os[si]; ui_sound_play_sfx_24(); break; } else if (oi1 == oi_tbl_n[i]) { d.oo.ships[si] = 0; ui_sound_play_sfx_24(); break; } } d.oo.shiptypenon0numsel = 0; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (d.oo.ships[i] != 0) { ++d.oo.shiptypenon0numsel; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_orbit_own_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); STARMAP_UIOBJ_FILL_FX(); if (!ui_sm_explicit_cursor_context || kbd_is_modifier(MOO_MOD_ALT)) { ui_starmap_fill_oi_tbls(&d); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); } else { ui_cursor_setup_area(2, &ui_cursor_area_tbl[1]); } ui_starmap_fill_oi_tbl_stars(&d); oi_cancel = uiobj_add_t0(227, 180, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); if (ui_starmap_orbit_own_in_frange(&d) && d.oo.shiptypenon0numsel) { oi_accept = uiobj_add_t0(271, 180, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); for (int i = 0; i < d.oo.sn0.num; ++i) { oi_tbl_p[i] = uiobj_add_t0(288, 35 + i * 26, "", ui_data.gfx.starmap.move_but_p, MOO_KEY_UNKNOWN); oi_tbl_m[i] = uiobj_add_t0(277, 35 + i * 26, "", ui_data.gfx.starmap.move_but_m, MOO_KEY_UNKNOWN); oi_tbl_a[i] = uiobj_add_t0(299, 35 + i * 26, "", ui_data.gfx.starmap.move_but_a, MOO_KEY_UNKNOWN); oi_tbl_n[i] = uiobj_add_t0(265, 35 + i * 26, "", ui_data.gfx.starmap.move_but_n, MOO_KEY_UNKNOWN); oi_tbl_s[i] = uiobj_add_mousewheel(227, 22 + i * 26, 319, 46 + i * 26, &scrollship); } ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); d.oi_tech = UIOBJI_INVALID; d.oi_next_turn = UIOBJI_INVALID; ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); g->planet_focus_i[active_player] = d.from; } 1oom-1.11.2/src/ui/classic/uistarmap_reloc.c000066400000000000000000000162201476061725400206460ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" /* -------------------------------------------------------------------------- */ static void ui_starmap_reloc_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *pf = &g->planet[d->from]; const planet_t *pt = &g->planet[g->planet_focus_i[d->api]]; char buf[0x40]; int x0, y0; STARMAP_LIM_INIT(); ui_starmap_draw_basic(d); x0 = (pf->x - ui_data.starmap.x) * 2 + 8; y0 = (pf->y - ui_data.starmap.y) * 2 + 8; if (g->planet_focus_i[d->api] != d->from) { int x1, y1; const uint8_t *ctbl; x1 = (pt->x - ui_data.starmap.x) * 2 + 14; y1 = (pt->y - ui_data.starmap.y) * 2 + 14; if (game_reloc_dest_ok(g, g->planet_focus_i[d->api], d->api)) { ctbl = colortbl_line_green; } else { ctbl = colortbl_line_red; } ui_draw_line_limit_ctbl(x0 + 6, y0 + 6, x1, y1, ctbl, 5, ui_data.starmap.line_anim_phase, starmap_scale); } lbxgfx_draw_frame_offs_delay(x0, y0, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); if (pt->owner == d->api) { lbxgfx_draw_frame(222, 80, ui_data.gfx.starmap.relocate, UI_SCREEN_W, ui_scale); } else { lbxgfx_draw_frame_offs(222, 80, ui_data.gfx.starmap.relocate, 0, 83, 310, 199, UI_SCREEN_W, ui_scale); if (BOOLVEC_IS0(pt->explored, d->api)) { ui_draw_filled_rect(227, 57, 310, 159, 0, ui_scale); lbxgfx_draw_frame_offs(224, 5, ui_data.gfx.starmap.unexplor, 227, 57, 310, 159, UI_SCREEN_W, ui_scale); } else { ui_draw_filled_rect(227, 73, 310, 159, 7, ui_scale); ui_draw_box1(227, 73, 310, 159, 4, 4, ui_scale); } } lbxfont_select_set_12_1(5, 5, 0, 0); lbxfont_print_str_center(269, 90, game_str_sm_sreloc, UI_SCREEN_W, ui_scale); lbxfont_select(0, 6, 0, 0); lbxfont_print_str_split(229, 105, 80, game_str_sm_sreloc2, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); if (g->planet_focus_i[d->api] != d->from) { if (pf->have_stargate && pt->have_stargate && pf->owner == pt->owner) { lib_strcpy(buf, game_str_sm_stargate, sizeof(buf)); } else { int eta; eta = game_calc_eta_ship(g, g->srd[d->api].design[pf->buildship].engine + 1, pf->x, pf->y, pt->x, pt->y); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_delay, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } lbxfont_select(0, 0, 0, 0); lbxfont_print_str_center(268, 149, buf, UI_SCREEN_W, ui_scale); } lbxgfx_set_new_frame(ui_data.gfx.starmap.reloc_bu_accept, 1); lbxgfx_draw_frame(271, 163, ui_data.gfx.starmap.reloc_bu_accept, UI_SCREEN_W, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_starmap_reloc(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_cancel, oi_accept, oi_search; struct starmap_data_s d; ui_starmap_common_init(g, &d, active_player); d.controllable = true; { uint8_t oldreloc; uint8_t pi = g->planet_focus_i[active_player]; d.from = pi; oldreloc = g->planet[pi].reloc; g->planet_focus_i[active_player] = oldreloc; if (!game_reloc_dest_ok(g, oldreloc, active_player)) { g->planet_focus_i[active_player] = pi; } } uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ oi_accept = UIOBJI_INVALID; \ oi_cancel = UIOBJI_INVALID; \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(2); uiobj_set_callback_and_delay(ui_starmap_reloc_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { int i; i = ui_search(g, active_player); if (i >= 0) { if (game_reloc_dest_ok(g, i, active_player)) { ui_sound_play_sfx_24(); g->planet_focus_i[active_player] = i; ui_starmap_set_pos_focus(g, active_player); } else { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } } } if ((oi1 == oi_cancel) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_accept) { do_accept: ui_sound_play_sfx_24(); flag_done = true; g->planet[d.from].reloc = g->planet_focus_i[active_player]; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if (oi1 == d.oi_tbl_stars[i]) { if (ui_extra_enabled && (oi_accept != UIOBJI_INVALID) && (g->planet_focus_i[active_player] == i)) { oi1 = oi_accept; goto do_accept; } g->planet_focus_i[active_player] = i; ui_sound_play_sfx_24(); break; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_reloc_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); if (game_num_extended_reloc_range) { ui_starmap_fill_oi_tbl_stars(&d); } else { ui_starmap_fill_oi_tbl_stars_own(&d, active_player); } oi_cancel = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); if (g->planet[d.from].buildship != BUILDSHIP_STARGATE && game_reloc_dest_ok(g, g->planet_focus_i[active_player], active_player)) { oi_accept = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_set_help_id(-1); g->planet_focus_i[active_player] = d.from; } 1oom-1.11.2/src/ui/classic/uistarmap_ships.c000066400000000000000000000162141476061725400206730ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_str.h" #include "game_tech.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" /* -------------------------------------------------------------------------- */ static inline int ui_starmap_ships_get_x(int i) { return 228 + 44 * (i / 3); } static inline int ui_starmap_ships_get_y(int i) { return 83 + 26 * (i % 3); } static void ui_starmap_ships_draw_cb1(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *p = &(g->planet[g->planet_focus_i[d->api]]); char buf[0x80]; ui_starmap_draw_basic(d); lbxgfx_draw_frame(222, 80, ui_data.gfx.starmap.relocate, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(225, 81, 312, 160, 0, ui_scale); const uint8_t n = g->eto[d->api].shipdesigns_num; ui_data.starmap.stars_xoff1 = 0; ui_data.starmap.stars_xoff2 = 0; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { int x = ui_starmap_ships_get_x(i); int y = ui_starmap_ships_get_y(i); ui_draw_stars(x, y, i * 5, 32, ui_scale); } for (int i = 0; i < n; ++i) { const shipdesign_t *sd = &g->srd[d->api].design[i]; uint8_t *gfx = ui_data.gfx.ships[sd->look]; int x = ui_starmap_ships_get_x(i); int y = ui_starmap_ships_get_y(i); lbxgfx_set_frame_0(gfx); lbxgfx_draw_frame(x, y, gfx, UI_SCREEN_W, ui_scale); lbxfont_select(2, 0xd, 0, 0); lbxfont_select_set_12_1(2, 0xa, 0, 0); lbxfont_print_str_center(x + 19, y + 18, sd->name, UI_SCREEN_W, ui_scale); } int i = p->buildship; if (i < n) { int x = ui_starmap_ships_get_x(i); int y = ui_starmap_ships_get_y(i); ui_draw_box1(x - 3, y - 1, x + 40, y + 24, 0x56, 0x56, ui_scale); } if (kbd_is_modifier(MOO_MOD_CTRL)) { lbxfont_select_set_12_1(2, 0xd, 0, 0); lbxfont_print_str_center(272, 84, game_str_sm_ship_everywhere, UI_SCREEN_W, ui_scale); } else if (kbd_is_modifier(MOO_MOD_ALT)) { lbxfont_select_set_12_1(2, 0xd, 0, 0); if (p->buildship != BUILDSHIP_STARGATE) { const shipdesign_t *sd = &g->srd[d->api].design[p->buildship]; lib_sprintf(buf, sizeof(buf), "%s %s", game_str_sm_ship_replace, sd->name); } else { lib_sprintf(buf, sizeof(buf), "%s %s", game_str_sm_ship_replace, game_str_sm_stargate); } lbxfont_print_str_center(272, 84, buf, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ void ui_starmap_ships(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_ship_design[NUM_SHIPDESIGNS]; int16_t oi_cancel, oi_accept, oi_search, oi_finished, oi_s; struct starmap_data_s d; ui_starmap_common_init(g, &d, active_player); planet_t *p = &(g->planet[g->planet_focus_i[active_player]]); uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ UIOBJI_SET_TBL_INVALID(oi_ship_design); \ oi_cancel = UIOBJI_INVALID; \ oi_accept = UIOBJI_INVALID; \ oi_finished = UIOBJI_INVALID; \ oi_s = UIOBJI_INVALID; \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_callback_and_delay(ui_starmap_ships_draw_cb1, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); ui_search_set_pos(g, active_player); } else if (oi1 == oi_s) { p->buildship = (p->buildship + 1) % g->eto[active_player].shipdesigns_num; } else if (oi1 == oi_finished) { if (ui_starmap_remove_build_finished(g, active_player, p)) { if (ui_extra_enabled) { g->planet_focus_i[active_player] = ui_data.start_planet_focus_i; ui_starmap_set_pos_focus(g, active_player); } } ui_sound_play_sfx_24(); flag_done = true; ui_delay_1(); oi1 = 0; } for (int i = 0; i < g->eto[active_player].shipdesigns_num; ++i) { if (oi1 == oi_ship_design[i]) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_CTRL)) { game_ship_build_everywhere(g, p->owner, i); } else if (kbd_is_modifier(MOO_MOD_ALT)) { game_ship_replace_everywhere(g, p->owner, p->buildship, i); } else { p->buildship = i; } } } if ((oi1 == oi_cancel) || (oi1 == oi_accept) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_24(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if ((oi1 == d.oi_tbl_stars[i]) && !g->evn.build_finished_num[active_player]) { g->planet_focus_i[active_player] = i; flag_done = true; ui_sound_play_sfx_24(); break; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_ships_draw_cb1(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); if (g->evn.build_finished_num[active_player]) { oi_finished = uiobj_add_mousearea(6, 6, 225, 180, MOO_KEY_SPACE); } ui_starmap_fill_oi_tbls(&d); ui_starmap_fill_oi_tbl_stars_own(&d, active_player); oi_cancel = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); oi_accept = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); oi_s = uiobj_add_inputkey(MOO_KEY_s); for (int i = 0; i < g->eto[active_player].shipdesigns_num; ++i) { int x = ui_starmap_ships_get_x(i); int y = ui_starmap_ships_get_y(i); oi_ship_design[i] = uiobj_add_mousearea(x - 3, y - 1, x + 40, y + 24, MOO_KEY_1 + i); } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_table_clear(); } 1oom-1.11.2/src/ui/classic/uistarmap_trans.c000066400000000000000000000315661476061725400207030ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void ui_starmap_trans_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *pf = &g->planet[d->from]; const planet_t *pt = &g->planet[g->planet_focus_i[d->api]]; char buf[0x80]; int x0, y0, trans_max = pf->pop / 2; STARMAP_LIM_INIT(); uiobj_set_help_id(17); ui_starmap_draw_basic(d); x0 = (pf->x - ui_data.starmap.x) * 2 + 8; y0 = (pf->y - ui_data.starmap.y) * 2 + 8; if (pt->owner == d->api) { lbxgfx_draw_frame(222, 80, ui_data.gfx.starmap.relocate, UI_SCREEN_W, ui_scale); /* if (pt->unrest == PLANET_UNREST_REBELLION) {} never true, trans button disabled in uistarmap.c */ } else { lbxgfx_draw_frame_offs(222, 80, ui_data.gfx.starmap.relocate, 0, 83, 310, 199, UI_SCREEN_W, ui_scale); if (BOOLVEC_IS0(pt->explored, d->api)) { ui_draw_filled_rect(227, 57, 310, 159, 0, ui_scale); lbxgfx_draw_frame_offs(224, 5, ui_data.gfx.starmap.unexplor, 227, 57, 310, 159, UI_SCREEN_W, ui_scale); } else { ui_draw_filled_rect(227, 73, 310, 159, 7, ui_scale); ui_draw_box1(227, 73, 310, 159, 4, 4, ui_scale); } } lbxgfx_draw_frame_offs_delay(x0, y0, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); lbxgfx_set_new_frame(ui_data.gfx.starmap.reloc_bu_accept, 1); lbxgfx_draw_frame(271, 163, ui_data.gfx.starmap.reloc_bu_accept, UI_SCREEN_W, ui_scale); if (d->from != g->planet_focus_i[d->api]) { const uint8_t *ctbl; int x1, y1; x1 = (pt->x - ui_data.starmap.x) * 2 + 14; y1 = (pt->y - ui_data.starmap.y) * 2 + 14; if (0 || (!d->tr.other) || (pt->within_frange[d->api] != 1) || BOOLVEC_IS0(pt->explored, d->api) || (pt->owner == PLAYER_NONE) || (pt->type < g->eto[d->api].have_colony_for) ) { ctbl = colortbl_line_red; } else { ctbl = colortbl_line_green; } ui_draw_line_limit_ctbl(x0 + 6, y0 + 6, x1, y1, ctbl, 5, ui_data.starmap.line_anim_phase, starmap_scale); } if (d->from != g->planet_focus_i[d->api] || (ui_extra_enabled && d->tr.other)) { if (pt->within_frange[d->api] != 1) { int mindist = game_get_min_dist(g, d->api, g->planet_focus_i[d->api]); lbxfont_select_set_12_1(0, 0xe, 5, 0); lbxfont_set_gap_h(1); lbxfont_print_str_split(228, 94, 82, game_str_sm_notrange, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %i %s %i %s", game_str_sm_notrange1, mindist, game_str_sm_notrange2, g->eto[d->api].fuel_range, game_str_sm_notrange3); lbxfont_print_str_split(229, 125, 80, game_str_sm_seltr, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else if (BOOLVEC_IS0(pt->explored, d->api)) { lbxfont_select(0, 0xe, 0, 0); lbxfont_print_str_split(229, 105, 80, game_str_sm_trfirste, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else if (pt->type < g->eto[d->api].have_colony_for) { int pos; lbxfont_select(0, 6, 0, 0); lbxfont_set_gap_h(1); pos = lib_sprintf(buf, sizeof(buf), "%s ", game_str_sm_trcontr1); lib_sprintf(&buf[pos], sizeof(buf) - pos, "%s ", game_str_tbl_sm_pltype[pt->type]); util_str_tolower(&buf[pos], sizeof(buf) - pos); lib_strcat(&buf[pos], game_str_sm_trcontr2, sizeof(buf) - pos); lbxfont_print_str_split(228, 111, 82, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else if (pt->owner == PLAYER_NONE) { lbxfont_select(0, 0xe, 0, 0); lbxfont_print_str_split(230, 105, 80, game_str_sm_trfirstc, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else { treaty_t treaty = TREATY_NONE; uiobj_set_help_id(1); if (pf->have_stargate && pt->have_stargate && (pf->owner == pt->owner)) { lib_strcpy(buf, game_str_sm_stargate, sizeof(buf)); } else { int eta, engine = g->eto[d->api].have_engine; eta = game_calc_eta_trans(g, engine, pf->x, pf->y, pt->x, pt->y); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } lbxfont_select(0, 0, 0, 0); lbxfont_print_str_center(268, 149, buf, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(230, 123, ui_data.gfx.starmap.tran_bar, UI_SCREEN_W, ui_scale); lbxfont_select(0, 6, 0, 0); if (pt->owner != PLAYER_NONE) {/* WASBUG MOO1 tests for == PLAYER_NONE, reading from eto offs 0xcc */ treaty = g->eto[d->api].treaty[pt->owner]; } if ((treaty == TREATY_NONAGGRESSION) || (treaty == TREATY_ALLIANCE)) { lbxfont_print_str_split(228, 105, 84, game_str_sm_trwarna, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else { int v = 0; if (pf->owner == pt->owner) { v = pt->pop; } v += d->tr.num; if (pt->max_pop3 < v) { if (d->anim_delay == 0) { d->tr.blink = !d->tr.blink; } if (d->tr.blink) { lbxfont_select(0, 5, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_trwarnm1, pt->max_pop3, game_str_sm_trwarnm2); lbxfont_print_str_split(228, 101, 80, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } } else { const char *s = (pt->owner == pf->owner) ? game_str_sm_trchnum1 : game_str_sm_trchnum2; lbxfont_print_str_split(228, 105, 84, s, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } } lbxfont_select_set_12_1(0, 1, 0, 0); lbxfont_print_num_right(273, 137, d->tr.num, UI_SCREEN_W, ui_scale); ui_draw_filled_rect(258, 127, 299, 129, 0x2f, ui_scale); if (d->tr.num > 0) { ui_draw_slider(258, 127, d->tr.num * 40, trans_max, 0, 0x73, ui_scale); } } } else { lbxfont_select(0, 6, 0, 0); lbxfont_print_str_split(229, 110, 80, game_str_sm_seltr, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } lbxfont_select_set_12_1(5, 5, 0, 0); { int y; y = (d->tr.other && (pt->within_frange[d->api] != 1)) ? 77 : 90; lbxfont_print_str_center(269, y, game_str_sm_transs, UI_SCREEN_W, ui_scale); } } /* -------------------------------------------------------------------------- */ void ui_starmap_trans(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_cancel, oi_accept, oi_plus, oi_minus, oi_search, oi_equals; struct starmap_data_s d; planet_t *p; int16_t trans_max; ui_starmap_common_init(g, &d, active_player); d.controllable = true; d.tr.blink = false; { uint8_t pi = g->planet_focus_i[active_player]; d.from = pi; p = &(g->planet[pi]); if (p->trans_num != 0) { d.tr.other = true; g->planet_focus_i[active_player] = p->trans_dest; } else { d.tr.other = false; g->planet_focus_i[active_player] = pi; } } d.tr.num = p->trans_num; trans_max = p->pop / 2; uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ oi_accept = UIOBJI_INVALID; \ oi_cancel = UIOBJI_INVALID; \ oi_plus = UIOBJI_INVALID; \ oi_minus = UIOBJI_INVALID; \ oi_equals = UIOBJI_INVALID; \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_callback_and_delay(ui_starmap_trans_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; const planet_t *pt; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); pt = &(g->planet[g->planet_focus_i[active_player]]); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); if (ui_search_set_pos(g, active_player)) { d.tr.other = true; } } if ((oi1 == oi_cancel) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_accept) { do_accept: ui_sound_play_sfx_24(); flag_done = true; if (BOOLVEC_IS1(pt->explored, active_player) && (pt->within_frange[active_player] == 1)) { p->trans_dest = g->planet_focus_i[active_player]; p->trans_num = d.tr.num; } if (d.from == g->planet_focus_i[active_player]) { p->trans_num = 0; } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_minus) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_CTRL)) { SUBSAT0(d.tr.num, (trans_max + 9) / 10); } else if (kbd_is_modifier(MOO_MOD_ALT)) { d.tr.num = 0; } else { SUBSAT0(d.tr.num, 1); } if (ui_extra_enabled) { d.tr.other = true; } } else if (oi1 == oi_plus || oi1 == oi_equals) { ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_CTRL)) { d.tr.num += (trans_max + 9) / 10; } else if (kbd_is_modifier(MOO_MOD_ALT)) { d.tr.num = trans_max; } else { ++d.tr.num; } SETMIN(d.tr.num, trans_max); if (ui_extra_enabled) { d.tr.other = true; } } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if (oi1 == d.oi_tbl_stars[i]) { if (ui_extra_enabled && (oi_accept != UIOBJI_INVALID) && (g->planet_focus_i[active_player] == i)) { oi1 = oi_accept; goto do_accept; } d.tr.other = true; g->planet_focus_i[active_player] = i; ui_sound_play_sfx_24(); break; } } if (!flag_done) { pt = &(g->planet[g->planet_focus_i[active_player]]); ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_trans_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); ui_starmap_fill_oi_tbl_stars(&d); oi_cancel = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); if ((d.tr.other) && (pt->owner != PLAYER_NONE) && (pt->within_frange[active_player] == 1) && BOOLVEC_IS1(pt->explored, active_player) && (pt->type >= g->eto[active_player].have_colony_for) ) { oi_accept = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); uiobj_add_slider_int(258, 124, 0, trans_max, 41, 8, &d.tr.num); oi_minus = uiobj_add_mousearea(252, 124, 256, 131, MOO_KEY_MINUS); oi_plus = uiobj_add_mousearea(301, 124, 305, 131, MOO_KEY_PLUS); oi_equals = uiobj_add_mousearea(301, 124, 305, 131, MOO_KEY_EQUALS); } else if (ui_extra_enabled && !d.tr.other) { oi_minus = uiobj_add_inputkey(MOO_KEY_MINUS); oi_plus = uiobj_add_inputkey(MOO_KEY_PLUS); oi_equals = uiobj_add_inputkey(MOO_KEY_EQUALS); } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_set_help_id(-1); g->planet_focus_i[active_player] = d.from; /* We clear the UI object table because one of them contains a pointer to a local variable. */ uiobj_table_clear(); } 1oom-1.11.2/src/ui/classic/uistarmap_transport.c000066400000000000000000000335671476061725400216130ustar00rootroot00000000000000#include "config.h" #include #include "uistarmap.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "kbd.h" #include "lbxgfx.h" #include "lbxfont.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidraw.h" #include "uidefs.h" #include "uidelay.h" #include "uiobj.h" #include "uisearch.h" #include "uisound.h" #include "uistarmap_common.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void ui_starmap_transport_draw_cb(void *vptr) { struct starmap_data_s *d = vptr; const struct game_s *g = d->g; const transport_t *r = &(g->transport[ui_data.starmap.fleet_selected]); const empiretechorbit_t *e = &(g->eto[r->owner]); const planet_t *pt = &g->planet[g->planet_focus_i[d->api]]; char buf[0x80]; STARMAP_LIM_INIT(); ui_starmap_draw_basic(d); { int x, y; x = (r->x - ui_data.starmap.x) * 2 + 5; y = (r->y - ui_data.starmap.y) * 2 + 5; lbxgfx_draw_frame_offs_delay(x, y, !d->anim_delay, ui_data.gfx.starmap.shipbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); } ui_draw_filled_rect(225, 8, 314, 180, 7, ui_scale); lbxgfx_draw_frame(224, 4, ui_data.gfx.starmap.tranbord, UI_SCREEN_W, ui_scale); if (d->controllable) { lbxgfx_draw_frame(224, 159, ui_data.gfx.starmap.tranxtra, UI_SCREEN_W, ui_scale); } ui_draw_filled_rect(227, 8, 310, 39, 0, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.scanner); for (int f = 0; f <= ui_data.starmap.frame_scanner; ++f) { lbxgfx_draw_frame(227, 8, ui_data.gfx.starmap.scanner, UI_SCREEN_W, ui_scale); } lib_sprintf(buf, sizeof(buf), "%s %s", game_str_tbl_race[e->race], game_str_sm_fleet); lbxfont_select_set_12_4(5, tbl_banner_fontparam[e->banner], 0, 0); lbxfont_print_str_center(267, 10, buf, UI_SCREEN_W, ui_scale); if (d->show_planet_focus) { const planet_t *pd = &(g->planet[r->dest]); uint8_t *gfx; int x0, y0, x1, y1, dist; bool dest_ok = true; x1 = (pt->x - ui_data.starmap.x) * 2 + 8; y1 = (pt->y - ui_data.starmap.y) * 2 + 8; lbxgfx_draw_frame_offs_delay(x1, y1, !d->anim_delay, ui_data.gfx.starmap.planbord, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); x0 = (r->x - ui_data.starmap.x) * 2 + 8; y0 = (r->y - ui_data.starmap.y) * 2 + 8; if (d->controllable) { dest_ok = game_transport_dest_ok(g, pt, d->api); } { const uint8_t *ctbl; ctbl = dest_ok ? colortbl_line_green : colortbl_line_red; ui_draw_line_limit_ctbl(x0 + 4, y0 + 1, x1 + 6, y1 + 6, ctbl, 5, ui_data.starmap.line_anim_phase, starmap_scale); } if (ui_extra_enabled && ui_data.starmap.flag_show_own_routes && (r->owner == d->api)) { int x2, y2; x2 = (pd->x - ui_data.starmap.x) * 2 + 8; y2 = (pd->y - ui_data.starmap.y) * 2 + 8; ui_draw_line_limit_ctbl(x0 + 4, y0 + 1, x2 + 6, y2 + 6, colortbl_line_green, 5, ui_data.starmap.line_anim_phase, starmap_scale); } gfx = ui_data.gfx.starmap.smaltran[e->banner]; if (pd->x < r->x) { lbxgfx_set_new_frame(gfx, 1); } else { lbxgfx_set_frame_0(gfx); } lbxgfx_draw_frame_offs(x0, y0, gfx, STARMAP_LIMITS, UI_SCREEN_W, starmap_scale); dist = game_get_min_dist(g, r->owner, g->planet_focus_i[d->api]); if (d->controllable && (pt->within_frange[d->api] == 0)) { /* FIXME use proper positioning for varying str length */ d->ts.in_frange = false; lib_sprintf(buf, sizeof(buf), " %s %i %s.", game_str_sm_outsr, dist - e->fuel_range, game_str_sm_parsecs2); lbxfont_select_set_12_4(2, 0, 0, 0); lbxfont_set_gap_h(2); lbxfont_print_str_split(230, 26, 80, buf, 2, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } else { int eta = game_calc_eta_trans(g, r->speed, pt->x, pt->y, r->x, r->y); d->ts.in_frange = true; lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); lbxfont_select_set_12_4(0, 0, 0, 0); lbxfont_print_str_center(268, 32, buf, UI_SCREEN_W, ui_scale); } if (!dest_ok) { d->ts.in_frange = false; } } else { /*6a51c*/ d->ts.in_frange = false; } { int x = 228, y = 73; ui_draw_filled_rect(x, y, x + 81, y + 25, 0, ui_scale); ui_draw_stars(x, y, 0, 80, ui_scale); lbxgfx_set_frame_0(ui_data.gfx.starmap.tranship); for (int f = 0; f <= ui_data.starmap.frame_ship; ++f) { lbxgfx_draw_frame(x + 7, y + 3, ui_data.gfx.starmap.tranship, UI_SCREEN_W, ui_scale); } } lbxfont_select_set_12_4(0, 5, 0, 0); lib_sprintf(buf, sizeof(buf), "%i %s", r->pop, game_str_sm_colony); lbxfont_print_str_center(267, 48, buf, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 57, (r->pop == 1) ? game_str_sm_trans1 : game_str_sm_transs, UI_SCREEN_W, ui_scale); if (d->show_planet_focus) { const planet_t *pd = &(g->planet[r->dest]); lbxfont_select_set_12_1(5, 0, 0, 0); lbxfont_print_str_center(267, 110, game_str_sm_tdest, UI_SCREEN_W, ui_scale); lbxfont_print_str_center(267, 120, pd->name, UI_SCREEN_W, ui_scale); } if (d->controllable && (!d->ts.in_frange)) { lbxgfx_set_new_frame(ui_data.gfx.starmap.reloc_bu_accept, 1); lbxgfx_draw_frame(271, 163, ui_data.gfx.starmap.reloc_bu_accept, UI_SCREEN_W, ui_scale); } if (!d->anim_delay) { if (ui_data.starmap.scanner_delay == 0) { ui_data.starmap.frame_scanner = (ui_data.starmap.frame_scanner + 1) % 20; ++ui_data.starmap.scanner_delay; } else { ui_data.starmap.scanner_delay = 0; } ui_data.starmap.frame_ship = (ui_data.starmap.frame_ship + 1) % 5; ui_draw_set_stars_xoffs(false); } } /* -------------------------------------------------------------------------- */ static void ui_starmap_transport_set_pos_focus(const struct game_s *g, player_id_t player_i) { const transport_t *r = &g->transport[ui_data.starmap.fleet_selected]; ui_starmap_set_pos(g, r->x, r->y); } static int ui_starmap_transport_next(const struct game_s *g, player_id_t pi, int i) { const transport_t *r = &g->transport[i]; player_id_t owner = r->owner; int start = i; do { i = (i + 1) % g->transport_num; r = &g->transport[i]; if (r->owner == owner && BOOLVEC_IS1(r->visible, pi)) { return i; } } while (i != start); return g->transport_num; } static int ui_starmap_transport_prev(const struct game_s *g, player_id_t pi, int i) { const transport_t *r = &g->transport[i]; player_id_t owner = r->owner; int start = i; do { if (--i < 0) { i = g->transport_num - 1; } r = &g->transport[i]; if (r->owner == owner && BOOLVEC_IS1(r->visible, pi)) { return i; } } while (i != start); return g->transport_num; } void ui_starmap_transport(struct game_s *g, player_id_t active_player) { bool flag_done = false; int16_t oi_cancel, oi_accept, oi_search; int16_t oi_f4, oi_f5; struct starmap_data_s d; transport_t *r = &(g->transport[ui_data.starmap.fleet_selected]); ui_starmap_common_init(g, &d, active_player); d.show_planet_focus = ((r->owner == d.api) || (g->eto[d.api].have_ia_scanner)); d.set_pos_focus = ui_starmap_transport_set_pos_focus; d.ts.in_frange = false; ui_data.starmap.frame_ship = 0; ui_data.starmap.frame_scanner = 0; ui_data.starmap.scanner_delay = 0; d.from = g->planet_focus_i[active_player]; g->planet_focus_i[active_player] = r->dest; d.controllable = g->eto[active_player].have_hyperspace_comm && (r->owner == active_player); uiobj_table_clear(); #define UIOBJ_CLEAR_LOCAL() \ do { \ STARMAP_UIOBJ_CLEAR_COMMON(); \ oi_accept = UIOBJI_INVALID; \ oi_cancel = UIOBJI_INVALID; \ oi_f4 = UIOBJI_INVALID; \ oi_f5 = UIOBJI_INVALID; \ } while (0) UIOBJ_CLEAR_LOCAL(); uiobj_set_help_id(3); uiobj_set_callback_and_delay(ui_starmap_transport_draw_cb, &d, STARMAP_DELAY); while (!flag_done) { int16_t oi1, oi2; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); ui_starmap_handle_scrollkeys(&d, oi1); if (ui_starmap_handle_oi_bottom_buttons(&d, oi1)) { flag_done = true; ui_sound_play_sfx_24(); } else if (ui_starmap_handle_oi_misc(&d, oi1)) { ui_sound_play_sfx_24(); } else if (oi1 == oi_search) { ui_sound_play_sfx_24(); if (ui_search_set_pos(g, active_player)) { if (!d.controllable) { d.from = g->planet_focus_i[active_player]; flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } } } else if ((oi1 == oi_cancel) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_06(); flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } else if (oi1 == oi_f4) { int i = ui_starmap_transport_next(g, active_player, ui_data.starmap.fleet_selected); if (i != g->transport_num) { ui_data.starmap.fleet_selected = i; flag_done = true; ui_sound_play_sfx_24(); } } else if (oi1 == oi_f5) { int i = ui_starmap_transport_prev(g, active_player, ui_data.starmap.fleet_selected); if (i != g->transport_num) { ui_data.starmap.fleet_selected = i; flag_done = true; ui_sound_play_sfx_24(); } } else if (oi1 == oi_accept) { do_accept: ui_sound_play_sfx_24(); if (g->planet[g->planet_focus_i[active_player]].within_frange[active_player] != 0) { /* FIXME allows redirecting no nonexplored planets */ r->dest = g->planet_focus_i[active_player]; flag_done = true; } ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } if (!d.controllable || ui_sm_explicit_cursor_context) { for (int i = 0; i < g->enroute_num; ++i) { if (oi1 == d.oi_tbl_enroute[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_ENROUTE_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->transport_num; ++i) { if (oi1 == d.oi_tbl_transport[i]) { ui_data.starmap.fleet_selected = i; ui_data.ui_main_loop_action = UI_MAIN_LOOP_TRANSPORT_SEL; ui_sound_play_sfx_24(); flag_done = true; break; } } for (int i = 0; i < g->galaxy_stars; ++i) { for (player_id_t j = PLAYER_0; j < g->players; ++j) { if (oi1 == d.oi_tbl_pl_stars[j][i]) { g->planet_focus_i[active_player] = i; d.from = i; ui_data.starmap.orbit_player = j; ui_data.ui_main_loop_action = (j == active_player) ? UI_MAIN_LOOP_ORBIT_OWN_SEL : UI_MAIN_LOOP_ORBIT_EN_SEL; ui_sound_play_sfx_24(); flag_done = true; j = g->players; i = g->galaxy_stars; } } } } ui_starmap_handle_oi_ctrl(&d, oi1); for (int i = 0; i < g->galaxy_stars; ++i) { if (oi1 == d.oi_tbl_stars[i]) { if (ui_extra_enabled && (oi_accept != UIOBJI_INVALID) && (g->planet_focus_i[active_player] == i)) { oi1 = oi_accept; goto do_accept; } g->planet_focus_i[active_player] = i; if (!d.controllable) { d.from = i; flag_done = true; ui_data.ui_main_loop_action = UI_MAIN_LOOP_STARMAP; } break; } } if (!flag_done) { ui_starmap_common_update_mouse_hover(&d, oi2); ui_starmap_transport_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); oi_f4 = uiobj_add_inputkey(MOO_KEY_F4); oi_f5 = uiobj_add_inputkey(MOO_KEY_F5); if (!ui_sm_explicit_cursor_context || kbd_is_modifier(MOO_MOD_ALT) || !d.controllable) { ui_starmap_fill_oi_tbls(&d); ui_cursor_setup_area(2, &ui_cursor_area_tbl[3]); } else { ui_cursor_setup_area(2, &ui_cursor_area_tbl[1]); } ui_starmap_fill_oi_tbl_stars(&d); if (d.controllable) { oi_cancel = uiobj_add_t0(227, 163, "", ui_data.gfx.starmap.reloc_bu_cancel, MOO_KEY_ESCAPE); if (game_transport_dest_ok(g, &(g->planet[g->planet_focus_i[active_player]]), active_player)) { oi_accept = uiobj_add_t0(271, 163, "", ui_data.gfx.starmap.reloc_bu_accept, MOO_KEY_SPACE); } } oi_search = uiobj_add_inputkey(MOO_KEY_SLASH); ui_starmap_fill_oi_ctrl(&d); ui_starmap_add_oi_bottom_buttons(&d); ui_starmap_add_oi_misc(&d); ui_draw_finish(); ui_delay_ticks_or_click(STARMAP_DELAY); } } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); g->planet_focus_i[active_player] = d.from; } 1oom-1.11.2/src/ui/classic/uistarview.c000066400000000000000000000277271476061725400176750ustar00rootroot00000000000000#include "config.h" #include #include #include "uistarview.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "gfxaux.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" #include "util.h" /* -------------------------------------------------------------------------- */ struct starview_data_s { struct game_s *g; player_id_t api; uint8_t planet_i; uint8_t mode; int frame; bool flag_pal; uint8_t *gfx_planet; uint8_t *gfx_star; uint8_t *gfx_shield; uint8_t *gfx_pop; uint8_t *gfx_fact; uint8_t *gfx_waste; uint8_t *gfx_base; }; static void starview_load_data(struct starview_data_s *d) { const struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet_i]); d->gfx_planet = lbxfile_item_get(LBXFILE_STARVIEW, 7 + p->infogfx); d->gfx_shield = lbxfile_item_get(LBXFILE_STARVIEW, 0); { int i = p->star_type; if (i == 3) { i = 4; } else if (i == 4) { i = 3; } d->gfx_star = lbxfile_item_get(LBXFILE_STARVIEW, 1 + i); } d->gfx_pop = lbxfile_item_get(LBXFILE_STARVIEW, 0x2a); d->gfx_fact = lbxfile_item_get(LBXFILE_STARVIEW, 0x2b); d->gfx_waste = lbxfile_item_get(LBXFILE_STARVIEW, 0x2c); d->gfx_base = lbxfile_item_get(LBXFILE_STARVIEW, 0x2d); } static void starview_free_data(struct starview_data_s *d) { lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_planet); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_shield); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_star); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_pop); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_fact); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_waste); lbxfile_item_release(LBXFILE_STARVIEW, d->gfx_base); } static void starview_draw_cb(void *vptr) { struct starview_data_s *d = vptr; const struct game_s *g = d->g; const planet_t *p = &(g->planet[d->planet_i]); const seen_t *s = &(g->seen[d->api][d->planet_i]); player_id_t sowner = s->owner; char buf[0x80]; ui_draw_erase_buf(); if (p->type != PLANET_TYPE_NOT_HABITABLE) { lbxgfx_draw_frame(0, 0, d->gfx_planet, UI_SCREEN_W, ui_scale); if (!d->flag_pal) { d->flag_pal = true; lbxgfx_apply_palette(d->gfx_planet); lbxgfx_apply_palette(d->gfx_star); } } if ((p->shield != 0) && (sowner != PLAYER_NONE)) { lbxgfx_draw_frame(0, 0, d->gfx_shield, UI_SCREEN_W, ui_scale); } lbxgfx_draw_frame(212, 0, d->gfx_star, UI_SCREEN_W, ui_scale); lbxfont_select(4, 0, 0, 0); lbxfont_print_str_center(170, 2, p->name, UI_SCREEN_W, ui_scale); lbxfont_select(3, 0xb, 0, 0); lib_strcpy(buf, game_str_tbl_sm_pltype[p->type], sizeof(buf)); util_str_tolower(buf, sizeof(buf)); if (p->type != PLANET_TYPE_NOT_HABITABLE) { int l; l = strlen(buf); buf[l++] = ' '; buf[l] = '\0'; lib_strcat(&buf[l], game_str_sv_envir, sizeof(buf)); } lbxfont_print_str_center(170, 17, buf, UI_SCREEN_W, ui_scale); if (p->have_stargate) { lbxfont_select(5, 0xb, 0, 0); lbxfont_print_str_center(269, 134, game_str_sv_stargt, UI_SCREEN_W, ui_scale); } if ((sowner != PLAYER_NONE) && d->mode) { const empiretechorbit_t *e = &(g->eto[sowner]); const shipdesign_t *sd = &(g->srd[sowner].design[0]); int n = 0; lbxfont_select(0, 0x8, 0, 0); for (int i = 0; i < e->shipdesigns_num; ++i) { int ships; ships = e->orbit[d->planet_i].ships[i]; if (ships > 0) { const int sx[NUM_SHIPDESIGNS] = { 225, 175, 225, 175, 275, 125 }; const int sy[NUM_SHIPDESIGNS] = { 66, 33, 100, 66, 100, 33 }; int x, y; uint8_t *gfx; x = sx[n]; y = sy[n]; gfx = ui_data.gfx.ships[sd[i].look]; lbxgfx_set_new_frame(gfx, (d->frame + i) % 5); gfx_aux_draw_frame_to(gfx, &ui_data.aux.ship_p1); gfx_aux_draw_frame_from(x + 8, y + 8, &ui_data.aux.ship_p1, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(x + 39, y + 25, ships, UI_SCREEN_W, ui_scale); ++n; } } } if ((sowner != PLAYER_NONE) && d->mode) { if (p->shield != 0) { lib_sprintf(buf, sizeof(buf), "%s %s %s", game_str_sv_shild1, game_str_tbl_roman[p->shield], game_str_sv_shild2); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_str_normal(8, 10, buf, UI_SCREEN_W, ui_scale); } ui_draw_filled_rect(225, 144, 319, 199, 0xf0, ui_scale); ui_draw_box2(225, 144, 319, 199, 0xb3, 0xb3, 0xb3, 0xb3, ui_scale); lbxfont_select(0, 0xe, 0, 0); lbxfont_print_str_right(284, 149, game_str_sv_psize, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(284, 159, game_str_sv_fact, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(284, 169, game_str_sv_waste, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(284, 179, game_str_sv_pop, UI_SCREEN_W, ui_scale); lbxfont_print_str_right(284, 189, game_str_sv_growth, UI_SCREEN_W, ui_scale); lbxfont_select(0, 0xd, 0, 0); lbxfont_print_num_right(308, 149, p->max_pop3, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(308, 159, s->factories, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(308, 169, p->waste, UI_SCREEN_W, ui_scale); lbxfont_print_num_right(308, 179, s->pop, UI_SCREEN_W, ui_scale); if ((sowner == d->api) && (p->pop != p->pop_prev)) { lib_sprintf(buf, sizeof(buf), "%+i", p->pop - p->pop_prev); lbxfont_print_str_right(308, 189, buf, UI_SCREEN_W, ui_scale); } } else if ((p->type != PLANET_TYPE_NOT_HABITABLE) && ((p->special != PLANET_SPECIAL_NORMAL) || (p->growth != PLANET_GROWTH_NORMAL)) ) { int y0 = (p->growth != PLANET_GROWTH_NORMAL) ? 122 : 162; if (p->special != PLANET_SPECIAL_NORMAL) { const char *str0, *str1, *str2; switch (p->special) { case PLANET_SPECIAL_ULTRA_POOR: str0 = game_str_ex_ps1[0]; str2 = game_str_sv_1_3x; str1 = game_str_sv_resp; break; case PLANET_SPECIAL_POOR: str0 = game_str_ex_ps1[1]; str2 = game_str_sv_1_2x; str1 = game_str_sv_resp; break; case PLANET_SPECIAL_RICH: str0 = game_str_ex_ps1[3]; str2 = game_str_sv_2x; str1 = game_str_sv_resp; break; case PLANET_SPECIAL_ULTRA_RICH: str0 = game_str_ex_ps1[4]; str2 = game_str_sv_3x; str1 = game_str_sv_resp; break; case PLANET_SPECIAL_ARTIFACTS: str0 = game_str_ex_ps1[2]; str2 = game_str_sv_2x; str1 = game_str_sv_techp; break; case PLANET_SPECIAL_4XTECH: str0 = game_str_ex_ps1[2]; str2 = game_str_sv_4x; str1 = game_str_sv_techp; break; default: str0 = 0; str2 = 0; str1 = 0; break; } lib_sprintf(buf, sizeof(buf), "%s:", str0); lbxfont_select_set_12_4(5, 0xd, 0, 0); lbxfont_print_str_normal(8, y0, buf, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %s", str1, str2); lbxfont_select_set_12_4(5, 0xa, 0, 0); lbxfont_print_str_split(80, y0, 110, buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } if (p->growth != PLANET_GROWTH_NORMAL) { int i = p->growth; if (i > PLANET_GROWTH_NORMAL) { --i; } y0 = 162; lib_sprintf(buf, sizeof(buf), "%s:", game_str_sv_pg1[i]); lbxfont_select_set_12_4(5, 0xd, 0, 0); lbxfont_print_str_normal(8, y0, buf, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %s", game_str_sv_popgr, game_str_sv_pg2[i]); lbxfont_select_set_12_4(5, 0xa, 0, 0); lbxfont_print_str_split(80, y0, 110, buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); } } if ((sowner != PLAYER_NONE) && d->mode) { int v10, v12, v14, y0 = 184; v12 = (s->pop + 9) / 10; v10 = (v12 + 9) / 10; for (int i = 0; i < v10; ++i) { if (i == (v10 - 1)) { v14 = v12 - (v10 - 1) * 10; } else { v14 = 10; } for (int j = 0; j < v14; ++j) { lbxgfx_draw_frame(j * 18 + (i & 1) * 9 + 5, y0 - (v10 - 1 - i) * 5, d->gfx_pop, UI_SCREEN_W, ui_scale); } } y0 -= v10 * 5 + 10; v12 = (MIN(s->factories, 1200) + 9) / 10; v10 = (v12 + 9) / 10; for (int i = 0; i < v10; ++i) { if (i == (v10 - 1)) { v14 = v12 - (v10 - 1) * 10; } else { v14 = 10; } for (int j = 0; j < v14; ++j) { lbxgfx_draw_frame(j * 18 + (i & 1) * 9 + 5, y0 - (v10 - 1 - i) * 5, d->gfx_fact, UI_SCREEN_W, ui_scale); } } y0 -= v10 * 5 + 10; v12 = (MIN(s->bases, 300) + 4) / 5; v10 = (v12 + 9) / 10; for (int i = 0; i < v10; ++i) { if (i == (v10 - 1)) { v14 = v12 - (v10 - 1) * 10; } else { v14 = 10; } for (int j = 0; j < v14; ++j) { lbxgfx_draw_frame(j * 14 + (i & 1) * 7 + 5, y0 - (v10 - 1 - i) * 5, d->gfx_base, UI_SCREEN_W, ui_scale); } } y0 -= v10 * 5 + 10; v12 = (MIN(p->waste, 200) + 9) / 10; v10 = (v12 + 9) / 10; for (int i = 0; i < v10; ++i) { if (i == (v10 - 1)) { v14 = v12 - (v10 - 1) * 10; } else { v14 = 10; } for (int j = 0; j < v14; ++j) { lbxgfx_draw_frame(j * 18 + (i & 1) * 9 + 5, y0 - (v10 - 1 - i) * 5, d->gfx_waste, UI_SCREEN_W, ui_scale); } } } d->frame = (d->frame + 1) % 5; } /* -------------------------------------------------------------------------- */ void ui_starview(struct game_s *g, player_id_t pi) { struct starview_data_s d; bool flag_done = false; int16_t oi_mode; d.g = g; d.api = pi; d.planet_i = g->planet_focus_i[pi]; d.mode = (g->planet[d.planet_i].owner == PLAYER_NONE) ? 0 : 1; d.frame = 0; d.flag_pal = false; ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; lbxpal_select(5, -1, 0); starview_load_data(&d); uiobj_set_callback_and_delay(starview_draw_cb, &d, 4); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_UNKNOWN); oi_mode = ui_extra_enabled ? uiobj_add_inputkey(MOO_KEY_i) : UIOBJI_INVALID; uiobj_set_help_id(34); uiobj_set_downcount(1); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi == oi_mode) { d.mode = (d.mode + 1) % 2; } else if (oi != 0) { flag_done = true; } if (!flag_done) { starview_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(3); } } ui_sound_play_sfx_24(); ui_delay_1(); uiobj_unset_callback(); uiobj_table_clear(); ui_palette_fadeout_a_f_1(); ui_draw_finish_mode = 2; lbxpal_select(0, -1, 0); uiobj_set_help_id(-1); starview_free_data(&d); } 1oom-1.11.2/src/ui/classic/uistarview.h000066400000000000000000000002741476061725400176660ustar00rootroot00000000000000#ifndef INC_1OOM_UISTARVIEW_H #define INC_1OOM_UISTARVIEW_H #include "game_types.h" #include "types.h" struct game_s; extern void ui_starview(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiswitch.c000066400000000000000000000132531476061725400173170ustar00rootroot00000000000000#include "config.h" #include #include "uiswitch.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "types.h" #include "ui.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ struct switch_data_s { struct game_s *g; player_id_t tbl_pi[PLAYER_NUM]; int num_pi; int bottom_highlight; bool allow_opts; }; static void switch_draw_cb(void *vptr) { struct switch_data_s *d = vptr; struct game_s *g = d->g; void *ctx; char buf[32]; ui_draw_erase_buf(); lbxgfx_draw_frame(0, 0, ui_data.gfx.starmap.mainview, UI_SCREEN_W, ui_scale); ctx = ui_gmap_basic_init(g, true); ui_gmap_basic_draw_frame(ctx, -1); lbxfont_select(3, 2, 0, 0); lbxfont_print_num_normal(230, 16, g->year + YEAR_BASE, UI_SCREEN_W, ui_scale); for (int i = 0; i < d->num_pi; ++i) { empiretechorbit_t *e; player_id_t pi; uint8_t color; pi = d->tbl_pi[i]; e = &(g->eto[pi]); color = tbl_banner_fontparam[e->banner]; lbxfont_select(3, color, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %i", game_str_player, pi + 1); lbxfont_print_str_normal(230, i * 24 + 32, buf, UI_SCREEN_W, ui_scale); lbxfont_select(0, color, 0, 0); lbxfont_print_str_normal(230, i * 24 + 32 + 10, g->emperor_names[pi], UI_SCREEN_W, ui_scale); } if (d->allow_opts) { lbxfont_select_set_12_4(5, (d->bottom_highlight == 0) ? 0 : 2, 0, 0); lbxfont_print_str_normal(10, 184, game_str_sm_game, UI_SCREEN_W, ui_scale); } ui_gmap_basic_shutdown(ctx); } static bool ui_switch(struct game_s *g, player_id_t *tbl_pi, int num_pi, bool allow_opts) { struct switch_data_s d; bool flag_done = false, flag_opts = false; int16_t oi_ma = UIOBJI_INVALID, oi_gameopts = UIOBJI_INVALID; d.g = g; d.num_pi = num_pi; d.bottom_highlight = -1; d.allow_opts = allow_opts; for (int i = 0; i < num_pi; ++i) { d.tbl_pi[i] = tbl_pi[i]; } ui_delay_1(); ui_sound_stop_music(); /* or fade? */ uiobj_set_downcount(1); ui_cursor_setup_area(1, &ui_cursor_area_tbl[0]); uiobj_table_clear(); uiobj_set_callback_and_delay(switch_draw_cb, &d, 1); while (!flag_done) { int16_t oi1, oi2; oi1 = uiobj_handle_input_cond(); oi2 = uiobj_at_cursor(); ui_delay_prepare(); if ((oi1 == oi_ma) || (oi1 == UIOBJI_ESC)) { ui_sound_play_sfx_24(); flag_done = true; } else if (oi1 == oi_gameopts) { ui_sound_play_sfx_24(); flag_done = true; flag_opts = true; } d.bottom_highlight = -1; if (oi2 == oi_gameopts) { d.bottom_highlight = 0; } if (!flag_done) { switch_draw_cb(&d); uiobj_table_clear(); if (allow_opts) { oi_gameopts = uiobj_add_mousearea(5, 181, 36, 194, MOO_KEY_g); } oi_ma = uiobj_add_mousearea_all(MOO_KEY_SPACE); ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); return flag_opts; } /* -------------------------------------------------------------------------- */ bool ui_switch_1_opts(struct game_s *g, player_id_t pi) { BOOLVEC_DECLARE(viewing, PLAYER_NUM); if ((g->gaux->local_players <= 1) || IS_AI(g, pi)) { return false; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); BOOLVEC_SET1(viewing, pi); if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); return ui_switch(g, &pi, 1, true); } return false; } void ui_switch_1(struct game_s *g, player_id_t pi) { BOOLVEC_DECLARE(viewing, PLAYER_NUM); if ((g->gaux->local_players <= 1) || IS_AI(g, pi)) { return; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); BOOLVEC_SET1(viewing, pi); if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, &pi, 1, false); } } bool ui_switch_2(struct game_s *g, player_id_t pi1, player_id_t pi2) { player_id_t tbl[2]; int n = 0; BOOLVEC_DECLARE(viewing, PLAYER_NUM); if (g->gaux->local_players <= 1) { return false; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); if (IS_HUMAN(g, pi1) && IS_ALIVE(g, pi1)) { BOOLVEC_SET1(viewing, pi1); tbl[n++] = pi1; } if (IS_HUMAN(g, pi2) && IS_ALIVE(g, pi2)) { BOOLVEC_SET1(viewing, pi2); tbl[n++] = pi2; } if ((n == 2) && (pi1 > pi2)) { tbl[0] = pi2; tbl[1] = pi1; } if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, tbl, n, false); return true; } return false; } void ui_switch_all(struct game_s *g) { player_id_t tbl[PLAYER_NUM]; int n = 0; BOOLVEC_DECLARE(viewing, PLAYER_NUM); if (g->gaux->local_players <= 1) { return; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (IS_HUMAN(g, pi) && IS_ALIVE(g, pi)) { tbl[n++] = pi; } } if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, tbl, n, false); } } 1oom-1.11.2/src/ui/classic/uiswitch.h000066400000000000000000000005621476061725400173230ustar00rootroot00000000000000#ifndef INC_1OOM_UISWITCH_H #define INC_1OOM_UISWITCH_H #include "game_types.h" #include "types.h" struct game_s; extern bool ui_switch_1_opts(struct game_s *g, player_id_t pi); extern void ui_switch_1(struct game_s *g, player_id_t pi); extern bool ui_switch_2(struct game_s *g, player_id_t pi1, player_id_t pi2); extern void ui_switch_all(struct game_s *g); #endif 1oom-1.11.2/src/ui/classic/uitech.c000066400000000000000000000404161476061725400167420ustar00rootroot00000000000000#include "config.h" #include #include "uitech.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_str.h" #include "game_tech.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lbxpal.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicursor.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uiobj.h" #include "uipal.h" #include "uisound.h" /* -------------------------------------------------------------------------- */ #define TECH_ON_SCREEN 16 #define TECH_SCROLL_NUM 12 struct tech_data_s { struct game_s *g; player_id_t api; uint8_t *gfx; int8_t completed[TECH_PER_FIELD + 3]; tech_field_t field; int num; int pos; int selected; }; static void tech_load_data(struct tech_data_s *d) { d->gfx = lbxfile_item_get(LBXFILE_BACKGRND, 4); } static void tech_free_data(struct tech_data_s *d) { lbxfile_item_release(LBXFILE_BACKGRND, d->gfx); } static void ui_tech_build_completed(struct tech_data_s *d) { const techdata_t *t = &(d->g->eto[d->api].tech); tech_field_t field = d->field; const uint8_t *q = d->g->srd[d->api].researchcompleted[field]; int num = t->completed[field]; int8_t *p = d->completed; if (field == TECH_FIELD_WEAPON) { *p++ = -2; *p++ = -1; } for (int i = 0; i < num; ++i) { *p++ = *q++; } if (field == TECH_FIELD_WEAPON) { num += 2; } if (t->project[field]) { *p++ = t->project[field]; num++; } d->num = num; } static void tech_slider_cb(void *ctx, uint8_t i, int16_t value) { struct tech_data_s *d = ctx; struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); techdata_t *t = &(e->tech); if (!t->slider_lock[i]) { game_adjust_slider_group(t->slider, i, t->slider[i], TECH_FIELD_NUM, t->slider_lock); } } static void tech_draw_cb(void *vptr) { struct tech_data_s *d = vptr; const struct game_s *g = d->g; const empiretechorbit_t *e = &(g->eto[d->api]); const techdata_t *t = &(e->tech); char buf[0xe0]; ui_draw_color_buf(0x3a); ui_draw_filled_rect(3, 150, 275, 196, 0x5b, ui_scale); ui_draw_filled_rect(5, 4, 53, 15, (d->field == 0) ? 0x89 : 0xc0, ui_scale); ui_draw_filled_rect(55, 4, 108, 15, (d->field == 1) ? 0x89 : 0xc0, ui_scale); ui_draw_filled_rect(109, 4, 161, 16, (d->field == 2) ? 0x89 : 0xc0, ui_scale); ui_draw_filled_rect(5, 19, 54, 31, (d->field == 3) ? 0x89 : 0xc0, ui_scale); ui_draw_filled_rect(55, 19, 108, 31, (d->field == 4) ? 0x89 : 0xc0, ui_scale); ui_draw_filled_rect(109, 19, 161, 31, (d->field == 5) ? 0x89 : 0xc0, ui_scale); for (int i = 0; i < TECH_FIELD_NUM; ++i) { int y; y = 21 * i + 22; ui_draw_filled_rect(168, y, 218, y + 8, t->slider_lock[i] ? 0x24 : 0xbc, ui_scale); } ui_draw_filled_rect(7, 36, 154, 147, 0, ui_scale); lbxgfx_draw_frame(7, 36, ui_data.gfx.screens.techback, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(0, 0, d->gfx, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%i %s", e->total_research_bc, game_str_bc); lbxfont_select(2, 6, 0, 0); lbxfont_print_str_right(309, 169, buf, UI_SCREEN_W, ui_scale); for (int i = 0; i < TECH_ON_SCREEN; ++i) { if ((i + d->pos) < d->num) { uint8_t a2; if (i == d->selected) { a2 = 0; } else if (((i + d->pos) == (d->num - 1)) && t->project[d->field]) { a2 = 5; } else { a2 = 1; } lbxfont_select(2, a2, 0, 0); game_tech_get_name(g->gaux, d->field, d->completed[i + d->pos], buf, sizeof(buf)); lbxfont_print_str_normal(9, 37 + i * 7, buf, UI_SCREEN_W, ui_scale); } } game_tech_get_descr(g->gaux, d->field, d->completed[d->selected + d->pos], buf, sizeof(buf)); lbxfont_select(5, 6, 0, 0); lbxfont_set_gap_h(1); lbxfont_print_str_split(10, 155, 260, buf, 0, UI_SCREEN_W, UI_SCREEN_H, ui_scale); lbxgfx_set_new_frame(ui_data.gfx.screens.tech_but_up, 1); lbxgfx_set_new_frame(ui_data.gfx.screens.tech_but_down, 1); lbxgfx_draw_frame(157, 35, ui_data.gfx.screens.tech_but_up, UI_SCREEN_W, ui_scale); lbxgfx_draw_frame(157, 141, ui_data.gfx.screens.tech_but_down, UI_SCREEN_W, ui_scale); for (int i = 0; i < TECH_FIELD_NUM; ++i) { int y; y = 21 * i + 24; ui_draw_filled_rect(227, y, 277, y + 3, 0x2f, ui_scale); if (t->slider[i]) { ui_draw_slider(227, y + 1, t->slider[i], 2, -1, t->slider_lock[i] ? 0x22 : 0x73, ui_scale); } lbxfont_select(0, 6, 0, 0); lbxfont_set_color_c_n((g->gaux->flag_cheat_tech_hint && game_tech_current_research_has_max_bonus(g, d->api, i)) ? 0x41 : 0x26, 5); lbxfont_print_num_right(307, y, t->percent[i], UI_SCREEN_W, ui_scale); } lbxfont_select(2, 6, 0, 0); lib_sprintf(buf, sizeof(buf), "%s %i, %s %i/%s", game_str_te_scrange, e->scanner_range, game_str_te_rctrl, e->colonist_oper_factories, game_str_te_col); lbxfont_print_str_normal(168, 33, buf, UI_SCREEN_W, ui_scale); { uint8_t groundcmbonus = 0, groundcmbonus2 = 0; for (int i = 0; i < t->completed[TECH_FIELD_CONSTRUCTION]; ++i) { uint8_t c, tier; tech_group_t group; c = g->srd[d->api].researchcompleted[TECH_FIELD_CONSTRUCTION][i]; group = game_tech_get_group(g->gaux, TECH_FIELD_CONSTRUCTION, c); tier = game_tech_get_tier(g->gaux, TECH_FIELD_CONSTRUCTION, c); if (group == TECH_GROUP_ARMOR) { groundcmbonus = tier * 5; } else if (group == TECH_GROUP_PERSONAL_ARMOR) { groundcmbonus2 = tier * 10; } } groundcmbonus += groundcmbonus2; lib_sprintf(buf, sizeof(buf), "%s %i, %s +%i%%", game_str_te_fwaste, e->ind_waste_scale, game_str_te_gcombat, groundcmbonus); lbxfont_print_str_normal(168, 54, buf, UI_SCREEN_W, ui_scale); } { uint8_t groundcmbonus = 0; for (int i = 0; i < t->completed[TECH_FIELD_FORCE_FIELD]; ++i) { uint8_t c, tier; tech_group_t group; c = g->srd[d->api].researchcompleted[TECH_FIELD_FORCE_FIELD][i]; group = game_tech_get_group(g->gaux, TECH_FIELD_FORCE_FIELD, c); tier = game_tech_get_tier(g->gaux, TECH_FIELD_FORCE_FIELD, c); if (group == TECH_GROUP_PERSONAL_SHIELD) { groundcmbonus = tier * 10; } } lib_sprintf(buf, sizeof(buf), "%s +%i%%", game_str_te_gcombat, groundcmbonus); lbxfont_print_str_normal(168, 75, buf, UI_SCREEN_W, ui_scale); } lib_sprintf(buf, sizeof(buf), "%s +%i, %s %i/%s", game_str_te_tform, e->have_terraform_n, game_str_te_wasteel, e->have_eco_restoration_n, game_str_bc); lbxfont_print_str_normal(168, 96, buf, UI_SCREEN_W, ui_scale); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_te_shrange, e->fuel_range, game_str_sm_parsecs2); lbxfont_print_str_normal(168, 117, buf, UI_SCREEN_W, ui_scale); { uint8_t groundcmbonus = 0; for (int i = 0; i < t->completed[TECH_FIELD_WEAPON]; ++i) { uint8_t c, tier; tech_group_t group; c = g->srd[d->api].researchcompleted[TECH_FIELD_WEAPON][i]; group = game_tech_get_group(g->gaux, TECH_FIELD_WEAPON, c); tier = game_tech_get_tier(g->gaux, TECH_FIELD_WEAPON, c); if (group == TECH_GROUP_PERSONAL_WEAPONS) { groundcmbonus = tier * 5; } } lib_sprintf(buf, sizeof(buf), "%s +%i%%", game_str_te_gcombat, groundcmbonus); lbxfont_print_str_normal(168, 138, buf, UI_SCREEN_W, ui_scale); } for (int i = 0; i < TECH_FIELD_NUM; ++i) { int y; y = 21 * i + 21; if ((t->percent[i] < 99) || (t->project[i] != 0)) { /* WASBUG MOO1 has no project check and shows MAX early */ int complpercent; complpercent = game_tech_current_research_percent2(g, d->api, i); if (complpercent > 0) { lib_sprintf(buf, sizeof(buf), "%i%%", complpercent); lbxfont_select_set_12_1(2, 0xd, 0, 0); lbxfont_print_str_right(295, y + 3, buf, UI_SCREEN_W, ui_scale); } else { int y0, y1; complpercent = game_tech_current_research_percent1(g, d->api, i); lbxgfx_draw_frame(287, y, ui_data.gfx.screens.litebulb_off, UI_SCREEN_W, ui_scale); y0 = y + (8 - (complpercent * 4) / 50); y1 = y + 7; lbxgfx_draw_frame_offs(287, y, ui_data.gfx.screens.litebulb_on, 0, y0, UI_SCREEN_W - 1, y1, UI_SCREEN_W, ui_scale); } } else { lbxfont_select_set_12_1(2, 0xd, 0, 0); lbxfont_print_str_right(295, y + 3, game_str_te_max, UI_SCREEN_W, ui_scale); } } } /* -------------------------------------------------------------------------- */ void ui_tech(struct game_s *g, player_id_t active_player) { struct tech_data_s d; bool flag_done = false; int16_t oi_ok, oi_up, oi_down, oi_equals, oi_wheel, oi_hash, oi_tbl_lock[TECH_FIELD_NUM], oi_tbl_plus[TECH_FIELD_NUM], oi_tbl_minus[TECH_FIELD_NUM], oi_tbl_bonus[TECH_FIELD_NUM], oi_tbl_field[TECH_FIELD_NUM], oi_tbl_techname[TECH_ON_SCREEN] ; int16_t scroll = 0; techdata_t *t = &(g->eto[active_player].tech); d.g = g; d.api = active_player; tech_load_data(&d); game_update_production(g); game_update_total_research(g); #define UIOBJ_CLEAR_LOCAL() \ do { \ oi_ok = UIOBJI_INVALID; \ oi_up = UIOBJI_INVALID; \ oi_down = UIOBJI_INVALID; \ oi_equals = UIOBJI_INVALID; \ oi_wheel = UIOBJI_INVALID; \ oi_hash = UIOBJI_INVALID; \ UIOBJI_SET_TBL5_INVALID(oi_tbl_lock, oi_tbl_plus, oi_tbl_minus, oi_tbl_bonus, oi_tbl_field); \ UIOBJI_SET_TBL_INVALID(oi_tbl_techname); \ } while (0) UIOBJ_CLEAR_LOCAL(); d.field = TECH_FIELD_COMPUTER; ui_tech_build_completed(&d); d.pos = d.num - TECH_ON_SCREEN; SETMAX(d.pos, 0); d.selected = d.num - 1 - d.pos; uiobj_set_help_id(13); uiobj_set_callback_and_delay(tech_draw_cb, &d, 1); uiobj_table_clear(); while (!flag_done) { int16_t oi; oi = uiobj_handle_input_cond(); ui_delay_prepare(); if ((oi == oi_ok) || (oi == UIOBJI_ESC)) { ui_sound_play_sfx_24(); flag_done = true; } else if (oi == oi_up) { ui_sound_play_sfx_24(); d.pos -= TECH_SCROLL_NUM; } else if (oi == oi_down) { ui_sound_play_sfx_24(); d.pos += TECH_SCROLL_NUM; } else if (oi == oi_wheel) { d.pos += scroll; scroll = 0; } for (int i = 0; i < TECH_FIELD_NUM; ++i) { if (oi == oi_tbl_field[i]) { ui_sound_play_sfx_24(); d.field = i; ui_tech_build_completed(&d); d.pos = d.num - TECH_ON_SCREEN; SETMAX(d.pos, 0); d.selected = d.num - 1 - d.pos; } else if (oi == oi_tbl_lock[i]) { ui_sound_play_sfx_24(); t->slider_lock[i] ^= 1; } else if (oi == oi_tbl_minus[i]) { int16_t v; ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_ALT)) { v = 0; t->slider[i] = 0; } else if (kbd_is_modifier(MOO_MOD_CTRL)) { v = t->slider[i]; v -= 10; SETMAX(v, 0); t->slider[i] = v; } else { v = t->slider[i]; v -= 2; SETMAX(v, 0); t->slider[i] = v; } game_adjust_slider_group(t->slider, i, v, TECH_FIELD_NUM, t->slider_lock); } else if (oi == oi_tbl_plus[i]) { int16_t v; ui_sound_play_sfx_24(); if (kbd_is_modifier(MOO_MOD_ALT)) { v = 100; t->slider[i] = 100; } else if (kbd_is_modifier(MOO_MOD_CTRL)) { v = t->slider[i]; v += 10; SETMIN(v, 100); t->slider[i] = v; } else { v = t->slider[i]; v += 2; SETMIN(v, 100); t->slider[i] = v; } game_adjust_slider_group(t->slider, i, v, TECH_FIELD_NUM, t->slider_lock); } else if (oi == oi_tbl_bonus[i]) { ui_sound_play_sfx_24(); game_tech_set_to_max_bonus(g, active_player, i); } } for (int i = 0; i < TECH_ON_SCREEN; ++i) { if (oi == oi_tbl_techname[i]) { ui_sound_play_sfx_24(); d.selected = i; } } if (oi == oi_equals || oi == oi_hash) { ui_sound_play_sfx_24(); if (ui_fixbugs_enabled) { game_equalize_slider_group(t->slider, TECH_FIELD_NUM, t->slider_lock); } else { t->slider[0] = 16; t->slider[1] = 17; t->slider[2] = 17; t->slider[3] = 16; t->slider[4] = 17; t->slider[5] = 17; } } if ((d.pos + TECH_ON_SCREEN) >= d.num) { d.pos = d.num - TECH_ON_SCREEN; } SETMAX(d.pos, 0); if ((d.selected + d.pos) >= d.num) { d.selected = d.num - d.pos; } SETMAX(d.pos, 0); if (!flag_done) { tech_draw_cb(&d); uiobj_table_clear(); UIOBJ_CLEAR_LOCAL(); if (d.num >= TECH_ON_SCREEN) { if (d.pos > 0) { oi_up = uiobj_add_t0(157, 35, "", ui_data.gfx.screens.tech_but_up, MOO_KEY_COMMA); } if ((d.pos + TECH_ON_SCREEN) < d.num) { oi_down = uiobj_add_t0(157, 141, "", ui_data.gfx.screens.tech_but_down, MOO_KEY_PERIOD); } } oi_ok = uiobj_add_t0(277, 181, "", ui_data.gfx.screens.tech_but_ok, MOO_KEY_SPACE); oi_tbl_field[0] = uiobj_add_mousearea(5, 4, 53, 15, MOO_KEY_1); oi_tbl_field[1] = uiobj_add_mousearea(55, 4, 108, 15, MOO_KEY_2); oi_tbl_field[2] = uiobj_add_mousearea(109, 4, 161, 16, MOO_KEY_3); oi_tbl_field[3] = uiobj_add_mousearea(5, 19, 54, 31, MOO_KEY_4); oi_tbl_field[4] = uiobj_add_mousearea(55, 19, 108, 31, MOO_KEY_5); oi_tbl_field[5] = uiobj_add_mousearea(109, 19, 161, 31, MOO_KEY_6); oi_equals = uiobj_add_inputkey(MOO_KEY_EQUALS); oi_hash = uiobj_add_inputkey(MOO_KEY_HASH); for (int i = 0; i < TECH_FIELD_NUM; ++i) { int y; y = i * 21 + 22; oi_tbl_lock[i] = uiobj_add_mousearea(168, y, 218, y + 8, (d.field == i) ? MOO_KEY_l : MOO_KEY_UNKNOWN); if (g->gaux->flag_cheat_tech_hint) { oi_tbl_bonus[i] = uiobj_add_mousearea(298, y, 309, y + 8, MOO_KEY_UNKNOWN); } if (!t->slider_lock[i]) { oi_tbl_minus[i] = uiobj_add_mousearea(223, y, 226, y + 8, (d.field == i) ? MOO_KEY_MINUS : MOO_KEY_UNKNOWN); oi_tbl_plus[i] = uiobj_add_mousearea(279, y, 283, y + 8, (d.field == i) ? MOO_KEY_PLUS : MOO_KEY_UNKNOWN); uiobj_add_slider_func(227, y, 0, 100, 50, 9, &t->slider[i], tech_slider_cb, &d, i); } } for (int i = 0; i < TECH_ON_SCREEN; ++i) { if ((i + d.pos) < d.num) { oi_tbl_techname[i] = uiobj_add_mousearea(9, i * 7 + 37, 160, i * 7 + 43, MOO_KEY_UNKNOWN); } } if (d.num >= TECH_ON_SCREEN) { oi_wheel = uiobj_add_mousewheel(0, 0, 167, 199, &scroll); } ui_draw_finish(); ui_delay_ticks_or_click(1); } } uiobj_unset_callback(); uiobj_table_clear(); uiobj_set_help_id(-1); tech_free_data(&d); } 1oom-1.11.2/src/ui/classic/uitech.h000066400000000000000000000002351476061725400167420ustar00rootroot00000000000000#ifndef INC_1OOM_UITECH_H #define INC_1OOM_UITECH_H #include "game_types.h" struct game_s; extern void ui_tech(struct game_s *g, player_id_t pi); #endif 1oom-1.11.2/src/ui/classic/uiturn.c000066400000000000000000000037251476061725400170110ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "hw.h" #include "kbd.h" #include "lbx.h" #include "lbxfont.h" #include "lbxgfx.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidelay.h" #include "uidefs.h" #include "uidraw.h" #include "uigmap.h" #include "uiobj.h" #include "uisound.h" #include "uistarmap_common.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct turnmsg_data_s { struct game_s *g; player_id_t api; const char *str; struct starmap_data_s sm; }; static void ui_turn_msg_draw_cb(void *vptr) { struct turnmsg_data_s *d = vptr; ui_starmap_draw_basic(&d->sm); ui_draw_textbox_2str("", d->str, 74, ui_scale); } /* -------------------------------------------------------------------------- */ void ui_turn_pre(const struct game_s *g) { struct starmap_data_s d; ui_starmap_draw_button_text(&d, false); hw_video_copy_back_to_page2(); } void ui_turn_msg(struct game_s *g, int pi, const char *str) { struct turnmsg_data_s d; bool flag_done = false; int tempnum; ui_switch_1(g, pi); tempnum = g->evn.build_finished_num[pi]; g->evn.build_finished_num[pi] = 0; d.g = g; d.api = pi; d.str = str; ui_starmap_common_init(g, &d.sm, pi); d.sm.bottom_highlight = -1; uiobj_set_callback_and_delay(ui_turn_msg_draw_cb, &d, 3); uiobj_table_clear(); uiobj_add_mousearea_all(MOO_KEY_SPACE); while (!flag_done) { int16_t oi; ui_delay_prepare(); oi = uiobj_handle_input_cond(); if (oi != 0) { flag_done = true; } ui_turn_msg_draw_cb(&d); ui_draw_finish(); ui_delay_ticks_or_click(3); } uiobj_unset_callback(); uiobj_table_clear(); ui_sound_play_sfx_24(); ui_delay_1(); g->evn.build_finished_num[pi] = tempnum; } 1oom-1.11.2/src/ui/cmdline/000077500000000000000000000000001476061725400153025ustar00rootroot000000000000001oom-1.11.2/src/ui/cmdline/Makefile.am000066400000000000000000000020011476061725400173270ustar00rootroot00000000000000AM_CPPFLAGS = \ -I$(top_srcdir)/src/game \ -I$(top_srcdir)/src noinst_LIBRARIES = libuicmdline.a libuicmdline_a_SOURCES = \ uiaudience.c \ uibattle.c \ uibomb.c \ uicheat.c \ uicheat.h \ uicmdline.c \ uicmds.c \ uicmds.h \ uidefs.h \ uidesign.c \ uidesign.h \ uielection.c \ uiempire.c \ uiempire.h \ uiempirereport.c \ uiempirereport.h \ uiempirestats.c \ uiempirestats.h \ uiending.c \ uiexplore.c \ uifinished.c \ uifinished.h \ uifleet.c \ uifleet.h \ uigame.c \ uigmap.c \ uiground.c \ uihelp.c \ uihelp.h \ uiinput.c \ uiinput.h \ uiintro.c \ uiload.c \ uiload.h \ uimainmenu.c \ uinews.c \ uinewtech.c \ uiplanet.c \ uiplanet.h \ uiraces.c \ uiraces.h \ uisave.c \ uisave.h \ uispecs.c \ uispecs.h \ uispy_esp.c \ uispy_sab.c \ uiswitch.c \ uiswitch.h \ uitech.c \ uitech.h \ uiview.c \ uiview.h 1oom-1.11.2/src/ui/cmdline/uiaudience.c000066400000000000000000000052641476061725400175700ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_audience.h" #include "game_str.h" #include "types.h" #include "uidefs.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ static void ui_audience_show(struct audience_s *au) { const struct game_s *g = au->g; const char *mood[] = { " :)", ">:(", " :V" }; int moodi; switch (au->gfxi) { default: case 0: moodi = 2; break; case 3: moodi = 0; break; case 4: moodi = 1; break; } printf("Audience | %s | %s | %s\n", game_str_tbl_race[g->eto[au->pa].race], mood[moodi], au->buf); } static int16_t ui_audience_ask(struct audience_s *au) { struct input_list_s rl_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 4, "5", NULL, NULL }, { 5, "6", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; int num = 0; for (int i = 0; i < (AUDIENCE_STR_MAX - 1); ++i) { if (au->strtbl[i]) { if ((!au->condtbl) || au->condtbl[i]) { rl_in[num].value = i; rl_in[num].display = au->strtbl[i] + 2 /* skip "[ " */; ++num; } } else { break; } } rl_in[num].value = 0; rl_in[num].key = NULL; rl_in[num].str = NULL; rl_in[num].display = NULL; ui_audience_show(au); return ui_input_list(NULL, "> ", rl_in); } /* -------------------------------------------------------------------------- */ void ui_audience_start(struct audience_s *au) { ui_switch_2(au->g, au->ph, au->pa); } void ui_audience_show1(struct audience_s *au) { ui_audience_show(au); } void ui_audience_show2(struct audience_s *au) { ui_audience_show(au); } void ui_audience_show3(struct audience_s *au) { ui_audience_show(au); } int16_t ui_audience_ask2a(struct audience_s *au) { return ui_audience_ask(au); } int16_t ui_audience_ask2b(struct audience_s *au) { return ui_audience_ask(au); } int16_t ui_audience_ask3(struct audience_s *au) { return ui_audience_ask(au); } int16_t ui_audience_ask4(struct audience_s *au) { return ui_audience_ask(au); } void ui_audience_newtech(struct audience_s *au, int pi) { if (pi == PLAYER_NONE) { ui_newtech(au->g, au->ph); ui_newtech(au->g, au->pa); } else { ui_newtech(au->g, pi); } ui_switch_2(au->g, au->ph, au->pa); } void ui_audience_end(struct audience_s *au) { ui_switch_1(au->g, au->ph); } 1oom-1.11.2/src/ui/cmdline/uibattle.c000066400000000000000000000451241476061725400172650ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_aux.h" #include "game_battle.h" #include "game_battle_human.h" #include "game_str.h" #include "lib.h" #include "uicmds.h" #include "uidefs.h" #include "uihelp.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ static const char battlegfx[][3][5] = { { " ", " > ", " " }, { " ", " |> ", " " }, { " \\ ", " >> ", " / " }, { "=\\ ", "|O> ", "=/ " }, { " ", " < ", " " }, { " ", " <| ", " " }, { " / ", " << ", " \\ " }, { " /=", " area[sy][sx]; if ((sv == 1) || (sv >= 30)) { int tx, ty; tx = sx * 4 + 3; ty = sy * 3; for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx < 4; ++dx) { char c; c = ui_data.battle.screen[ty + dy][tx + dx]; if (c == ' ') { ui_data.battle.screen[ty + dy][tx + dx] = '.'; } } } } } } } static void ui_battle_prepost(const struct battle_s *bt, int winner) { shipsum_t force[2][SHIP_HULL_NUM]; game_battle_count_hulls(bt, force); for (int i = 0; i < SHIP_HULL_NUM; ++i) { printf("- %5u %s %u\n", force[SIDE_L][i], game_str_tbl_st_hull[i], force[SIDE_R][i]); } if (bt->bases) { printf("- %s %u\n", game_str_sb_bases, bt->bases); } if (winner != SIDE_NONE) { int party_winner = (winner != SIDE_NONE) ? bt->s[winner].party : -1; const char *str; if (party_winner >= PLAYER_NUM) { str = game_str_tbl_mon_names[party_winner - PLAYER_NUM]; } else { race_t race = bt->g->eto[party_winner].race; str = game_str_tbl_races[race]; } printf("%s %s\n", str, game_str_bp_won); } } static void ui_battle_draw_scan_weap(const struct battle_item_s *b, int wi, char *buf, size_t bufsize) { if (b->wpn[wi].n != 0) { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[wi].t]); struct strbuild_s str = strbuild_init(buf, bufsize); strbuild_catf(&str, "%i x %s", b->wpn[wi].n, *w->nameptr); if (b->wpn[wi].numshots >= 0) { strbuild_catf(&str, " (x %i)", b->wpn[wi].numshots); } } else { buf[0] = 0; } } /* -------------------------------------------------------------------------- */ ui_battle_autoresolve_t ui_battle_init(struct battle_s *bt) { struct game_s *g = bt->g; const planet_t *p = &(g->planet[bt->planet_i]); int party_u = bt->s[SIDE_L].party, party_d = bt->s[SIDE_R].party; const char *s1, *s2, *s3; ui_switch_2(bt->g, party_u, party_d); if (party_d >= PLAYER_NUM) { s1 = game_str_tbl_mon_names[party_d - PLAYER_NUM]; } else { race_t race = g->eto[bt->flag_human_att ? party_u : party_d].race; s1 = game_str_tbl_races[race]; } s2 = (party_d >= PLAYER_NUM) ? game_str_bp_attacks : game_str_bp_attack; { race_t race = g->eto[bt->flag_human_att ? party_d : party_u].race; s3 = game_str_tbl_races[race]; } printf("%s | %s | %s %s %s\n", game_str_bp_scombat, p->name, s1, s2, s3); ui_battle_prepost(bt, SIDE_NONE); { const struct input_list_s cl_cont_auto[] = { { UI_BATTLE_AUTORESOLVE_OFF, "C", NULL, "Continue" }, { UI_BATTLE_AUTORESOLVE_AUTO, "A", NULL, "Autoresolve" }, { UI_BATTLE_AUTORESOLVE_RETREAT, "R", NULL, "Retreat" }, { 0, NULL, NULL, NULL } }; return ui_input_list("Fight?", "> ", cl_cont_auto); } } void ui_battle_shutdown(struct battle_s *bt, bool colony_destroyed, int winner) { ui_battle_prepost(bt, winner); ui_switch_wait(bt->g); } void ui_battle_draw_planetinfo(const struct battle_s *bt, bool side_r) { const struct battle_item_s *b = &(bt->item[0/*planet*/]); if (b->side == SIDE_NONE) { return; } printf("%s, %s %i, %s %i\n", b->name, game_str_bt_pop, bt->pop, game_str_bt_ind, bt->fact); if (bt->s[bt->item[bt->cur_item].side].flag_have_scan || (side_r == (b->side == SIDE_R))) { printf("%s:\n", game_str_bt_bases); if (bt->have_subspace_int) { printf("- %s\n", game_str_bt_subint); } { const struct shiptech_weap_s *w = &(tbl_shiptech_weap[b->wpn[0].t]); if ((!bt->s[b->side].flag_base_missile) && (w->nummiss == 1)) { w = &(tbl_shiptech_weap[b->wpn[1].t]); } printf("- 3 %s %s\n", *w->nameptr, game_str_bt_launch); } printf("- bdef %i, mdef %i, att %i, hits %i, dam %i, shield %i\n", b->defense, b->misdefense, b->complevel, b->hp1, b->hploss, b->absorb); } } void ui_battle_draw_scan(const struct battle_s *bt, bool side_r) { battle_side_i_t scan_side = side_r ? SIDE_R : SIDE_L; int itembase, itemnum; itembase = (scan_side == SIDE_L) ? 1 : (bt->s[SIDE_L].items + 1); itemnum = bt->s[scan_side].items; if (!bt->s[scan_side].flag_have_scan) { printf("No scanners available.\n"); return; } for (int i = 0; i < itemnum; ++i) { const struct battle_item_s *b = &(bt->item[itembase + i]); char gfx[3][5]; char buf0[40]; char buf1[40]; { int tgfx; tgfx = (int)(intptr_t)(b->gfx); if (b->side == SIDE_R) { tgfx += 4; } for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx <= 4; ++dx) { gfx[dy][dx] = battlegfx[tgfx][dy][dx]; } } } gfx[0][((b->side == SIDE_R) ? 0 : 3)] = '1' + b->shiptbli; if (b->num > 0) { char buf[8]; if (b->num >= 1000) { lib_sprintf(buf, sizeof(buf), "%ik", b->num / 1000); } else { lib_sprintf(buf, sizeof(buf), "%i", b->num); } for (int j = 0; buf[j]; ++j) { gfx[2][j + 1] = buf[j]; } } lib_sprintf(buf0, sizeof(buf0), "%s", b->name); ui_battle_draw_scan_weap(b, 0, buf1, sizeof(buf1)); printf("%-30s %-30s %s\n", buf0, buf1, game_str_tbl_st_specsh[b->special[0]]); lib_sprintf(buf0, sizeof(buf0), "%s bdef %i, mdef %i, att %i", gfx[0], b->defense, b->misdefense, b->complevel); ui_battle_draw_scan_weap(b, 1, buf1, sizeof(buf1)); printf("%-30s %-30s %s\n", buf0, buf1, b->special[1] ? game_str_tbl_st_specsh[b->special[1]] : ""); lib_sprintf(buf0, sizeof(buf0), "%s hits %i, dmg %i", gfx[1], b->hp1, b->hploss); ui_battle_draw_scan_weap(b, 2, buf1, sizeof(buf1)); printf("%-30s %-30s %s\n", buf0, buf1, b->special[2] ? game_str_tbl_st_specsh[b->special[2]] : ""); lib_sprintf(buf0, sizeof(buf0), "%s shield %i, speed %i", gfx[2], b->absorb, b->man - b->unman); ui_battle_draw_scan_weap(b, 3, buf1, sizeof(buf1)); printf("%-30s %-30s\n", buf0, buf1); } } void ui_battle_draw_misshield(const struct battle_s *bt, int target_i, int target_x, int target_y, int missile_i) { } void ui_battle_draw_damage(const struct battle_s *bt, int target_i, int target_x, int target_y, uint32_t damage) { char loc[3]; loc[0] = bt->item[target_i].sx + 'a'; loc[1] = bt->item[target_i].sy + '1'; loc[2] = '\0'; printf("%s: Hit, %d damage\n", loc, damage); } void ui_battle_draw_explos_small(const struct battle_s *bt, int x, int y) { } void ui_battle_draw_basic(const struct battle_s *bt) { ui_battle_draw_arena(bt, 0, 0); } void ui_battle_draw_basic_copy(const struct battle_s *bt) { ui_battle_draw_arena(bt, 0, 0); } void ui_battle_draw_missile(const struct battle_s *bt, int missilei, int x, int y, int tx, int ty) { /* incoming tx, ty unused */ tx = (x * 4) / 32 + 3; ty = (y * 3) / 24; ui_data.battle.screen[ty][tx] = 'X'; } void ui_battle_draw_cloaking(const struct battle_s *bt, int from, int to, int sx, int sy) { } void ui_battle_draw_arena(const struct battle_s *bt, int itemi, int dmode) { memset(ui_data.battle.screen, ' ', sizeof(ui_data.battle.screen)); for (int l = 0; l < (8 * 3); ++l) { ui_data.battle.screen[l][2] = '|'; ui_data.battle.screen[l][3 + BATTLE_AREA_W * 4 + 1] = '|'; ui_data.battle.screen[l][3 + BATTLE_AREA_W * 4 + 2] = '\n'; ui_data.battle.screen[l][3 + BATTLE_AREA_W * 4 + 3] = '\0'; if ((l % 3) == 1) { ui_data.battle.screen[l][1] = '1' + (l / 3); } } for (int i = 1; i <= bt->items_num; ++i) { const struct battle_item_s *b; size_t battle_screen_write_pos = 3 + BATTLE_AREA_W * 4 + 2; b = &(bt->item[i]); int l; l = (b->side == SIDE_L) ? 0 : 12; l += b->shiptbli * 2; lib_sprintf(&ui_data.battle.screen[l][battle_screen_write_pos], BATTLE_SCREEN_WIDTH - battle_screen_write_pos, " %i%c %i/%i\n", b->shiptbli + 1, (b->side == SIDE_L) ? '>' : '<', b->hp1 - b->hploss, b->hp1); ++l; lib_sprintf(&ui_data.battle.screen[l][battle_screen_write_pos], BATTLE_SCREEN_WIDTH - battle_screen_write_pos, " %s\n", b->name); } for (int i = 0; i <= bt->items_num; ++i) { if ((i != itemi) || (dmode == 0/*normal*/)) { const struct battle_item_s *b; b = &(bt->item[i]); if (b->side != SIDE_NONE) { ui_battle_draw_item(bt, i, b->sx * 32, b->sy * 24); } } } for (int i = 0; i < bt->num_rocks; ++i) { const struct battle_rock_s *r; int tx, ty; r = &(bt->rock[i]); tx = (r->sx * 4) + 3; ty = (r->sy * 3); for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx < 4; ++dx) { char c; c = battlegfx[10][dy][dx]; ui_data.battle.screen[ty + dy][tx + dx] = c; } } } for (int i = 0; i < bt->num_missile; ++i) { const struct battle_missile_s *m = &(bt->missile[i]); int8_t target; target = m->target; if ((target != MISSILE_TARGET_NONE) && ((target != itemi) || (dmode != 2/*hide target missile*/))) { const struct battle_item_s *b; b = &(bt->item[target]); ui_battle_draw_missile(bt, i, m->x, m->y, b->sx * 32 + 16, b->sy * 24 + 12); } } } void ui_battle_draw_item(const struct battle_s *bt, int itemi, int x, int y) { const struct battle_item_s *b; int tx, ty, tgfx; b = &(bt->item[itemi]); tx = (x * 4) / 32 + 3; ty = (y * 3) / 24; tgfx = (int)(intptr_t)(b->gfx); if ((itemi != 0) && (b->side == SIDE_R)) { tgfx += 4; } for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx < 4; ++dx) { char c; c = battlegfx[tgfx][dy][dx]; ui_data.battle.screen[ty + dy][tx + dx] = c; } } if (b->selected && (!bt->s[b->side].flag_auto)) { if (b->selected != 2/*moving*/) { for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx < 4; ++dx) { char c; c = battlegfx[9][dy][dx]; if (c != ' ') { ui_data.battle.screen[ty + dy][tx + dx] = c; } } } } } if (itemi != 0) { ui_data.battle.screen[ty][tx + ((b->side == SIDE_R) ? 0 : 3)] = '1' + b->shiptbli; } if (b->num > 0) { char buf[8]; if (b->num >= 1000) { lib_sprintf(buf, sizeof(buf), "%ik", b->num / 1000); } else { lib_sprintf(buf, sizeof(buf), "%i", b->num); } for (int i = 0; buf[i]; ++i) { ui_data.battle.screen[ty + 2][tx + i + 1] = buf[i]; } } } void ui_battle_draw_bomb_attack(const struct battle_s *bt, int attacker_i, int target_i, ui_battle_bomb_t bombtype) { } void ui_battle_draw_beam_attack(const struct battle_s *bt, int attacker_i, int target_i, int wpni) { } void ui_battle_draw_stasis(const struct battle_s *bt, int attacker_i, int target_i) { } void ui_battle_draw_pulsar(const struct battle_s *bt, int attacker_i, int ptype, const uint32_t *dmgtbl) { } void ui_battle_draw_stream1(const struct battle_s *bt, int attacker_i, int target_i) { } void ui_battle_draw_stream2(const struct battle_s *bt, int attacker_i, int target_i) { } void ui_battle_draw_blackhole(const struct battle_s *bt, int attacker_i, int target_i) { } void ui_battle_draw_technull(const struct battle_s *bt, int attacker_i, int target_i) { } void ui_battle_draw_repulse(const struct battle_s *bt, int attacker_i, int target_i, int sx, int sy) { } void ui_battle_draw_retreat(const struct battle_s *bt) { int tx, ty, itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); b = &(bt->item[itemi]); tx = (b->sx * 4) + 3; ty = (b->sy * 3); ui_battle_draw_arena(bt, itemi, 1); ui_battle_draw_bottom(bt); for (int dy = 0; dy < 3; ++dy) { for (int dx = 0; dx < 4; ++dx) { ui_data.battle.screen[ty + dy][tx + dx] = 'R'; } } ui_battle_draw_finish(bt); } void ui_battle_draw_bottom(const struct battle_s *bt) { } void ui_battle_draw_finish(const struct battle_s *bt) { fputs(" +-A---B---C---D---E---F---G---H---I---J---+\n", stdout); for (int l = 0; l < (8 * 3); ++l) { fputs(ui_data.battle.screen[l], stdout); } fputs(" +-A---B---C---D---E---F---G---H---I---J---+\n", stdout); } void ui_battle_area_setup(const struct battle_s *bt) { } void ui_battle_turn_pre(const struct battle_s *bt) { } void ui_battle_turn_post(const struct battle_s *bt) { } ui_battle_action_t ui_battle_turn(const struct battle_s *bt) { int itemi = bt->cur_item; const struct battle_item_s *b = &(bt->item[itemi]); char prompt[EMPEROR_NAME_LEN + SHIP_NAME_LEN + 20]; ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_finish(bt); if (0 || (b->stasisby > 0) || ((itemi == 0) && (b->num <= 0)) || (bt->turn_done) || ((b->missile != 0) && (b->maxrange == 0) && bt->has_attacked) ) { return UI_BATTLE_ACT_DONE; } lib_sprintf(prompt, sizeof(prompt), "%s: %d %s > ", bt->g->emperor_names[bt->s[b->side].party], b->num, b->name); while (1) { char *input; input = ui_input_line(prompt); if ((ui_input_tokenize(input, cmdsptr_battle) == 0) && (ui_data.input.num > 0)) { if (ui_data.input.tok[0].type == INPUT_TOKEN_COMMAND) { const struct input_cmd_s *cmd; int v; cmd = ui_data.input.tok[0].data.cmd; v = cmd->handle(bt->g, 0, &ui_data.input.tok[1], ui_data.input.num - 1, cmd->var); if (v >= 0) { if (cmd->handle == ui_cmd_dummy_ret) { return v; } else if (cmd->handle == cmd_battle_look) { ui_battle_draw_arena(bt, 0, 0); ui_battle_draw_reach(bt, itemi); ui_battle_draw_finish(bt); } } } else { int x, y; const char *p; char c; x = y = -1; p = ui_data.input.tok[0].str; c = *p++; if ((c >= '1') && (c <= '8')) { y = c - '1'; c = *p++; if ((c >= 'a') && (c <= 'j')) { x = c - 'a'; if (*p != '\0') { x = -1; } } } else if ((c >= 'a') && (c <= 'j')) { x = c - 'a'; c = *p++; if ((c >= '1') && (c <= '8')) { y = c - '1'; if (*p != '\0') { y = -1; } } } if ((x >= 0) && (y >= 0)) { return UI_BATTLE_ACT_CLICK(x, y); } } } } } void ui_battle_ai_pre(const struct battle_s *bt) { } bool ui_battle_ai_post(const struct battle_s *bt) { return false; } uint8_t *ui_gfx_get_ship(int look) { if (look >= (SHIP_LOOK_PER_BANNER * BANNER_NUM)) { look = 3; } else { look = (look % SHIP_LOOK_PER_BANNER) / SHIP_LOOK_PER_HULL; } return (void *)(intptr_t)look; } uint8_t *ui_gfx_get_planet(int look) { return (void *)8; } uint8_t *ui_gfx_get_rock(int look) { return (void *)10; } 1oom-1.11.2/src/ui/cmdline/uibomb.c000066400000000000000000000041251476061725400167250ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "lib.h" #include "types.h" #include "uidefs.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ bool ui_bomb_ask(struct game_s *g, int pi, uint8_t planet_i, int pop_inbound) { const planet_t *p = &(g->planet[planet_i]); const empiretechorbit_t *e = &(g->eto[p->owner]); char buf[0x80]; int v; ui_switch_1(g, pi); printf("%s : %s %s, %s %i, %s %i", p->name, game_str_tbl_race[e->race], game_str_sm_colony, game_str_sb_pop, p->pop, game_str_sb_fact, p->factories); if (pop_inbound) { printf(", %i %s", pop_inbound, (pop_inbound == 1) ? game_str_sm_trinb1 : game_str_sm_trinb1s); } putchar('\n'); lib_sprintf(buf, sizeof(buf), "%s %s", game_str_sm_bomb1, game_str_sm_bomb2); v = ui_input_list(buf, "> ", il_yes_no); return (v == 1); } void ui_bomb_show(struct game_s *g, int pi, int attacker_i, int owner_i, uint8_t planet_i, int popdmg, int factdmg, bool play_music, bool hide_other) { const planet_t *p = &(g->planet[planet_i]); ui_switch_2(g, attacker_i, owner_i); printf("%s : %s %s. ", p->name, game_str_sm_obomb1, game_str_sm_obomb2); { const char *s; if ((g->gaux->local_players == 1) && IS_HUMAN(g, owner_i)) { s = game_str_sb_your; } else { s = game_str_tbl_race[g->eto[owner_i].race]; } printf("%s %s", s, game_str_sm_colony); } if (p->owner == PLAYER_NONE) { printf(". %s %s", game_str_sm_cdest1, game_str_sm_cdest2); } else if ((popdmg == 0) && (factdmg == 0)) { printf(". %s %s", game_str_sm_ineff1, game_str_sm_ineff2); } else { if (popdmg) { printf(", %i %s %s", popdmg, game_str_sm_bkill1, game_str_sm_bkill2); } if (factdmg) { printf(", %i %s %s", factdmg, (factdmg == 1) ? game_str_sm_bfact1 : game_str_sm_bfact1s, game_str_sm_bfact2); } } putchar('\n'); ui_switch_wait(g); } 1oom-1.11.2/src/ui/cmdline/uicheat.c000066400000000000000000000013201476061725400170640ustar00rootroot00000000000000#include "config.h" #include "uicheat.h" #include "game.h" #include "game_cheat.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int ui_cmd_cheat_galaxy(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return game_cheat_galaxy(g, api) ? 0 : -1; } int ui_cmd_cheat_events(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return game_cheat_events(g, api) ? 0 : -1; } int ui_cmd_cheat_moola(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return game_cheat_moola(g, api) ? 0 : -1; } 1oom-1.11.2/src/ui/cmdline/uicheat.h000066400000000000000000000007161476061725400171010ustar00rootroot00000000000000#ifndef INC_1OOM_UICHEAT_H #define INC_1OOM_UICHEAT_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_cheat_galaxy(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_cheat_events(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_cheat_moola(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uicmdline.c000066400000000000000000000037111476061725400174210ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "cfg.h" #include "game.h" #include "game_end.h" #include "game_turn.h" #include "log.h" #include "options.h" #include "types.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ const struct cfg_items_s ui_cfg_items[] = { CFG_ITEM_END }; const struct cmdline_options_s ui_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ const char *idstr_ui = "cmdline"; struct ui_data_s ui_data = { 0 }; bool ui_use_audio = false; /* -------------------------------------------------------------------------- */ void ui_early_show_message_box(const char *msg) { } int ui_early_init(void) { return 0; } int ui_init(void) { return 0; } int ui_late_init(void) { return 0; } void ui_shutdown(void) { } char *ui_get_strbuf(void) { return ui_data.strbuf; } void ui_sound_play_sfx(int sfxi) { } void ui_landing(struct game_s *g, int pi, uint8_t planet_i) { } void ui_turn_pre(const struct game_s *g) { } void ui_turn_msg(struct game_s *g, int pi, const char *str) { printf("%s | %i | Message: %s\n", g->emperor_names[pi], g->year + YEAR_BASE, str); } void ui_copyprotection_check(struct game_s *g) { copyprot_status = -99; } void ui_copyprotection_lose(struct game_s *g, struct game_end_s *ge) { } void ui_newships(struct game_s *g, int pi) { bool first = true; printf("%s | %i | New ships:", g->emperor_names[pi], g->year + YEAR_BASE); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { shipsum_t n; n = g->evn.new_ships[pi][i]; if (n != 0) { const shipdesign_t *sd = &(g->srd[pi].design[i]); if (!first) { fputs(",", stdout); } else { first = false; } printf(" %i * %s", n, sd->name); } } fputs("\n", stdout); } 1oom-1.11.2/src/ui/cmdline/uicmds.c000066400000000000000000000016661476061725400167430ustar00rootroot00000000000000#include "config.h" #include #include #include "uicmds.h" #include "uidefs.h" #include "uiload.h" #include "uiinput.h" #include "uisave.h" /* -------------------------------------------------------------------------- */ int ui_cmd_dummy_ret(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return (int)(intptr_t)var; } int ui_cmd_quit(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { if ((num_param == 1) && (param[0].str[0] == '!') && (param[0].str[1] == '\0')) { exit(EXIT_SUCCESS); } return 0; } const struct input_cmd_s ui_cmds_opts[] = { { "load", "[SAVENUM]", "Load game", 0, 1, 0, ui_cmd_load, 0 }, { "save", "[SAVENUM [SAVENAME]]", "Save game", 0, 2, 0, ui_cmd_save, 0 }, { "quit", "[!]", "Quit the game; add ! to quit without saving", 0, 1, 0, ui_cmd_quit, 0 }, { NULL, NULL, NULL, 0, 0, 0, NULL, 0 } }; 1oom-1.11.2/src/ui/cmdline/uicmds.h000066400000000000000000000006011476061725400167340ustar00rootroot00000000000000#ifndef INC_1OOM_UICMDS_H #define INC_1OOM_UICMDS_H #include "uidefs.h" struct game_s; struct input_token_s; extern int ui_cmd_dummy_ret(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_quit(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern const struct input_cmd_s ui_cmds_opts[]; #endif1oom-1.11.2/src/ui/cmdline/uidefs.h000066400000000000000000000024401476061725400167320ustar00rootroot00000000000000#ifndef INC_1OOM_UIDEFS_H #define INC_1OOM_UIDEFS_H #include "boolvec.h" #include "game_types.h" #include "ui.h" #include "types.h" #define UI_INPUT_TOKEN_MAX 32 struct game_s; struct input_token_s; struct input_cmd_s { const char *str_cmd; const char *str_param; const char *str_help; int num_param_min; int num_param_max; int flags; int (*handle)(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); void *var; }; struct input_token_s { const char *str; union { void *ptr; const struct input_cmd_s *cmd; int num; } data; enum { INPUT_TOKEN_NONE, INPUT_TOKEN_UNKNOWN, INPUT_TOKEN_COMMAND, INPUT_TOKEN_NUMBER, INPUT_TOKEN_RELNUMBER } type; }; #define BATTLE_SCREEN_HEIGHT (8 * 3) #define BATTLE_SCREEN_WIDTH (10 * 4 + 7 + 20) struct ui_data_s { struct { struct input_token_s tok[UI_INPUT_TOKEN_MAX]; int num; } input; struct { char screen[BATTLE_SCREEN_HEIGHT][BATTLE_SCREEN_WIDTH]; } battle; struct { uint32_t item[PLANETS_MAX + FLEET_ENROUTE_MAX + TRANSPORT_MAX]; } view; BOOLVEC_DECLARE(players_viewing, PLAYER_NUM); char strbuf[UI_STRBUF_SIZE]; }; extern struct ui_data_s ui_data; #endif 1oom-1.11.2/src/ui/cmdline/uidesign.c000066400000000000000000000753501476061725400172670ustar00rootroot00000000000000#include "config.h" #include #include "uidesign.h" #include "comp.h" #include "game.h" #include "game_design.h" #include "game_shiptech.h" #include "game_str.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicmds.h" #include "uidefs.h" #include "uifleet.h" #include "uihelp.h" #include "uiinput.h" #include "uispecs.h" #include "util.h" /* -------------------------------------------------------------------------- */ static int cmd_exit(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return (int)(intptr_t)var; } static int cmd_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const struct design_data_s *d = var; const struct game_design_s *gd = d->gd; const shipdesign_t *sd = &(gd->sd); uint8_t extraman; { uint8_t v; extraman = 0; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { v = tbl_shiptech_special[sd->special[i]].extraman; SETMAX(extraman, v); } } { uint16_t v = 0; for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { v |= tbl_shiptech_special[sd->special[i]].boolmask; } v = tbl_shiptech_comp[sd->comp].level + ((v & (1 << SHIP_SPECIAL_BOOL_SCANNER)) ? 1 : 0); printf("%c%s: %s, %s %u\n", d->flag_disable_comp ? '-' : ' ', game_str_sd_comp, *tbl_shiptech_comp[sd->comp].nameptr, game_str_sd_att, v); } { printf("%c%s: %s", d->flag_disable_shield ? '-' : ' ', game_str_sd_shield, *tbl_shiptech_shield[sd->shield].nameptr); if (sd->shield) { uint8_t v = tbl_shiptech_shield[sd->shield].absorb; printf(", %s %i %s", game_str_sd_absorbs, v, (v == 1) ? game_str_sd_hit : game_str_sd_hits); } putchar('\n'); } { uint8_t v = extraman + sd->man + tbl_shiptech_jammer[sd->jammer].level + tbl_shiptech_hull[sd->hull].defense + 1; printf("%c%s: %s, %s %u\n", d->flag_disable_jammer ? '-' : ' ', game_str_sd_ecm, *tbl_shiptech_jammer[sd->jammer].nameptr, game_str_sd_misdef, v); } printf("%c%s: %s, %s %i\n", d->flag_disable_armor ? '-' : ' ', game_str_sd_armor, *tbl_shiptech_armor[sd->armor].nameptr, game_str_sd_hp, sd->hp); { uint8_t def, warp = tbl_shiptech_engine[sd->engine].warp; def = extraman + sd->man + tbl_shiptech_hull[sd->hull].defense + 1; printf("%c%s: %s, %s %u, %s %u\n", d->flag_disable_engine ? '-' : ' ', game_str_sd_engine, *tbl_shiptech_engine[sd->engine].nameptr, game_str_sd_warp, warp, game_str_sd_def, def); } { uint8_t cspeed, man = extraman + sd->man + 1; cspeed = (extraman / 2) + (sd->man + 3) / 2; printf("%c%s: %u, %s %u\n", d->flag_disable_cspeed ? '-' : ' ', game_str_sd_man, man, game_str_sd_cspeed, cspeed); } for (int i = 0; i < WEAPON_SLOT_NUM; ++i) { weapon_t wi; wi = sd->wpnt[i]; printf("%c%s:", d->flag_tbl_weapon[i] ? '-' : ' ', game_str_tbl_sd_weap[i]); if (wi != WEAPON_NONE) { const char *str; int dmin, dmax; dmin = tbl_shiptech_weap[wi].damagemin; dmax = tbl_shiptech_weap[wi].damagemax; printf(" %c%c %2i x %s, %s ", d->flag_tbl_weap_dn[i] ? ' ' : '-', d->flag_tbl_weap_up[i] ? ' ' : '+', sd->wpnn[i], *tbl_shiptech_weap[wi].nameptr, game_str_sd_damage); if (dmin != dmax) { printf("%i-", dmin); } printf("%i, %s %i", dmax, game_str_sd_rng, tbl_shiptech_weap[wi].range); str = *tbl_shiptech_weap[wi].extratextptr; if (str && *str) { printf(", %s", str); } } putchar('\n'); } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { ship_special_t si; si = sd->special[i]; printf("%c%s:", d->flag_tbl_special[i] ? '-' : ' ', game_str_tbl_sd_spec[i]); if (si != SHIP_SPECIAL_NONE) { printf(" %s", *tbl_shiptech_special[si].nameptr); } putchar('\n'); } printf(" '%s', %s, %s %i %s, %s %i/%i\n", sd->name, *tbl_shiptech_hull[sd->hull].nameptr, game_str_sd_cost, sd->cost, game_str_bc, game_str_sd_space, sd->space, game_design_get_hull_space(gd)); return 0; } static int cmd_clear(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; game_design_clear(gd); return 0; } /* -------------------------------------------------------------------------- */ struct sel_shiptech_s { struct design_data_s *d; const bool *flag_enable; const int8_t *havebuf; int oldv, slot; }; #define SEL_LIST_MAX 33 static const char *selstrs[SEL_LIST_MAX] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", /* leave Q for Quit */ "R", "S", "T", "U", "V", "W", "X" /* Y/Z for prev/next */ }; static void sel_build_il(struct input_list_s *il, bool *flag_enable, const int8_t *havebuf, int havelast, int offs) { int i, n = 0; for (i = 0; i <= havelast; ++i) { flag_enable[i] = (havebuf[i] > 0); } for (i = offs; (i <= havelast) && (n < SEL_LIST_MAX); ++i) { if (havebuf[i] >= 0) { il[n].value = i; il[n].key = selstrs[n]; il[n].str = 0; il[n].display = 0; ++n; } } if (offs > 0) { il[n].value = -2/*prev*/; il[n].key = "Y"; il[n].str = 0; il[n].display = "(prev)"; ++n; } if (i <= havelast) { il[n].value = -3/*next*/; il[n].key = "Z"; il[n].str = 0; il[n].display = "(next)"; ++n; } il[n].value = -1; il[n].key = "Q"; il[n].str = 0; il[n].display = "(quit)"; ++n; il[n].value = -4; il[n].key = 0; il[n].str = 0; il[n].display = 0; } static bool sel_is_ok(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; int v = l->value; return ((v < 0) || sel->flag_enable[v]); } static const char *sel_comp_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, space, cost, space2, power, cost2, sizei; if (i < 0) { return l->display; } sd->comp = 0; game_design_update_engines(sd); space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->comp = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(gd); power = tbl_shiptech_comp[i].power[sd->hull]; cost2 = game_design_calc_cost(gd) - cost; sizei = game_design_calc_space_item(gd, DESIGN_SLOT_COMP, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s, %s %i, %s %i, %s %i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_comp[i].nameptr, game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_power, power, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_comp(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_COMP_NUM + 2]; bool flag_enable[SHIP_COMP_NUM]; int oldv = sd->comp; { int8_t havebuf[SHIP_COMP_NUM]; int havelast; sd->comp = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_comp(d->g, gd, havebuf); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_comp_get_display }; int v = ui_input_list_dynamic(game_str_sd_comp, "> ", &ld); sd->comp = (v < 0) ? oldv : v; } return 0; } static const char *sel_shield_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, space, cost, space2, power, cost2, sizei; if (i < 0) { return l->display; } sd->shield = 0; game_design_update_engines(sd); space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->shield = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(gd); power = tbl_shiptech_shield[i].power[sd->hull]; cost2 = game_design_calc_cost(gd) - cost; sizei = game_design_calc_space_item(gd, DESIGN_SLOT_SHIELD, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s, %s %i, %s %i, %s %i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_shield[i].nameptr, game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_power, power, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_shield(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_SHIELD_NUM + 2]; bool flag_enable[SHIP_SHIELD_NUM]; int oldv = sd->shield; { int8_t havebuf[SHIP_SHIELD_NUM]; int havelast; sd->shield = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_shield(d->g, gd, havebuf); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_shield_get_display }; int v = ui_input_list_dynamic(game_str_sd_shield, "> ", &ld); sd->shield = (v < 0) ? oldv : v; } return 0; } static const char *sel_jammer_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, space, cost, space2, power, cost2, sizei; if (i < 0) { return (i == -1) ? "(quit)" : 0; } sd->jammer = 0; game_design_update_engines(sd); space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->jammer = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(gd); power = tbl_shiptech_jammer[i].power[sd->hull]; cost2 = game_design_calc_cost(gd) - cost; sizei = game_design_calc_space_item(gd, DESIGN_SLOT_JAMMER, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s, %s %i, %s %i, %s %i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_jammer[i].nameptr, game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_power, power, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_jammer(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_JAMMER_NUM + 2]; bool flag_enable[SHIP_JAMMER_NUM]; int oldv = sd->jammer; { int8_t havebuf[SHIP_JAMMER_NUM]; int havelast; sd->jammer = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_jammer(d->g, gd, havebuf); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_jammer_get_display }; int v = ui_input_list_dynamic(game_str_sd_ecm, "> ", &ld); sd->jammer = (v < 0) ? oldv : v; } return 0; } static const char *sel_armor_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, cost2, sizei; if (i < 0) { return l->display; } sd->armor = i; game_design_update_engines(sd); cost2 = game_design_calc_cost_item(d->gd, DESIGN_SLOT_ARMOR, i); sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_ARMOR, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s, %s %i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_armor[i].nameptr, game_str_sd_cost, cost2, game_str_sd_size, sizei); return ui_data.strbuf; } static int cmd_sel_armor(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_ARMOR_NUM + 2]; bool flag_enable[SHIP_ARMOR_NUM]; int oldv = sd->armor; { int8_t havebuf[SHIP_ARMOR_NUM]; int havelast; havelast = game_design_build_tbl_fit_armor(d->g, gd, havebuf); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_armor_get_display }; int v = ui_input_list_dynamic(game_str_sd_armor, "> ", &ld); sd->armor = (v < 0) ? oldv : v; } return 0; } static const char *sel_engine_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, cost2, sizei, sizet, ne; if (i < 0) { return l->display; } sd->engine = i; game_design_update_engines(sd); ne = sd->engines; sizei = game_design_calc_space_item(d->gd, DESIGN_SLOT_ENGINE, i); sizet = (sizei * ne) / 10; cost2 = game_design_calc_cost_item(d->gd, DESIGN_SLOT_ENGINE, i); sizei = game_design_calc_space_item(gd, DESIGN_SLOT_JAMMER, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s, %s %i, %s %i, %s %i.%i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_engine[i].nameptr, game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_numengs, ne / 10, ne % 10, game_str_sd_space, sizet); return ui_data.strbuf; } static int cmd_sel_engine(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_ENGINE_NUM + 2]; bool flag_enable[SHIP_ENGINE_NUM]; int oldv = sd->engine; { int8_t havebuf[SHIP_ENGINE_NUM]; int havelast; sd->engine = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_engine(d->g, gd, havebuf); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_engine_get_display }; int v = ui_input_list_dynamic(game_str_sd_engine, "> ", &ld); sd->engine = (v < 0) ? oldv : v; } return 0; } static const char *sel_man_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, powperwarp, space, cost, space2, spacet, cost2; if (i < 0) { return l->display; } sd->man = 0; game_design_update_engines(sd); powperwarp = tbl_shiptech_hull[sd->hull].power / tbl_shiptech_engine[sd->engine].warp; sd->engines = sd->engines - (powperwarp * 10) / tbl_shiptech_engine[sd->engine].power; space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->man = i; game_design_update_engines(sd); spacet = game_design_calc_space(gd); space2 = space - spacet; SETMAX(space2, 1); powperwarp = (tbl_shiptech_hull[sd->hull].power * (i + 1)) / tbl_shiptech_engine[sd->engine].warp; SETMAX(powperwarp, 1); cost2 = game_design_calc_cost(d->gd) - cost; SETMAX(cost2, 1); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s %s, %s %i, %s %i, %s %i, %s %i", (i == sel->oldv) ? "*" : "", game_str_sd_class, game_str_tbl_roman[i + 1], game_str_sd_speed, (i + 3) / 2, game_str_sd_cost, cost2, game_str_sd_power, powperwarp, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_man(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_ENGINE_NUM + 2]; bool flag_enable[SHIP_ENGINE_NUM]; int oldv = sd->man; { int8_t havebuf[SHIP_ENGINE_NUM]; int havelast = sd->engine; for (int i = 0; i <= havelast; ++i) { int spacet; sd->man = i; game_design_update_engines(sd); spacet = game_design_calc_space(d->gd); havebuf[i] = (spacet >= 0) ? 1 : 0; } sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_man_get_display }; int v = ui_input_list_dynamic(game_str_sd_man, "> ", &ld); sd->man = (v < 0) ? oldv : v; } return 0; } static const char *sel_wpnt_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, wslot = sel->slot, space, cost, space2, power, cost2, sizei, dmin, dmax; if (i < 0) { return l->display; } if (i == 0) { return *tbl_shiptech_weap[0].nameptr; } sd->wpnt[wslot] = 0; sd->wpnn[wslot] = 0; game_design_update_engines(sd); space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->wpnt[wslot] = i; sd->wpnn[wslot] = 1; game_design_update_engines(sd); space2 = space - game_design_calc_space(gd); power = tbl_shiptech_weap[i].power; cost2 = game_design_calc_cost(gd) - cost; sizei = game_design_calc_space_item(gd, DESIGN_SLOT_WEAPON1, i); dmin = tbl_shiptech_weap[i].damagemin; dmax = tbl_shiptech_weap[i].damagemax; struct strbuild_s str = strbuild_init(ui_data.strbuf, UI_STRBUF_SIZE); strbuild_catf(&str, "%s%i x %s", (i == sel->oldv) ? "*" : "", sel->havebuf[i], *tbl_shiptech_weap[i].nameptr); if (**tbl_shiptech_weap[i].extratextptr != ' ') { strbuild_catf(&str, ": %s", *tbl_shiptech_weap[i].extratextptr); } strbuild_catf(&str, ", %s %i", game_str_sd_dmg, dmin); if (dmin != dmax) { strbuild_catf(&str, "-%i", dmax); } strbuild_catf(&str, ", %s %i, %s %i, %s %i, %s %i", game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_power, power, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_wpnt(struct design_data_s *d, int wslot) { struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SEL_LIST_MAX + 4]; int8_t havebuf[WEAPON_NUM]; bool flag_enable[WEAPON_NUM]; int havelast, offs = 0, oldv = sd->wpnt[wslot]; uint8_t oldn = sd->wpnn[wslot]; struct sel_shiptech_s sel = { .d = d, .havebuf = havebuf, .flag_enable = flag_enable, .oldv = oldv, .slot = wslot }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_wpnt_get_display }; sd->wpnt[wslot] = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_weapon(d->g, gd, havebuf, wslot, WEAPON_GROUP_ALL); while (1) { int v; sel_build_il(il, flag_enable, havebuf, havelast, offs); v = ui_input_list_dynamic(game_str_tbl_sd_weap[wslot], "> ", &ld); if (v >= 0) { uint8_t wn; sd->wpnt[wslot] = v; wn = havebuf[v]; SETMIN(wn, oldn); SETMAX(wn, 1); sd->wpnn[wslot] = wn; return 0; } else if (v == -1/*quit*/) { sd->wpnt[wslot] = oldv; sd->wpnn[wslot] = oldn; return 0; } else if (v == -2/*prev*/) { offs -= SEL_LIST_MAX; SETMAX(offs, 0); } else { offs += SEL_LIST_MAX; SETMIN(offs, havelast); } } } static int cmd_sel_wpnt1(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_wpnt(var, 0); } static int cmd_sel_wpnt2(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_wpnt(var, 1); } static int cmd_sel_wpnt3(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_wpnt(var, 2); } static int cmd_sel_wpnt4(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_wpnt(var, 3); } static int cmd_set_wpnn(struct design_data_s *d, int wslot, struct input_token_s *param) { struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int v; if (sd->wpnt[wslot] == 0) { printf("No weapon in slot %i\n", wslot); return -1; } if (param[0].type == INPUT_TOKEN_NUMBER) { v = param[0].data.num; } else if (param[0].type == INPUT_TOKEN_RELNUMBER) { v = sd->wpnn[wslot] + param[0].data.num; } else { return -1; } SETRANGE(v, 0, 99); do { sd->wpnn[wslot] = v; game_design_update_engines(sd); --v; } while ((v >= 0) && (game_design_calc_space(gd) < 0)); return 0; } static int cmd_set_wpnn1(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_set_wpnn(var, 0, param); } static int cmd_set_wpnn2(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_set_wpnn(var, 1, param); } static int cmd_set_wpnn3(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_set_wpnn(var, 2, param); } static int cmd_set_wpnn4(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_set_wpnn(var, 3, param); } static const char *sel_spec_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; struct design_data_s *d = sel->d; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); int i = l->value, sslot = sel->slot, space, cost, space2, power, cost2, sizei; if (i < 0) { return l->display; } sd->special[sslot] = 0; game_design_update_engines(sd); space = game_design_calc_space(gd); cost = game_design_calc_cost(gd); sd->special[sslot] = i; game_design_update_engines(sd); space2 = space - game_design_calc_space(gd); power = tbl_shiptech_special[i].power[sd->hull]; cost2 = game_design_calc_cost(gd) - cost; sizei = game_design_calc_space_item(gd, DESIGN_SLOT_SPECIAL1, i); lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s: %s, %s %i, %s %i, %s %i, %s %i", (i == sel->oldv) ? "*" : "", *tbl_shiptech_special[i].nameptr, *tbl_shiptech_special[i].extratextptr, game_str_sd_cost, cost2, game_str_sd_size, sizei, game_str_sd_power, power, game_str_sd_space, space2); return ui_data.strbuf; } static int cmd_sel_spec(struct design_data_s *d, int sslot) { struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_SPECIAL_NUM + 2]; bool flag_enable[SHIP_SPECIAL_NUM]; int oldv = sd->special[sslot]; { int8_t havebuf[SHIP_SPECIAL_NUM]; int havelast; sd->special[sslot] = 0; game_design_update_engines(sd); havelast = game_design_build_tbl_fit_special(d->g, gd, havebuf, sslot); sel_build_il(il, flag_enable, havebuf, havelast, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv, .slot = sslot }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_spec_get_display }; int v = ui_input_list_dynamic(game_str_tbl_sd_spec[sslot], "> ", &ld); sd->special[sslot] = (v < 0) ? oldv : v; } return 0; } static int cmd_sel_spec1(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_spec(var, 0); } static int cmd_sel_spec2(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_spec(var, 1); } static int cmd_sel_spec3(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return cmd_sel_spec(var, 2); } static const char *sel_hull_get_display(void *ctx, const struct input_list_s *l) { struct sel_shiptech_s *sel = ctx; int i = l->value; if (i < 0) { return l->display; } lib_sprintf(ui_data.strbuf, UI_STRBUF_SIZE, "%s%s", (i == sel->oldv) ? "*" : "", *tbl_shiptech_hull[i].nameptr); return ui_data.strbuf; } static int cmd_sel_hull(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); struct input_list_s il[SHIP_HULL_NUM + 2]; bool flag_enable[SHIP_HULL_NUM]; int oldv = sd->hull; { int8_t havebuf[SHIP_HULL_NUM]; for (int i = 0; i < SHIP_HULL_NUM; ++i) { bool flag_no; flag_no = d->flag_tbl_hull[i]; havebuf[i] = flag_no ? 0 : 1; flag_enable[i] = !flag_no; } sel_build_il(il, flag_enable, havebuf, SHIP_HULL_NUM - 1, 0); } { struct sel_shiptech_s sel = { .d = d, .flag_enable = flag_enable, .oldv = oldv }; struct input_list_dyn_s ld = { .list = il, .ctx = &sel, .is_ok = sel_is_ok, .get_display = sel_hull_get_display }; int v = ui_input_list_dynamic("Ship size", "> ", &ld); sd->hull = (v < 0) ? oldv : v; } return 0; } static int cmd_set_name(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct design_data_s *d = var; struct game_design_s *gd = d->gd; shipdesign_t *sd = &(gd->sd); if (num_param == 0) { sd->name[0] = '\0'; } else { #define BUFLEN 64 char name[BUFLEN]; int len; strncpy(name, param[0].str, BUFLEN - 1); name[BUFLEN - 1] = '\0'; util_trim_whitespace(name, sizeof(name)); len = strlen(name); if (len >= SHIP_NAME_LEN) { printf("Name too long!\n"); return -1; } memset(sd->name, 0, SHIP_NAME_LEN); memcpy(sd->name, name, len); #undef BUFLEN } if (sd->name[0] == '\0') { lib_strcpy(sd->name, gd->names[sd->hull], SHIP_NAME_LEN); } return 0; } /* -------------------------------------------------------------------------- */ static const struct input_cmd_s * const cmdsptr_design[2]; static const struct input_cmd_s cmds_design[] = { { "?", NULL, "Help", 0, 0, 0, ui_cmd_help, (void *)cmdsptr_design }, { "q", NULL, "Cancel", 0, 0, 0, cmd_exit, (void *)1/*cancel*/ }, { "b", NULL, "Build", 0, 0, 0, cmd_exit, (void *)2/*ok*/ }, { "l", NULL, "Look", 0, 0, 0, cmd_look, 0 }, { "clear", NULL, "Clear", 0, 0, 0, cmd_clear, 0 }, { "c", NULL, "Computer", 0, 0, 0, cmd_sel_comp, 0 }, { "s", NULL, "Shield", 0, 0, 0, cmd_sel_shield, 0 }, { "j", NULL, "Ecm", 0, 0, 0, cmd_sel_jammer, 0 }, { "a", NULL, "Armor", 0, 0, 0, cmd_sel_armor, 0 }, { "e", NULL, "Engine", 0, 0, 0, cmd_sel_engine, 0 }, { "m", NULL, "Maneuver", 0, 0, 0, cmd_sel_man, 0 }, { "w1", NULL, "Weapon 1 type", 0, 0, 0, cmd_sel_wpnt1, 0 }, { "w2", NULL, "Weapon 2 type", 0, 0, 0, cmd_sel_wpnt2, 0 }, { "w3", NULL, "Weapon 3 type", 0, 0, 0, cmd_sel_wpnt3, 0 }, { "w4", NULL, "Weapon 4 type", 0, 0, 0, cmd_sel_wpnt4, 0 }, { "a1", "NUM", "Weapon 1 amount", 1, 1, 0, cmd_set_wpnn1, 0 }, { "a2", "NUM", "Weapon 2 amount", 1, 1, 0, cmd_set_wpnn2, 0 }, { "a3", "NUM", "Weapon 3 amount", 1, 1, 0, cmd_set_wpnn3, 0 }, { "a4", "NUM", "Weapon 4 amount\nNUM can be +N or -N for relative adjustment", 1, 1, 0, cmd_set_wpnn4, 0 }, { "s1", NULL, "Special 1", 0, 0, 0, cmd_sel_spec1, 0 }, { "s2", NULL, "Special 2", 0, 0, 0, cmd_sel_spec2, 0 }, { "s3", NULL, "Special 3", 0, 0, 0, cmd_sel_spec3, 0 }, { "h", NULL, "Ship size", 0, 0, 0, cmd_sel_hull, 0 }, { "n", "[NAME]", "Name", 0, 1, 0, cmd_set_name, 0 }, { NULL, NULL, NULL, 0, 0, 0, NULL, 0 } }; static const struct input_cmd_s * const cmdsptr_design[2] = { cmds_design, NULL }; static bool ui_design(struct game_s *g, struct game_design_s *gd, player_id_t pi) { struct design_data_s d; shipdesign_t *sd = &(gd->sd); d.g = g; d.gd = gd; d.api = pi; game_design_init_maxtech_haveflags(&d); lib_strcpy(sd->name, gd->names[sd->hull], SHIP_NAME_LEN); cmd_look(g, pi, 0, 0, &d); while (1) { char *input; input = ui_input_line("Ship design > "); if ((ui_input_tokenize(input, cmdsptr_design) == 0) && (ui_data.input.num > 0)) { if (ui_data.input.tok[0].type == INPUT_TOKEN_COMMAND) { const struct input_cmd_s *cmd; int v; cmd = ui_data.input.tok[0].data.cmd; v = cmd->handle(g, pi, &ui_data.input.tok[1], ui_data.input.num - 1, cmd->var ? cmd->var : &d); if (cmd->handle == cmd_exit) { return (v == 2/*ok*/); } else if (cmd->handle != ui_cmd_help) { game_design_update_engines(sd); game_design_update_haveflags(&d); cmd_look(g, pi, 0, 0, &d); } } } } } /* -------------------------------------------------------------------------- */ int ui_cmd_design(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_design_s gd; bool ok; int sd_num; sd_num = g->eto[api].shipdesigns_num; game_design_prepare(g, &gd, api, &g->current_design[api]); ok = ui_design(g, &gd, api); if (ok && (sd_num == NUM_SHIPDESIGNS)) { ui_cmd_fleet_specs(g, api, 0, 0, 0); ui_cmd_fleet_scrap(g, api, 0, 0, 0); sd_num = g->eto[api].shipdesigns_num; ok = (sd_num < NUM_SHIPDESIGNS); if (ok) { game_design_look_fix(g, api, &gd.sd); } } if (ok) { game_design_add(g, api, &gd.sd, true); } g->current_design[api] = gd.sd; return 0; } 1oom-1.11.2/src/ui/cmdline/uidesign.h000066400000000000000000000003471476061725400172660ustar00rootroot00000000000000#ifndef INC_1OOM_UIDESIGN_H #define INC_1OOM_UIDESIGN_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_design(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uielection.c000066400000000000000000000035641476061725400176160ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_election.h" #include "game_str.h" #include "types.h" #include "uidefs.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ void ui_election_start(struct election_s *el) { ui_switch_all(el->g); } void ui_election_show(struct election_s *el) { struct game_s *g = el->g; printf("Election | "); if (el->flag_show_votes) { char vbuf[0x20]; uint16_t n; n = el->got_votes[0]; printf("%s %s, ", game_election_print_votes(n, vbuf, sizeof(vbuf)), g->emperor_names[el->candidate[0]]); n = el->got_votes[1]; printf("%s %s, ", game_election_print_votes(n, vbuf, sizeof(vbuf)), g->emperor_names[el->candidate[1]]); n = el->total_votes; printf("%s %s | ", game_election_print_votes(n, vbuf, sizeof(vbuf)), game_str_el_total); } if (el->cur_i != PLAYER_NONE) { printf("(%s) | ", game_str_tbl_race[g->eto[el->tbl_ei[el->cur_i]].race]); } if (el->str) { puts(el->str); } } void ui_election_delay(struct election_s *el, int delay) { } int ui_election_vote(struct election_s *el, int player_i) { struct input_list_s il_vote[] = { { 1, "1", NULL, NULL }, { 2, "2", NULL, NULL }, { 0, "0", NULL, game_str_el_abs }, { 0, NULL, NULL, NULL } }; for (int i = 0; i < 2; ++i) { player_id_t pi; pi = el->candidate[i]; il_vote[i].display = (pi == player_i) ? game_str_el_self : el->g->emperor_names[pi]; } return ui_input_list(el->str, "> ", il_vote); } bool ui_election_accept(struct election_s *el, int player_i) { int v; v = ui_input_list(el->str, "> ", il_yes_no); return (v == 1); } void ui_election_end(struct election_s *el) { ui_switch_wait(el->g); } 1oom-1.11.2/src/ui/cmdline/uiempire.c000066400000000000000000000051251476061725400172700ustar00rootroot00000000000000#include "config.h" #include #include #include "uiempire.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_str.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ static int ui_empire_slider(struct input_token_s *param, int base) { int v; if (param[0].type == INPUT_TOKEN_NUMBER) { v = param[0].data.num; } else if (param[0].type == INPUT_TOKEN_RELNUMBER) { v = base + param[0].data.num; } else { return -1; } SETRANGE(v, 0, 200); return v; } /* -------------------------------------------------------------------------- */ int ui_cmd_empire_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const empiretechorbit_t *e = &(g->eto[api]); char buf[64]; printf("%s, %s\n", game_str_tbl_races[e->race], g->emperor_names[api]); printf("- %s: ", game_str_pl_spending); game_print_prod_of_total(g, api, e->ship_maint_bc, buf, sizeof(buf)); printf("Ships %s", buf); game_print_prod_of_total(g, api, e->bases_maint_bc, buf, sizeof(buf)); printf(", Bases %s", buf); { int v = 0; for (player_id_t i = PLAYER_0; i < PLAYER_NUM; ++i) { if (i != api) { v += e->spying[i]; } } printf(", Spying %i.%i%%", v / 10, v % 10); } { int v = e->security; printf(", Security %i.%i%%\n", v / 10, v % 10); } printf("- %s: Trade %i %s, Planets %i %s\n", game_str_pl_tincome, e->total_trade_bc, game_str_bc, e->total_production_bc, game_str_bc); printf("- %s: %i %s\n", game_str_pl_reserve, e->reserve_bc, game_str_bc); { int tax, bc; tax = e->tax; bc = (tax * e->total_production_bc) / 2000; printf("- Tax: %i.%i%% +%i %s\n", tax / 10, tax % 10, bc, game_str_bc); } { int v = (e->security / 5); if (e->race == RACE_DARLOK) { v += 20; } printf("- Security: %i%%\n", v); } return 0; } int ui_cmd_empire_tax(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { empiretechorbit_t *e = &(g->eto[api]); int v = ui_empire_slider(param, e->tax); if (v < 0) { return -1; } e->tax = v; return 0; } int ui_cmd_empire_security(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { empiretechorbit_t *e = &(g->eto[api]); int v = ui_empire_slider(param, e->security); if (v < 0) { return -1; } e->security = v; return 0; } 1oom-1.11.2/src/ui/cmdline/uiempire.h000066400000000000000000000007211476061725400172720ustar00rootroot00000000000000#ifndef INC_1OOM_UIEMPIRE_H #define INC_1OOM_UIEMPIRE_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_empire_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_empire_tax(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_empire_security(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiempirereport.c000066400000000000000000000101631476061725400205220ustar00rootroot00000000000000#include "config.h" #include #include #include "uiempirereport.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "uidefs.h" #include "uiinput.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void show_empire_report(const struct game_s *g, player_id_t api, player_id_t pi) { const empiretechorbit_t *eapi = &(g->eto[api]); const empiretechorbit_t *e = &(g->eto[pi]); const shipresearch_t *srd = &(g->srd[pi]); char *buf = ui_data.strbuf; printf("Report: %s, %s, %s %s. %s ", game_str_tbl_races[e->race], g->emperor_names[pi], game_str_tbl_trait1[e->trait1], game_str_tbl_trait2[e->trait2], game_str_re_reportis); { int reportage = g->year - eapi->spyreportyear[pi] - 1; if (reportage < 2) { fputs(game_str_re_current, stdout); } else { printf("%i %s", reportage, game_str_re_yearsold); } putchar('\n'); } { bool first = true; printf("%s:", game_str_re_alliance); for (int i = 0; i < g->players; ++i) { if ((i != pi) && (e->treaty[i] == TREATY_ALLIANCE) && IS_ALIVE(g, i)) { if (!first) { putchar(','); } putchar(' '); first = false; fputs(game_str_tbl_races[g->eto[i].race], stdout); } } putchar('\n'); } { bool first = true; printf("%s:", game_str_re_wars); for (int i = 0; i < g->players; ++i) { if ((i != pi) && (e->treaty[i] >= TREATY_WAR) && IS_ALIVE(g, i)) { if (!first) { putchar(','); } putchar(' '); first = false; fputs(game_str_tbl_races[g->eto[i].race], stdout); } } putchar('\n'); } for (int f = 0; f < TECH_FIELD_NUM; ++f) { const uint8_t *rct = &(srd->researchcompleted[f][0]); uint16_t tc; uint8_t first, num, rf; tc = e->tech.completed[f]; rf = eapi->spyreportfield[pi][f]; num = 0; for (int i = 0; i < tc; ++i) { uint8_t rc; rc = rct[i]; if (rc <= rf) { num = i + 1; } } if (num > 8) { first = num - 8; num = 8; } else { first = 0; } puts(game_str_tbl_te_field[f]); for (int i = 0; i < num; ++i) { uint8_t rc; rc = rct[first + i]; game_tech_get_name(g->gaux, f, rc, buf, UI_STRBUF_SIZE); putchar(game_tech_player_has_tech(g, f, rc, api) ? '-' : '!'); putchar(' '); puts(buf); } } } /* -------------------------------------------------------------------------- */ int ui_cmd_empirereport(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct input_list_s rl_in[] = { { -1, "1", NULL, NULL }, { -1, "2", NULL, NULL }, { -1, "3", NULL, NULL }, { -1, "4", NULL, NULL }, { -1, "5", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; const empiretechorbit_t *e = &(g->eto[api]); int num = 0; for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != api) && BOOLVEC_IS1(e->contact, pi) && IS_ALIVE(g, pi)) { rl_in[num].value = pi; rl_in[num].display = game_str_tbl_race[g->eto[pi].race]; ++num; } } if (num > 0) { int v; rl_in[num].value = -1; rl_in[num].key = "Q"; rl_in[num].str = "q"; rl_in[num].display = "(quit)"; ++num; rl_in[num].value = 0; rl_in[num].key = NULL; rl_in[num].str = NULL; rl_in[num].display = NULL; v = ui_input_list("Choose race", "> ", rl_in); if (v >= 0) { show_empire_report(g, api, v); } } else { puts("No races to report on"); } return 0; } 1oom-1.11.2/src/ui/cmdline/uiempirereport.h000066400000000000000000000003711476061725400205270ustar00rootroot00000000000000#ifndef INC_1OOM_UIEMPIREREPORT_H #define INC_1OOM_UIEMPIREREPORT_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_empirereport(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiempirestats.c000066400000000000000000000025621476061725400203510ustar00rootroot00000000000000#include "config.h" #include #include #include "uiempirestats.h" #include "comp.h" #include "game.h" #include "game_str.h" #include "game_stat.h" #include "lib.h" #include "uidefs.h" #include "util.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ int ui_cmd_empirestats(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_stats_s st[1]; int maxlen = 0; char fmt[10]; printf("%s | %s: %i\n", game_str_ra_stats, game_str_year, g->year + YEAR_BASE); game_stats_all(g, api, st); for (int i = 0; i < st->num; ++i) { int len; player_id_t pi; const empiretechorbit_t *e; pi = st->p[i]; e = (&g->eto[pi]); len = strlen(game_str_tbl_race[e->race]); SETMAX(maxlen, len); } lib_sprintf(fmt, sizeof(fmt), "%%-%is", maxlen); printf(fmt, ""); puts(" Fleet Tech Prod Pop Planets Total"); for (int i = 0; i < st->num; ++i) { player_id_t pi; const empiretechorbit_t *e; pi = st->p[i]; e = (&g->eto[pi]); printf(fmt, game_str_tbl_race[e->race]); for (int s = 0; s < 6; ++s) { printf(" %3u", st->v[s][i]); } putchar('\n'); } return 0; } 1oom-1.11.2/src/ui/cmdline/uiempirestats.h000066400000000000000000000003661476061725400203560ustar00rootroot00000000000000#ifndef INC_1OOM_UIEMPIRESTATS_H #define INC_1OOM_UIEMPIRESTATS_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_empirestats(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiending.c000066400000000000000000000012021476061725400172430ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" /* -------------------------------------------------------------------------- */ void ui_play_ending_good(int race, const char *name) { putchar('\n'); fputs(name, stdout); fputs(" won! :)\n\n", stdout); } void ui_play_ending_tyrant(int race, const char *name) { putchar('\n'); fputs(name, stdout); fputs(" won... :/\n\n", stdout); } void ui_play_ending_funeral(int p0, int p2) { fputs("\nFuneral. :(\n\n", stdout); } void ui_play_ending_exile(const char *name) { putchar('\n'); fputs(name, stdout); fputs(" was exiled. >:I\n\n", stdout); } 1oom-1.11.2/src/ui/cmdline/uiexplore.c000066400000000000000000000027271476061725400174720ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_str.h" #include "lib.h" #include "uiinput.h" #include "uiplanet.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ bool ui_explore(struct game_s *g, int pi, uint8_t planet_i, bool by_scanner, bool flag_colony_ship) { ui_switch_1(g, pi); if (!flag_colony_ship) { if (by_scanner) { printf("%s %s %s %s\n", game_str_ex_planeta, game_str_ex_scanner, game_str_ex_explore, game_str_ex_starsys); } else { printf("%s %s %s\n", game_str_ex_scout, game_str_ex_explore, game_str_ex_starsys); } } ui_planet_look(g, pi, planet_i, true); if (flag_colony_ship) { char buf[0x80]; int v; lib_sprintf(buf, sizeof(buf), "%s %s", game_str_ex_build, game_str_ex_colony); v = ui_input_list(buf, "> ", il_yes_no); flag_colony_ship = (v == 1); if (flag_colony_ship) { char *name; printf("%s %i %s %s%s: (%s) ", game_str_la_inyear, g->year + YEAR_BASE, game_str_la_the, game_str_tbl_race[g->eto[pi].race], game_str_la_formnew, g->planet[planet_i].name); name = ui_input_line_len_trim("> ", PLANET_NAME_LEN); if (name[0] != '\0') { lib_strcpy(g->planet[planet_i].name, name, PLANET_NAME_LEN); } } } else { ui_switch_wait(g); } return flag_colony_ship; } 1oom-1.11.2/src/ui/cmdline/uifinished.c000066400000000000000000000017161476061725400176020ustar00rootroot00000000000000#include "config.h" #include #include "uifinished.h" #include "game.h" #include "game_planet.h" #include "ui.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ void ui_finished_print_all(struct game_s *g, int api) { if (g->evn.build_finished_num[api] > 0) { g->evn.build_finished_num[api] = 0; for (uint8_t pli = 0; pli < g->galaxy_stars; ++pli) { planet_t *p = &(g->planet[pli]); if ((p->owner == api) && (p->finished[0] & (~(1 << FINISHED_SHIP)))) { for (planet_finished_t type = 0; type < FINISHED_NUM; ++type) { if ((type != FINISHED_SHIP) && BOOLVEC_IS1(p->finished, type)) { BOOLVEC_SET0(p->finished, type); printf("- %s\n", game_planet_get_finished_text(g, p, type, ui_data.strbuf, UI_STRBUF_SIZE)); } } } } } } 1oom-1.11.2/src/ui/cmdline/uifinished.h000066400000000000000000000002471476061725400176050ustar00rootroot00000000000000#ifndef INC_1OOM_UIFINISHED_H #define INC_1OOM_UIFINISHED_H #include "types.h" struct game_s; extern void ui_finished_print_all(struct game_s *g, int api); #endif 1oom-1.11.2/src/ui/cmdline/uifleet.c000066400000000000000000000304711476061725400171100ustar00rootroot00000000000000#include "config.h" #include #include #include #include "uifleet.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_fleet.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "lib.h" #include "uidefs.h" #include "uiinput.h" #include "uiplanet.h" #include "util.h" /* -------------------------------------------------------------------------- */ static uint8_t get_fleet_planet_on(const struct game_s *g, const fleet_enroute_t *r) { for (int i = 0; i < g->galaxy_stars; ++i) { const planet_t *p; p = &g->planet[i]; if ((p->x == r->x) && (p->y == r->y)) { return i; } } return PLANET_NONE; } static void ui_fleet_print_fleet_orbit(const struct game_s *g, int api, uint8_t planet_i, int pi) { const fleet_orbit_t *r = &(g->eto[pi].orbit[planet_i]); if (BOOLVEC_IS1(r->visible, api)) { char buf[80]; char pname[20]; const planet_t *p; p = &(g->planet[planet_i]); lib_sprintf(buf, sizeof(buf), "%s [%i] (%i,%i) %s", game_str_fl_inorbit, planet_i, p->x, p->y, ui_planet_str(g, api, planet_i, pname, sizeof(pname))); printf("%-40s", buf); for (int k = 0; k < NUM_SHIPDESIGNS; ++k) { printf(" %5i", r->ships[k]); } if (pi != api) { printf(" %s", game_str_tbl_race[g->eto[pi].race]); } putchar('\n'); } } /* -------------------------------------------------------------------------- */ void ui_fleet_print_fleets_orbit(const struct game_s *g, int api, uint8_t planet_i, bool show_my, bool show_opp) { if (show_my) { ui_fleet_print_fleet_orbit(g, api, planet_i, api); } if (show_opp) { for (int i = 0; i < g->players; ++i) { const fleet_orbit_t *r = &(g->eto[i].orbit[planet_i]); if ((i == api) || BOOLVEC_IS0(r->visible, api)) { continue; } ui_fleet_print_fleet_orbit(g, api, planet_i, i); } } } void ui_fleet_print_fleet_enroute(const struct game_s *g, int api, const fleet_enroute_t *r, uint8_t pon) { char buf[80]; char pname[20]; const planet_t *p = &(g->planet[r->dest]); lib_sprintf(buf, sizeof(buf), "#F%i (%i,%i) %s [%i] %s", (int)(r - g->enroute), r->x, r->y, game_str_fl_moving, r->dest, ui_planet_str(g, api, r->dest, pname, sizeof(pname))); printf("%-40s", buf); for (int k = 0; k < NUM_SHIPDESIGNS; ++k) { printf(" %5i", r->ships[k]); } if ((r->owner == api) || g->eto[api].have_ia_scanner) { int eta; if (pon == PLANET_NONE) { pon = get_fleet_planet_on(g, r); } eta = game_calc_eta_ship(g, game_fleet_get_speed(g, r, pon, r->dest), p->x, p->y, r->x, r->y); printf(" %s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } if (r->owner != api) { printf(" %s", game_str_tbl_race[g->eto[r->owner].race]); } putchar('\n'); } void ui_fleet_print_transport_enroute(const struct game_s *g, int api, const transport_t *r) { char buf[80]; char pname[20]; const empiretechorbit_t *e = &(g->eto[api]); int eta; const planet_t *p = &(g->planet[r->dest]); lib_sprintf(buf, sizeof(buf), "#T%i (%i,%i) %s [%i] %s", (int)(r - g->transport), r->x, r->y, game_str_fl_moving, r->dest, ui_planet_str(g, api, r->dest, pname, sizeof(pname))); printf("%-40s", buf); printf(" %5i", r->pop); eta = game_calc_eta_trans(g, e->have_engine, p->x, p->y, r->x, r->y); printf(" %s %i %s\n", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } int ui_cmd_fleet_list(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { { const empiretechorbit_t *e = &(g->eto[api]); const shipdesign_t *sd = &(g->srd[api].design[0]); for (int j = 0; j < e->shipdesigns_num; ++j) { printf("%c %s", (j == 0) ? '-' : ',', sd[j].name); } putchar('\n'); } for (int i = 0; i < g->galaxy_stars; ++i) { ui_fleet_print_fleet_orbit(g, api, i, api); } for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if ((r->owner == api) && BOOLVEC_IS1(r->visible, api)) { ui_fleet_print_fleet_enroute(g, api, r, PLANET_NONE); } } return 0; } int ui_cmd_fleet_redir(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const empiretechorbit_t *e = &(g->eto[api]); int sd_num = e->shipdesigns_num; if (num_param == 0) { for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (r->owner == api) { for (int j = 0; j < sd_num; ++j) { if (r->ships[j] != 0) { uint8_t pon; pon = get_fleet_planet_on(g, r); if (e->have_hyperspace_comm || (pon != PLANET_NONE)) { ui_fleet_print_fleet_enroute(g, api, r, pon); } break; } } } } if (e->have_hyperspace_comm) { for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (r->owner == api) { ui_fleet_print_transport_enroute(g, api, r); } } } } else if (num_param == 1) { return -1; } else { bool is_fleet; int dist, n = -1; uint8_t dest; const planet_t *p; if (param->str[0] != '#') { return -1; } if (tolower(param->str[1]) == 'f') { is_fleet = true; } else if (tolower(param->str[1]) == 't') { is_fleet = false; } else { return -1; } if (0 || (!util_parse_signed_number(¶m->str[2], &n)) || (n < 0) || (is_fleet && (n >= g->enroute_num)) || ((!is_fleet) && (n >= g->transport_num)) ) { return -1; } dest = ui_planet_from_param(g, api, ¶m[1]); if (dest == PLANET_NONE) { puts("Unknown destination"); return -1; } p = &(g->planet[dest]); dist = game_get_min_dist(g, api, dest); if (is_fleet) { fleet_enroute_t *r = &(g->enroute[n]); uint8_t pon; bool in_range; if (r->owner != api) { return -1; } pon = get_fleet_planet_on(g, r); if ((!e->have_hyperspace_comm) && (pon == PLANET_NONE)) { return -1; } if (game_num_retreat_redir_fix && r->retreat && (!e->have_hyperspace_comm) && (pon == dest)) { return -1; } in_range = false; if (p->within_frange[api] == 1) { in_range = true; } else if (p->within_frange[api] == 2) { in_range = true; for (int k = 0; k < e->shipdesigns_num; ++k) { if (r->ships[k] && (!g->srd[api].have_reserve_fuel[k])) { in_range = false; break; } } } if (!in_range) { printf("%s %i %s\n", game_str_sm_outsr, dist - e->fuel_range, game_str_sm_parsecs2); return -1; } game_fleet_redirect(g, r, pon, dest); } else { transport_t *r = &(g->transport[n]); if (0 || (r->owner != api) || (!e->have_hyperspace_comm) ) { return -1; } if (p->within_frange[api] != 1) { printf("%s %i %s\n", game_str_sm_outsr, dist - e->fuel_range, game_str_sm_parsecs2); return -1; } if (!game_transport_dest_ok(g, p, api)) { puts("Destination not OK"); return -1; } r->dest = dest; } } return 0; } int ui_cmd_fleet_send(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint8_t pti, pfi = g->planet_focus_i[api]; empiretechorbit_t *e = &(g->eto[api]); fleet_orbit_t *o = &(e->orbit[pfi]); const planet_t *pt; shipcount_t ships[NUM_SHIPDESIGNS]; pti = ui_planet_from_param(g, api, param); if (pti == PLANET_NONE) { puts("Unknown destination"); return -1; } if (pti == pfi) { puts("Not sending fleet to planet it is orbiting"); return -1; } pt = &(g->planet[pti]); { bool any_ships = false; int i; for (i = 0; i < e->shipdesigns_num; ++i) { ships[i] = o->ships[i]; if (ships[i] != 0) { any_ships = true; } } for (; i < NUM_SHIPDESIGNS; ++i) { ships[i] = 0; } if (!any_ships) { puts("No ships on orbit"); return -1; } } if (num_param > 1) { int i; for (i = 0; (i < e->shipdesigns_num) && (i < (num_param - 1)); ++i) { shipcount_t n; if (param[1 + i].type != INPUT_TOKEN_NUMBER) { printf("Invalid param %i\n", 1 + i); return -1; } n = param[1 + i].data.num; if (n > ships[i]) { printf("Trying to send more ships than you have (%i > %i)\n", n, ships[i]); return -1; } ships[i] = n; } for (; i < NUM_SHIPDESIGNS; ++i) { ships[i] = 0; } } { bool any_ships = false; for (int i = 0; i < e->shipdesigns_num; ++i) { if (ships[i] != 0) { any_ships = true; break; } } if (!any_ships) { puts("Not sending empty fleet"); return -1; } } { bool have_reserve_fuel = true; bool *hrf = &(g->srd[api].have_reserve_fuel[0]); for (int i = 0; i < e->shipdesigns_num; ++i) { if (ships[i] && (!hrf[i])) { have_reserve_fuel = false; break; } } if (!((pt->within_frange[api] == 1) || ((pt->within_frange[api] == 2) && have_reserve_fuel))) { puts("Out of range"); return -1; } } { const uint8_t shiptypes[NUM_SHIPDESIGNS] = { 0, 1, 2, 3, 4, 5 }; game_send_fleet_from_orbit(g, api, pfi, pti, ships, shiptypes, NUM_SHIPDESIGNS); } return 0; } int ui_cmd_fleet_scrap(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const empiretechorbit_t *e = &(g->eto[api]); const shipresearch_t *srd = &(g->srd[api]); int n = -1; if (e->shipdesigns_num <= 1) { return -1; } if (num_param == 0) { struct input_list_s rl_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 4, "5", NULL, NULL }, { 5, "6", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; int i; for (i = 0; i < e->shipdesigns_num; ++i) { rl_in[i].display = srd->design[i].name; } rl_in[i].value = -1; rl_in[i].key = "Q"; rl_in[i].str = "q"; rl_in[i].display = "(quit)"; ++i; rl_in[i].value = 0; rl_in[i].key = NULL; rl_in[i].str = NULL; rl_in[i].display = NULL; n = ui_input_list("Scrap", "> ", rl_in); } else { if (param->type == INPUT_TOKEN_NUMBER) { n = param->data.num; if ((n < 1) || (n > e->shipdesigns_num)) { return -1; } } else { for (int i = 0; i < e->shipdesigns_num; ++i) { if (strcasecmp(srd->design[i].name, param->str) == 0) { n = i; break; } } if (n == -1) { return -1; } } } if ((n >= 0) && (n < e->shipdesigns_num)) { game_design_scrap(g, api, n, var != NULL); } return 0; } 1oom-1.11.2/src/ui/cmdline/uifleet.h000066400000000000000000000017061476061725400171140ustar00rootroot00000000000000#ifndef INC_1OOM_UIFLEET_H #define INC_1OOM_UIFLEET_H #include "types.h" struct game_s; struct fleet_enroute_s; struct transport_s; struct input_token_s; extern void ui_fleet_print_fleets_orbit(const struct game_s *g, int api, uint8_t planet_i, bool show_my, bool show_opp); extern void ui_fleet_print_fleet_enroute(const struct game_s *g, int api, const struct fleet_enroute_s *r, uint8_t pon); extern void ui_fleet_print_transport_enroute(const struct game_s *g, int api, const struct transport_s *r); extern int ui_cmd_fleet_list(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_fleet_redir(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_fleet_send(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_fleet_scrap(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uigame.c000066400000000000000000000134771476061725400167310ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "game.h" #include "game_save.h" #include "game_shipdesign.h" #include "game_turn_start.h" #include "lib.h" #include "log.h" #include "types.h" #include "uicheat.h" #include "uicmds.h" #include "uidefs.h" #include "uidesign.h" #include "uiempire.h" #include "uiempirereport.h" #include "uiempirestats.h" #include "uifinished.h" #include "uifleet.h" #include "uihelp.h" #include "uiinput.h" #include "uiload.h" #include "uiplanet.h" #include "uiraces.h" #include "uispecs.h" #include "uiswitch.h" #include "uitech.h" #include "uiview.h" #include "util.h" /* -------------------------------------------------------------------------- */ static int cmd_next(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { return 0; } static const struct input_cmd_s * const cmdsptr_turn[3]; static const struct input_cmd_s cmds_turn[] = { { "?", NULL, "Help", 0, 0, 0, ui_cmd_help, (void *)cmdsptr_turn }, { "n", NULL, "Next turn", 0, 0, 0, cmd_next, 0 }, { "v", "[RANGE] [+DIST] [FILTERS]", "View galaxy up to RANGE and or DIST from planet\nFILTERS: Planet, Fleet, Transport,\n mY, Opponent,\n Unexplored, eXplored,\n uNcolonized, Colonized", 0, 3, 0, ui_cmd_view, 0 }, { "l", "[PLANET|*]", "Look at planet", 0, 1, 0, ui_cmd_planet_look, 0 }, { "g", "PLANET", "Go to planet", 1, 1, 0, ui_cmd_planet_go, 0 }, { "s", "SLIDER VALUE", "Set planet slider\nSLIDER is s, d, i, e or t\nVALUE can be +N or -N for relative adjustment", 2, 2, 0, ui_cmd_planet_slider, 0 }, { "sl", "SLIDER", "Toggle planet slider lock", 1, 1, 0, ui_cmd_planet_slider_lock, 0 }, { "b", "[SHIP]", "Select ship to build", 0, 1, 0, ui_cmd_planet_build, 0 }, { "bscrap", "VALUE", "Scrap missile bases", 1, 1, 0, ui_cmd_planet_scrap_bases, 0 }, { "reloc", "[PLANET]", "Relocate built ships to", 0, 1, 0, ui_cmd_planet_reloc, 0 }, { "trans", "[PLANET NUM]", "Transport troops to", 0, 2, 0, ui_cmd_planet_trans, 0 }, { "res", "[BC]", "Transfer reserves", 0, 1, 0, ui_cmd_planet_reserve, 0 }, { "fs", "PLANET [NUM]*", "Send fleet to\nAll ships are sent if no NUM given", 1, 7, 0, ui_cmd_fleet_send, 0 }, { "des", NULL, "Ship design", 0, 0, 0, ui_cmd_design, 0 }, { "fleet", NULL, "Display fleets", 0, 0, 0, ui_cmd_fleet_list, 0 }, { "scrap", "[SHIP]", "Scrap ship", 0, 1, 0, ui_cmd_fleet_scrap, 0 }, { "specs", "[SHIP]", "Show fleet specs", 0, 1, 0, ui_cmd_fleet_specs, 0 }, { "redir", "[#Fn|#Tn PLANET]", "Redirect fleet/transport to planet\nShows redirectable items if no params given", 0, 2, 0, ui_cmd_fleet_redir, 0 }, { "t", "[FIELD]", "View technology\nFIELD is c, o, f, p, r or w\nShows sliders if no field given", 0, 1, 0, ui_cmd_tech_look, 0 }, { "ts", "FIELD VALUE", "Set tech slider to value\nVALUE can be +N or -N for relative adjustment", 2, 2, 0, ui_cmd_tech_slider, 0 }, { "tsl", "FIELD", "Toggle tech slider lock", 1, 1, 0, ui_cmd_tech_slider_lock, 0 }, { "t=", NULL, "Equalize tech sliders", 0, 0, 0, ui_cmd_tech_equals, 0 }, { "emp", NULL, "Empire overview", 0, 0, 0, ui_cmd_empire_look, 0 }, { "tax", "VALUE", "Set tax (tenths of percent)\nVALUE can be +N or -N for relative adjustment", 1, 1, 0, ui_cmd_empire_tax, 0 }, { "races", NULL, "Show races", 0, 0, 0, ui_cmd_races, 0 }, { "stats", NULL, "Show stats", 0, 0, 0, ui_cmd_empirestats, 0 }, { "spy", "RACE VALUE|MODE", "Set spy spending (tenths of percent) or mode (Hide, Esp., Sabotage)\nVALUE can be +N or -N for relative adjustment", 2, 2, 0, ui_cmd_spy, 0 }, { "sec", "VALUE", "Set security spending (tenths of percent)\nVALUE can be +N or -N for relative adjustment", 1, 1, 0, ui_cmd_empire_security, 0 }, { "rep", NULL, "Show report", 0, 0, 0, ui_cmd_empirereport, 0 }, { "aud", NULL, "Audience", 0, 0, 0, ui_cmd_audience, 0 }, { "galaxy", NULL, NULL, 0, 0, 0, ui_cmd_cheat_galaxy, 0 }, { "events", NULL, NULL, 0, 0, 0, ui_cmd_cheat_events, 0 }, { "moola", NULL, NULL, 0, 0, 0, ui_cmd_cheat_moola, 0 }, { NULL, NULL, NULL, 0, 0, 0, NULL, 0 } }; static const struct input_cmd_s * const cmdsptr_turn[3] = { cmds_turn, ui_cmds_opts, NULL }; /* -------------------------------------------------------------------------- */ ui_turn_action_t ui_game_turn(struct game_s *g, int *load_game_i_ptr, int pi) { ui_switch_1_opts(g, pi); game_turn_start_messages(g, pi); ui_finished_print_all(g, pi); while (1) { char *input; char prompt[80], buf_planet_name[PLANET_NAME_LEN]; lib_sprintf(prompt, sizeof(prompt), "%s | %i | %s > ", g->emperor_names[pi], g->year + YEAR_BASE, ui_planet_str(g, pi, g->planet_focus_i[pi], buf_planet_name, sizeof(buf_planet_name))); input = ui_input_line(prompt); if ((ui_input_tokenize(input, cmdsptr_turn) == 0) && (ui_data.input.num > 0)) { if (ui_data.input.tok[0].type == INPUT_TOKEN_COMMAND) { const struct input_cmd_s *cmd; int v; cmd = ui_data.input.tok[0].data.cmd; v = cmd->handle(g, pi, &ui_data.input.tok[1], ui_data.input.num - 1, cmd->var); if (v >= 0) { if (cmd->handle == cmd_next) { return UI_TURN_ACT_NEXT_TURN; } if (cmd->handle == ui_cmd_load) { *load_game_i_ptr = v; return UI_TURN_ACT_LOAD_GAME; } if (cmd->handle == ui_cmd_quit) { return UI_TURN_ACT_QUIT_GAME; } } } } } } void ui_game_start(struct game_s *g) { BOOLVEC_CLEAR(ui_data.players_viewing, PLAYER_NUM); fputs("Welcome! Type ? to get the list of commands.\n", stdout); } void ui_game_end(struct game_s *g) { } 1oom-1.11.2/src/ui/cmdline/uigmap.c000066400000000000000000000006551476061725400167360ustar00rootroot00000000000000#include "config.h" #include "game.h" #include "game_aux.h" #include "ui.h" void *ui_gmap_basic_init(struct game_s *g, bool show_player_switch) { return 0; } void ui_gmap_basic_shutdown(void *ctx) { } void ui_gmap_basic_start_player(void *ctx, int pi) { } void ui_gmap_basic_start_frame(void *ctx, int pi) { } void ui_gmap_basic_draw_frame(void *ctx, int pi) { } void ui_gmap_basic_finish_frame(void *ctx, int pi) { } 1oom-1.11.2/src/ui/cmdline/uiground.c000066400000000000000000000070051476061725400173040ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_ground.h" #include "game_spy.h" #include "game_str.h" #include "game_tech.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ static void ui_ground_print_troops(struct ground_s *gr, const char **strrace) { printf("Ground | %i %s %s", gr->s[1].pop1, strrace[1], game_str_gr_troops); for (int i = 0; i < gr->s[1].strnum; ++i) { printf(", %s", gr->s[1].str[i]); } putchar('\n'); printf("Ground | %i %s %s", gr->s[0].pop1, gr->flag_rebel ? game_str_gr_rebel : strrace[0], game_str_gr_troops); for (int i = 0; i < gr->s[0].strnum; ++i) { printf(", %s", gr->s[0].str[i]); } putchar('\n'); } /* -------------------------------------------------------------------------- */ void ui_ground(struct game_s *g, struct ground_s *gr) { const char *strrace[2]; ui_switch_2(g, gr->s[0].player, gr->s[1].player); for (int i = 0; i < 2; ++i) { strrace[i] = game_str_tbl_race[g->eto[gr->s[i].player].race]; } fputs("Ground | ", stdout); printf("%s %s\n", game_str_gr_gcon, g->planet[gr->planet_i].name); fputs("Ground | ", stdout); if (!gr->flag_rebel) { printf("%i %s %i %s %s ", gr->inbound, game_str_gr_outof, gr->total_inbound, strrace[gr->flag_swap ? 1 : 0], game_str_gr_transs); printf("%s %s %s\n", game_str_gr_penetr, strrace[gr->flag_swap ? 0 : 1], game_str_gr_defenss); } else { printf("%i %s\n", gr->inbound, game_str_gr_reclaim); } ui_ground_print_troops(gr, strrace); fputs("Ground | ", stdout); printf("(*BANG* *ZZZAP* etc)\n"); while ((gr->s[0].pop1 != 0) && (gr->s[1].pop1 != 0)) { game_ground_kill(gr); } ui_ground_print_troops(gr, strrace); { int pop = gr->s[gr->flag_swap ? 1 : 0].pop1; fputs("Ground | ", stdout); if (pop != 0) { if (!gr->flag_swap) { printf("%s%s ", strrace[0], game_str_gr_scapt); } else { if (gr->flag_rebel) { printf("%s ", game_str_gr_itroops); } else { printf("%s%s ", strrace[1], game_str_gr_scapt); } } } else { const char *s; if (!gr->flag_swap) { s = strrace[1]; } else { if (gr->flag_rebel) { s = game_str_gr_rebel; } else { s = strrace[0]; } } printf("%s%s ", s, game_str_gr_succd); } printf("%s\n", g->planet[gr->planet_i].name); if ((pop > 0) && (!gr->flag_rebel)) { if (gr->fact > 0) { fputs("Ground | ", stdout); printf("%i %s\n", gr->fact, game_str_gr_fcapt); } if (gr->techchance > 0) { fputs("Ground | ", stdout); if (gr->flag_swap == gr->s[0].human) { fputs(game_str_gr_tsteal, stdout); for (int i = 0; i < gr->techchance; ++i) { char buf[0x80]; game_tech_get_name(g->gaux, gr->got[i].field, gr->got[i].tech, buf, sizeof(buf)); printf("%s %s", (i > 0) ? "," : ":", buf); } } else { fputs(game_str_gr_tnew, stdout); } putchar('\n'); } } } ui_switch_wait(g); } 1oom-1.11.2/src/ui/cmdline/uihelp.c000066400000000000000000000041531476061725400167370ustar00rootroot00000000000000#include "config.h" #include #include #include "lib.h" #include "uihelp.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ static int get_cmds_w(const struct input_cmd_s *cmds, int lmax) { int i = 0; while (cmds[i].str_cmd != NULL) { int l; l = strlen(cmds[i].str_cmd) + 1; if (cmds[i].str_param) { l += strlen(cmds[i].str_param); } if (l > lmax) { lmax = l; } ++i; } return lmax; } static int get_cmdsptr_w(const struct input_cmd_s * const *cmdsptr, int lmax) { const struct input_cmd_s *cmds; while ((cmds = *cmdsptr++) != NULL) { lmax = get_cmds_w(cmds, lmax); } return lmax; } static void show_cmds(const struct input_cmd_s * const *cmdsptr, int lmax) { char fmt1[16]; char fmt2[16]; const struct input_cmd_s *cmds; lib_sprintf(fmt1, sizeof(fmt1), " %%-%is ", lmax); lib_sprintf(fmt2, sizeof(fmt2), "%%s\n%%-%is", lmax + 5); while ((cmds = *cmdsptr++) != NULL) { int i; i = 0; while (cmds[i].str_cmd != NULL) { char buf[128]; if (cmds[i].str_help) { const char *p, *q; lib_sprintf(buf, sizeof(buf), "%s %s", cmds[i].str_cmd, cmds[i].str_param ? cmds[i].str_param : ""); printf(fmt1, buf); p = cmds[i].str_help; while ((q = strchr(p, '\n')) != NULL) { int len; len = q - p; memcpy(buf, p, len); buf[len] = '\0'; printf(fmt2, buf, ""); p = q + 1; } printf("%s\n", p); } ++i; } } } /* -------------------------------------------------------------------------- */ int ui_cmd_help(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const struct input_cmd_s * const *cmdsptr = var; int w; w = get_cmdsptr_w(cmdsptr, 0) + 1; show_cmds(cmdsptr, w); return 0; } 1oom-1.11.2/src/ui/cmdline/uihelp.h000066400000000000000000000003151476061725400167400ustar00rootroot00000000000000#ifndef INC_1OOM_UIHELP_H #define INC_1OOM_UIHELP_H struct game_s; struct input_token_s; extern int ui_cmd_help(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiinput.c000066400000000000000000000210051476061725400171410ustar00rootroot00000000000000#include "config.h" #include #include #include #include #ifdef HAVE_READLINE #include #include #endif #include "uiinput.h" #include "lib.h" #include "log.h" #include "types.h" #include "uidefs.h" #include "util.h" /* -------------------------------------------------------------------------- */ #define DEBUGLEVEL_INPUT 4 /* -------------------------------------------------------------------------- */ const struct input_list_s il_yes_no[] = { { 1, "Y", NULL, "Yes" }, { 0, "N", NULL, "No" }, { 0, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ static char *skip_whitespace(char *str) { char c = *str; while ((c == ' ') || (c == '\t')) { c = *++str; } return str; } static char *skip_and_end_token(char *str) { char c = *str; if (c == '"') { c = *++str; while ((c != '"') && (c != '\n') && (c != '\r') && (c != '\0')) { if (c == '\\') { c = *++str; } c = *++str; } if (c != '"') { log_error("Input: missing terminating '\"'\n"); return NULL; } } else { while ((c != ' ') && (c != '\t') && (c != '\n') && (c != '\r') && (c != '\0')) { c = *++str; } } *str = '\0'; if (c != '\0') { ++str; } return str; } /* -------------------------------------------------------------------------- */ bool ui_input_match_input(const char *in, const char *key, const char *str) { int len = strlen(in); if (len == 0) { return false; } if (key && (in[1] == 0) && (tolower(in[0]) == tolower(key[0]))) { return true; } if (str) { int i; for (i = 0; (i < len) && str[i]; ++i) { if (str[i] != tolower(in[i])) { return false; } } if (str[i] == 0) { return true; } } return false; } void ui_input_wait_enter(void) { ui_input_line("(press enter)"); } #ifdef HAVE_READLINE char *ui_input_line(const char *prompt) { static char *line = NULL; lib_free(line); line = readline(prompt); if ((line != 0) && (*line != 0)) { add_history(line); } else if (line == NULL) { log_message("(end of input)\n"); exit(0); } return line; } #else char *ui_input_line(const char *prompt) { static char line[1024]; line[sizeof(line) - 1] = 0; fputs(prompt, stdout); fflush(stdout); if (fgets(line, sizeof(line) - 1, stdin)) { char *p = line; char c; while (((c = *p) != 0) && (c != '\n') && (c != '\r')) { ++p; } *p = 0; return line; } else { log_message("(end of input)\n"); exit(0); } } #endif char *ui_input_line_len_trim(const char *prompt, int maxlen) { char *line; int len; line = ui_input_line(prompt); util_trim_whitespace(line, 1024); len = strlen(line); if (len > maxlen) { line[maxlen - 1] = 0; } return line; } int ui_input_list(const char *title, const char *prompt, const struct input_list_s *list) { const struct input_list_dyn_s listdyn = { list, 0, 0, 0 }; return ui_input_list_dynamic(title, prompt, &listdyn); } int ui_input_list_dynamic(const char *title, const char *prompt, const struct input_list_dyn_s *ld) { const struct input_list_s *l; char *in; int num_shortcuts = 0; char **shortcuts = NULL; const struct input_list_s *list = ld->list; l = list; while (ld->get_display ? ld->get_display(ld->ctx, l) : l->display) { ++num_shortcuts; ++l; } shortcuts = lib_malloc(num_shortcuts * sizeof(char *)); l = list; for (int i = 0; i < num_shortcuts; ++i, ++l) { const char *s; char *p; char c; s = ld->get_display ? ld->get_display(ld->ctx, l) : l->display; if (*s == '(') { ++s; } p = shortcuts[i] = lib_stralloc(s); while ((c = *p) != '\0') { *p++ = tolower(c); } } for (int i = 0; i < num_shortcuts; ++i) { int len; bool is_unique; is_unique = false; len = 0; while (!is_unique && shortcuts[i][++len]) { is_unique = true; for (int j = 0; j < num_shortcuts; ++j) { if ((i != j) && (strncmp(shortcuts[i], shortcuts[j], len) == 0)) { is_unique = false; break; } } if (is_unique && (len == 1)) { char c; c = toupper(shortcuts[i][0]); for (int j = 0; j < num_shortcuts; ++j) { if ((i != j) && list[j].key && (list[j].key[0] == c)) { is_unique = false; break; } } } } shortcuts[i][len] = '\0'; } while (1) { int i; putchar('\n'); if (title) { puts(title); } l = list; while ((l->str) || (l->key)) { const char *s; bool is_ok; if (ld->get_display) { s = ld->get_display(ld->ctx, l); is_ok = ld->is_ok(ld->ctx, l); } else { s = l->display; is_ok = true; } if (s) { printf(" %s) ", l->key); if (!is_ok) { putchar('('); } fputs(s, stdout); if (!is_ok) { putchar(')'); } putchar('\n'); } ++l; } in = ui_input_line(prompt); l = list; i = 0; while ((l->str) || (l->key)) { if (ui_input_match_input(in, l->key, l->str ? l->str : shortcuts[i])) { if (ld->is_ok && (!ld->is_ok(ld->ctx, l))) { break; } for (int j = 0; j < num_shortcuts; ++j) { lib_free(shortcuts[j]); } lib_free(shortcuts); return l->value; } ++l; ++i; } puts("???"); } } int ui_input_tokenize(char *inputbuf, const struct input_cmd_s * const *cmdsptr) { int num = 0; ui_data.input.num = 0; { char *p = inputbuf; p = skip_whitespace(p); if (*p == '#') { return 0; } while ((*p != '\0') && (*p != '\n') && (*p != '\r')) { ui_data.input.tok[num].str = p; ui_data.input.tok[num].data.ptr = 0; ui_data.input.tok[num].type = INPUT_TOKEN_UNKNOWN; p = skip_and_end_token(p); if ((p != NULL) && (num < UI_INPUT_TOKEN_MAX)) { ++num; } else { return -1; } p = skip_whitespace(p); } } for (int i = 0; i < num; ++i) { const char *p; p = ui_data.input.tok[i].str; if (p[0] != '"') { int v; if (util_parse_signed_number(p, &v)) { ui_data.input.tok[i].type = ((p[0] == '+') || (p[0] == '-')) ? INPUT_TOKEN_RELNUMBER : INPUT_TOKEN_NUMBER; ui_data.input.tok[i].data.num = v; } } else { ui_data.input.tok[i].str = p + 1; } LOG_DEBUG((DEBUGLEVEL_INPUT, "%s: tok %i t %i '%s' %i\n", __func__, i, ui_data.input.tok[i].type, ui_data.input.tok[i].str, ui_data.input.tok[i].data.num)); } if ((num > 0) && cmdsptr && (ui_data.input.tok[0].type == INPUT_TOKEN_UNKNOWN)) { const struct input_cmd_s *cmds; const char *p; p = ui_data.input.tok[0].str; while ((cmds = *cmdsptr++) != NULL) { while (cmds->str_cmd) { if (cmds->handle && (strcmp(cmds->str_cmd, p) == 0)) { if (((num - 1) < cmds->num_param_min) || ((num - 1) > cmds->num_param_max)) { log_error("Input: wrong number of parameters %i for '%s' (min %i, max %i)\n", num - 1, cmds->str_cmd, cmds->num_param_min, cmds->num_param_max); num = 0; } ui_data.input.tok[0].type = INPUT_TOKEN_COMMAND; ui_data.input.tok[0].data.cmd = cmds; goto done; } ++cmds; } } } done: ui_data.input.num = num; return 0; } 1oom-1.11.2/src/ui/cmdline/uiinput.h000066400000000000000000000017661476061725400171620ustar00rootroot00000000000000#ifndef INC_1OOM_UIINPUT_H #define INC_1OOM_UIINPUT_H #include "types.h" struct input_list_s { int value; const char *key; const char *str; const char *display; }; extern const struct input_list_s il_yes_no[]; struct input_list_dyn_s { const struct input_list_s *list; void *ctx; const char *(*get_display)(void *ctx, const struct input_list_s *l); bool (*is_ok)(void *ctx, const struct input_list_s *l); }; struct input_cmd_s; extern bool ui_input_match_input(const char *in, const char *key, const char *str); extern void ui_input_wait_enter(void); extern char *ui_input_line(const char *prompt); extern char *ui_input_line_len_trim(const char *prompt, int maxlen); extern int ui_input_list(const char *title, const char *prompt, const struct input_list_s *list); extern int ui_input_list_dynamic(const char *title, const char *prompt, const struct input_list_dyn_s *listdyn); extern int ui_input_tokenize(char *inputbuf, const struct input_cmd_s * const *cmdsptr); #endif 1oom-1.11.2/src/ui/cmdline/uiintro.c000066400000000000000000000010061476061725400171340ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" /* -------------------------------------------------------------------------- */ void ui_play_intro(void) { fputs("\n\n(imagine a view of a planet from orbit...\n" " names of dead companies...\n" " $GAME_TITLE\n" " ships shooting at missile bases...\n" " missile base shooting back...\n" " *BOOM*\n" " remaining ships warping out...\n" " credits roll by... intro over!)\n", stdout); } 1oom-1.11.2/src/ui/cmdline/uiload.c000066400000000000000000000032211476061725400167210ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game_save.h" #include "types.h" #include "uidefs.h" #include "uiinput.h" #include "util.h" /* -------------------------------------------------------------------------- */ int ui_load_game(void) { struct input_list_s lg_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 4, "5", NULL, NULL }, { 5, "6", NULL, NULL }, { 7, "7", NULL, NULL }, { 8, "8", NULL, NULL }, { 9, "9", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; int num = 0; for (int i = 0; i < NUM_ALL_SAVES; ++i) { if (game_save_tbl_have_save[i]) { lg_in[num].value = i; lg_in[num].display = game_save_tbl_name[i]; ++num; } } if (num == 0) { return -1; } lg_in[num].value = -1; lg_in[num].key = "Q"; lg_in[num].str = "q"; lg_in[num].display = "(quit)"; ++num; lg_in[num].value = 0; lg_in[num].key = NULL; lg_in[num].str = NULL; lg_in[num].display = NULL; return ui_input_list("Load game", "> ", lg_in); } int ui_cmd_load(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { if (num_param == 0) { return ui_load_game(); } else { int v; if (util_parse_signed_number(param->str, &v)) { if ((v >= 1) && (v <= NUM_ALL_SAVES)) { return v - 1; } else if ((v >= 2300) && (v <= 9999)) { return v; } } } return -1; } 1oom-1.11.2/src/ui/cmdline/uiload.h000066400000000000000000000004151476061725400167300ustar00rootroot00000000000000#ifndef INC_1OOM_UILOAD_H #define INC_1OOM_UILOAD_H struct input_token_s; /* returns -1 on cancel or 0..7 on load game */ extern int ui_load_game(void); extern int ui_cmd_load(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uimainmenu.c000066400000000000000000000306371476061725400176260ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "game_ai.h" #include "game_new.h" #include "game_str.h" #include "lib.h" #include "types.h" #include "uidefs.h" #include "uihelp.h" #include "uiinput.h" #include "uiload.h" /* -------------------------------------------------------------------------- */ static int ui_new_game_choose_race(struct game_new_options_s *newopts, player_id_t pi) { int v; struct input_list_s ng_race_in[] = { { RACE_HUMAN, "1", NULL, game_str_tbl_race[RACE_HUMAN] }, { RACE_MRRSHAN, "2", NULL, game_str_tbl_race[RACE_MRRSHAN] }, { RACE_SILICOID, "3", NULL, game_str_tbl_race[RACE_SILICOID] }, { RACE_SAKKRA, "4", NULL, game_str_tbl_race[RACE_SAKKRA] }, { RACE_PSILON, "5", NULL, game_str_tbl_race[RACE_PSILON] }, { RACE_ALKARI, "6", NULL, game_str_tbl_race[RACE_ALKARI] }, { RACE_KLACKON, "7", NULL, game_str_tbl_race[RACE_KLACKON] }, { RACE_BULRATHI, "8", NULL, game_str_tbl_race[RACE_BULRATHI] }, { RACE_MEKLAR, "9", NULL, game_str_tbl_race[RACE_MEKLAR] }, { RACE_DARLOK, "0", NULL, game_str_tbl_race[RACE_DARLOK] }, { RACE_RANDOM, "R", NULL, game_str_tbl_race[RACE_RANDOM] }, { -1, "Q", NULL, "(quit)" }, { 0, NULL, NULL, NULL }, }; if ((v = ui_input_list("Race", "> ", ng_race_in)) < 0) { return -1; } newopts->pdata[pi].race = v; return v; } static int ui_new_game_choose_banner(struct game_new_options_s *newopts, player_id_t pi) { int v; struct input_list_s ng_banner_in[] = { { BANNER_BLUE, "1", NULL, game_str_tbl_banner[BANNER_BLUE] }, { BANNER_GREEN, "2", NULL, game_str_tbl_banner[BANNER_GREEN] }, { BANNER_PURPLE, "3", NULL, game_str_tbl_banner[BANNER_PURPLE] }, { BANNER_RED, "4", NULL, game_str_tbl_banner[BANNER_RED] }, { BANNER_WHITE, "5", NULL, game_str_tbl_banner[BANNER_WHITE] }, { BANNER_YELLOW, "6", NULL, game_str_tbl_banner[BANNER_YELLOW] }, { BANNER_RANDOM, "7", NULL, game_str_tbl_banner[BANNER_RANDOM] }, { -1, "Q", NULL, "(quit)" }, { 0, NULL, NULL, NULL }, }; if ((v = ui_input_list("Banner", "> ", ng_banner_in)) < 0) { return -1; } newopts->pdata[pi].banner = v; return v; } static int ui_new_game_pname(struct game_new_options_s *newopts, player_id_t pi) { char *p; fputs("Your name\n", stdout); p = ui_input_line_len_trim("> ", EMPEROR_NAME_LEN); if (p[0] == '\0') { race_t race = newopts->pdata[pi].race; if (race < RACE_NUM) { game_new_generate_emperor_name(race, newopts->pdata[pi].playername, EMPEROR_NAME_LEN); } else { newopts->pdata[pi].playername[0] = '\0'; } } else { lib_strcpy(newopts->pdata[pi].playername, p, EMPEROR_NAME_LEN); } return 0; } static int ui_new_game_hname(struct game_new_options_s *newopts, player_id_t pi) { char *p; fputs("Home world\n", stdout); p = ui_input_line_len_trim("> ", PLANET_NAME_LEN); if (p[0] == '\0') { race_t race = newopts->pdata[pi].race; if (race < RACE_NUM) { game_new_generate_home_name(race, newopts->pdata[pi].homename, PLANET_NAME_LEN); } else { newopts->pdata[pi].homename[0] = '\0'; } } else { lib_strcpy(newopts->pdata[pi].homename, p, PLANET_NAME_LEN); } return 0; } static bool have_human(const struct game_new_options_s *newopts) { for (int j = 0; j < newopts->players; ++j) { if (!newopts->pdata[j].is_ai) { return true; } } return false; } static void ui_new_game_display(struct game_new_options_s *newopts) { for (int i = 0; i < newopts->players; ++i) { printf("%s %i: %s, %s", newopts->pdata[i].is_ai ? game_str_ng_computer : game_str_ng_player, i + 1, game_str_tbl_race[newopts->pdata[i].race], game_str_tbl_banner[newopts->pdata[i].banner]); if (newopts->pdata[i].playername[0]) { printf(", Emperor %s", newopts->pdata[i].playername); } if (newopts->pdata[i].homename[0]) { printf(", Home world %s", newopts->pdata[i].homename); } putchar('\n'); } printf("%s: %s\n", game_str_ng_ai, game_ais[newopts->ai_id]->name); if (!have_human(newopts)) { puts(game_str_ng_allai); } } static int cmd_exit(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_new_options_s *newopts = (struct game_new_options_s *)g; int v; v = (int)(intptr_t)var; if ((v == 2/*start*/) && (!have_human(newopts))) { v = 0; } return v; } static int cmd_toggle_computer(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_new_options_s *newopts = (struct game_new_options_s *)g; int n; if (param->type != INPUT_TOKEN_NUMBER) { return -1; } n = param->data.num; if ((n < 1) || (n > newopts->players)) { return -1; } --n; newopts->pdata[n].is_ai = !newopts->pdata[n].is_ai; return 0; } static int cmd_race(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_new_options_s *newopts = (struct game_new_options_s *)g; int n; race_t old_race, new_race; if (param->type != INPUT_TOKEN_NUMBER) { return -1; } n = param->data.num; if ((n < 1) || (n > newopts->players)) { return -1; } --n; old_race = newopts->pdata[n].race; if (ui_new_game_choose_race(newopts, n) < 0) { return -1; } new_race = newopts->pdata[n].race; if (new_race != old_race) { if (new_race < RACE_NUM) { game_new_generate_emperor_name(new_race, newopts->pdata[n].playername, EMPEROR_NAME_LEN); game_new_generate_home_name(new_race, newopts->pdata[n].homename, PLANET_NAME_LEN); } else { newopts->pdata[n].playername[0] = '\0'; newopts->pdata[n].homename[0] = '\0'; } } return 0; } static int cmd_choose(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct game_new_options_s *newopts = (struct game_new_options_s *)g; int (*func)(struct game_new_options_s *newopts, player_id_t pi) = var; int n; if (param->type != INPUT_TOKEN_NUMBER) { return -1; } n = param->data.num; if ((n < 1) || (n > newopts->players)) { return -1; } --n; if (func(newopts, n) < 0) { return -1; } return 0; } static int cmd_ai(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct input_list_s rl_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 4, "5", NULL, NULL }, { 5, "6", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; struct game_new_options_s *newopts = (struct game_new_options_s *)g; int num; for (num = 0; num < GAME_AI_NUM; ++num) { rl_in[num].value = num; rl_in[num].display = game_ais[num]->name; } rl_in[num].value = 0; rl_in[num].key = NULL; rl_in[num].str = NULL; rl_in[num].display = NULL; newopts->ai_id = ui_input_list(game_str_ng_ai, "> ", rl_in); return 0; } static bool ui_new_game_extra(struct game_new_options_s *newopts) { struct input_cmd_s cmds_newgame[] = { { "?", NULL, "Help", 0, 0, 0, ui_cmd_help, 0 }, { "q", NULL, game_str_ng_cancel, 0, 0, 0, cmd_exit, (void *)1/*cancel*/ }, { "s", NULL, game_str_ng_ok, 0, 0, 0, cmd_exit, (void *)2/*start*/ }, { "a", NULL, game_str_ng_ai, 0, 0, 0, cmd_ai, 0 }, { "c", "[PLAYER]", game_str_ng_computer, 1, 1, 0, cmd_toggle_computer, 0 }, { "r", "[PLAYER]", "Race", 1, 1, 0, cmd_race, 0 }, { "b", "[PLAYER]", "Banner", 1, 1, 0, cmd_choose, ui_new_game_choose_banner }, { "n", "[PLAYER]", "Emperor name", 1, 1, 0, cmd_choose, ui_new_game_pname }, { "h", "[PLAYER]", "Home word name", 1, 1, 0, cmd_choose, ui_new_game_hname }, { NULL, NULL, NULL, 0, 0, 0, NULL, 0 } }; const struct input_cmd_s * const cmdsptr_newgame[] = { cmds_newgame, NULL }; cmds_newgame[0].var = (void *)cmdsptr_newgame; ui_new_game_display(newopts); while (1) { char *input; input = ui_input_line("> "); if ((ui_input_tokenize(input, cmdsptr_newgame) == 0) && (ui_data.input.num > 0)) { if (ui_data.input.tok[0].type == INPUT_TOKEN_COMMAND) { const struct input_cmd_s *cmd; int v; cmd = ui_data.input.tok[0].data.cmd; v = cmd->handle((struct game_s *)newopts, 0, &ui_data.input.tok[1], ui_data.input.num - 1, cmd->var); if (cmd->handle == cmd_exit) { if (v == 1/*cancel*/) { return false; } else if (v == 2/*start*/) { return true; } } else { ui_new_game_display(newopts); } } } } } static bool ui_new_game(struct game_new_options_s *newopts) { int v; struct input_list_s ng_galaxy_in[] = { { 0, "1", NULL, game_str_tbl_gsize[0] }, { 1, "2", NULL, game_str_tbl_gsize[1] }, { 2, "3", NULL, game_str_tbl_gsize[2] }, { 3, "4", NULL, game_str_tbl_gsize[3] }, { -1, "Q", NULL, "(quit)" }, { 0, NULL, NULL, NULL }, }; struct input_list_s ng_diffic_in[] = { { 0, "1", NULL, game_str_tbl_diffic[0] }, { 1, "2", NULL, game_str_tbl_diffic[1] }, { 2, "3", NULL, game_str_tbl_diffic[2] }, { 3, "4", NULL, game_str_tbl_diffic[3] }, { 4, "5", NULL, game_str_tbl_diffic[4] }, { -1, "Q", NULL, "(quit)" }, { 0, NULL, NULL, NULL }, }; struct input_list_s ng_oppon_in[] = { { 2, "1", NULL, game_str_tbl_oppon[0] }, { 3, "2", NULL, game_str_tbl_oppon[1] }, { 4, "3", NULL, game_str_tbl_oppon[2] }, { 5, "4", NULL, game_str_tbl_oppon[3] }, { 6, "5", NULL, game_str_tbl_oppon[4] }, { -1, "Q", NULL, "(quit)" }, { 0, NULL, NULL, NULL }, }; if ((v = ui_input_list("Galaxy size", "> ", ng_galaxy_in)) < 0) { return false; } newopts->galaxy_size = v; if ((v = ui_input_list("Difficulty", "> ", ng_diffic_in)) < 0) { return false; } newopts->difficulty = v; if ((v = ui_input_list("Opponents", "> ", ng_oppon_in)) < 0) { return false; } newopts->players = v; if (ui_new_game_choose_race(newopts, PLAYER_0) < 0) { return false; } if (ui_new_game_choose_banner(newopts, PLAYER_0) < 0) { return false; } ui_new_game_pname(newopts, PLAYER_0); ui_new_game_hname(newopts, PLAYER_0); return ui_new_game_extra(newopts); } /* -------------------------------------------------------------------------- */ main_menu_action_t ui_main_menu(struct game_new_options_s *newopts, struct game_new_options_s *customopts, struct game_new_options_s *challengeopts, int *load_game_i_ptr) { struct input_list_s main_menu_in[] = { { MAIN_MENU_ACT_CONTINUE_GAME, "C", NULL, game_str_mm_continue }, { MAIN_MENU_ACT_LOAD_GAME, "L", NULL, game_str_mm_load }, { MAIN_MENU_ACT_NEW_GAME, "N", NULL, game_str_mm_new }, { MAIN_MENU_ACT_QUIT_GAME, "Q", NULL, game_str_mm_quit }, { MAIN_MENU_ACT_TUTOR, NULL, "tutor", NULL }, { MAIN_MENU_ACT_CUSTOM_GAME, "U", NULL, NULL }, { 0, NULL, NULL, NULL }, }; main_menu_action_t ret = MAIN_MENU_ACT_QUIT_GAME; bool flag_done = false; while (!flag_done) { ret = ui_input_list("Main menu", "> ", main_menu_in); switch (ret) { case MAIN_MENU_ACT_NEW_GAME: flag_done = ui_new_game(newopts); break; case MAIN_MENU_ACT_CUSTOM_GAME: flag_done = ui_new_game(customopts); break; case MAIN_MENU_ACT_LOAD_GAME: { int i; i = ui_load_game(); if (i >= 0) { *load_game_i_ptr = i; flag_done = true; } } break; default: flag_done = true; break; } } return ret; } 1oom-1.11.2/src/ui/cmdline/uinews.c000066400000000000000000000013721476061725400167630ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_news.h" #include "log.h" #include "types.h" #include "uidefs.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ void ui_news_start(void) { } void ui_news(struct game_s *g, struct news_s *ns) { ui_switch_all(g); game_news_get_msg(g, ns, ui_data.strbuf, UI_STRBUF_SIZE); printf("GNN | %s", ui_data.strbuf); if (ns->type == GAME_NEWS_STATS) { for (int i = 0; i < ns->statsnum; ++i) { if (i > 0) { putchar(','); } printf(" %i. %s", i + 1, ns->stats[i]); } } putchar('\n'); ui_switch_wait(g); } void ui_news_end(void) { } 1oom-1.11.2/src/ui/cmdline/uinewtech.c000066400000000000000000000217171476061725400174510ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_diplo.h" #include "game_misc.h" #include "game_num.h" #include "game_str.h" #include "game_tech.h" #include "game_techtypes.h" #include "lib.h" #include "rnd.h" #include "uidefs.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct newtech_data_s { struct game_s *g; player_id_t api; newtech_t nt; uint8_t dialog_type; bool flag_is_current; bool flag_choose_next; uint8_t tech_next[TECH_NEXT_MAX]; int num_next; }; /* -------------------------------------------------------------------------- */ static void ui_newtech_print1(struct newtech_data_s *d) { const struct game_s *g = d->g; puts(game_tech_get_newtech_msg(g, d->api, &(d->nt), ui_data.strbuf, UI_STRBUF_SIZE)); if (d->nt.source != TECHSOURCE_CHOOSE) { puts(game_tech_get_name(g->gaux, d->nt.field, d->nt.tech, ui_data.strbuf, UI_STRBUF_SIZE)); puts(game_tech_get_descr(g->gaux, d->nt.field, d->nt.tech, ui_data.strbuf, UI_STRBUF_SIZE)); } } static void ui_newtech_choose_next(struct newtech_data_s *d) { struct input_list_s rl_in[] = { { -1, "1", NULL, NULL }, { -1, "2", NULL, NULL }, { -1, "3", NULL, NULL }, { -1, "4", NULL, NULL }, { -1, "5", NULL, NULL }, { -1, "6", NULL, NULL }, { -1, "7", NULL, NULL }, { -1, "8", NULL, NULL }, { -1, "9", NULL, NULL }, { -1, "A", NULL, NULL }, { -1, "B", NULL, NULL }, { -1, "C", NULL, NULL }, { 0, NULL, NULL, NULL } }; char tname[TECH_NEXT_MAX][35]; int i; for (i = 0; i < d->num_next; ++i) { uint8_t tech; tech = d->tech_next[i]; game_tech_get_name(d->g->gaux, d->nt.field, tech, tname[i], 35); rl_in[i].value = tech; rl_in[i].display = tname[i]; } rl_in[i].value = 0; rl_in[i].key = NULL; rl_in[i].str = NULL; rl_in[i].display = NULL; i = ui_input_list(game_str_nt_choose, "> ", rl_in); game_tech_start_next(d->g, d->api, d->nt.field, i); } static void newtech_adjust_draw_typestr(char *buf, size_t bufsize, const char *str1, const char *str2) { lib_strcat(buf, game_str_nt_inc, bufsize); lib_strcat(buf, str1, bufsize); if (str2) { lib_strcat(buf, str2, bufsize); } } static void ui_newtech_adjust(struct newtech_data_s *d) { char *buf = ui_data.strbuf; lib_strcpy(buf, game_str_nt_doyou, UI_STRBUF_SIZE); switch (d->dialog_type) { case 0: lib_strcat(buf, game_str_nt_redueco, UI_STRBUF_SIZE); break; case 1: newtech_adjust_draw_typestr(buf, UI_STRBUF_SIZE, game_str_nt_ind, 0); break; case 2: newtech_adjust_draw_typestr(buf, UI_STRBUF_SIZE, game_str_nt_ecoall, game_str_nt_terra); break; case 3: newtech_adjust_draw_typestr(buf, UI_STRBUF_SIZE, game_str_nt_def, 0); break; case 4: newtech_adjust_draw_typestr(buf, UI_STRBUF_SIZE, game_str_nt_ecostd, game_str_nt_terra); break; case 5: newtech_adjust_draw_typestr(buf, UI_STRBUF_SIZE, game_str_nt_ecohost, game_str_nt_terra); break; default: break; } if (d->dialog_type == 0) { int v = ui_input_list(buf, "> ", il_yes_no); if (v) { game_update_tech_util(d->g); game_update_eco_on_waste(d->g, d->api, true); } } else { struct input_list_s rl_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 0, NULL, NULL, NULL } }; const int tbl_a0[5] = { 0, 0, 0, 1, 2 }; const int tbl_a2[5] = { 0, 3, 2, 3, 3 }; int v; for (int i = 0; i < 4; ++i) { rl_in[i].display = game_str_tbl_nt_adj[i]; } v = ui_input_list(buf, "> ", rl_in); game_update_tech_util(d->g); if (!game_num_newtech_adjust_fix) { game_update_eco_on_waste(d->g, d->api, true); } game_planet_adjust_percent(d->g, d->api, tbl_a0[d->dialog_type - 1], game_num_tbl_tech_autoadj[v], tbl_a2[d->dialog_type - 1]); } } static void ui_newtech_do(struct newtech_data_s *d) { struct game_s *g = d->g; empiretechorbit_t *e = &(g->eto[d->api]); uint8_t tech = d->nt.tech; bool flag_dialog = false; if (tech < 51) { if ((d->nt.field == TECH_FIELD_CONSTRUCTION) && (((tech - 5) % 10) == 0) && (g->evn.best_wastereduce[d->api] < tech)) { flag_dialog = true; d->dialog_type = 0; g->evn.best_wastereduce[d->api] = tech; } if ((d->nt.field == TECH_FIELD_PLANETOLOGY) && (g->evn.best_ecorestore[d->api] < tech)) { if (0 || (tech == TECH_PLAN_IMPROVED_ECO_RESTORATION) || (tech == TECH_PLAN_ENHANCED_ECO_RESTORATION) || (tech == TECH_PLAN_ADVANCED_ECO_RESTORATION) || (tech == TECH_PLAN_COMPLETE_ECO_RESTORATION) ) { flag_dialog = true; d->dialog_type = 0; g->evn.best_ecorestore[d->api] = tech; } } if (e->race == RACE_SILICOID) { flag_dialog = false; } if ((d->nt.field == TECH_FIELD_COMPUTER) && (((tech - 8) % 10) == 0) && (g->evn.best_roboctrl[d->api] < tech)) { flag_dialog = true; d->dialog_type = 1; g->evn.best_roboctrl[d->api] = tech; } if (d->nt.field == TECH_FIELD_PLANETOLOGY) { if ((((tech - 2) % 6) == 0) && (g->evn.best_terraform[d->api] < tech)) { flag_dialog = true; d->dialog_type = 2; g->evn.best_terraform[d->api] = tech; } if ((tech == TECH_PLAN_SOIL_ENRICHMENT) || (tech == TECH_PLAN_ADVANCED_SOIL_ENRICHMENT)) { flag_dialog = true; d->dialog_type = 4; } if (tech == TECH_PLAN_ATMOSPHERIC_TERRAFORMING) { flag_dialog = true; d->dialog_type = 5; } } if ((d->nt.field == TECH_FIELD_FORCE_FIELD) && (((tech - 12) % 10) == 0)) { flag_dialog = true; d->dialog_type = 3; } } ui_newtech_print1(d); again: if (d->flag_choose_next) { nexttech_t *xt = &(g->evn.newtech[d->api].next[d->nt.field]); d->num_next = xt->num; if (d->num_next == 0) { return; } memcpy(d->tech_next, xt->tech, d->num_next); d->nt.frame = false; d->nt.source = TECHSOURCE_CHOOSE; ui_newtech_choose_next(d); } else { if (d->nt.frame) { struct input_list_s rl_in[] = { { -1, "1", NULL, NULL }, { -1, "2", NULL, NULL }, { -1, "0", NULL, "(none)" }, { 0, NULL, NULL, NULL } }; int frame; rl_in[0].value = d->nt.other1; rl_in[0].display = game_str_tbl_races[g->eto[d->nt.other1].race]; rl_in[1].value = d->nt.other2; rl_in[1].display = game_str_tbl_races[g->eto[d->nt.other2].race]; puts(game_str_nt_frame); frame = ui_input_list(game_str_nt_victim, "> ", rl_in); if (frame >= 0) { g->evn.stolen_spy[d->nt.stolen_from][d->api] = frame; game_diplo_esp_frame(g, frame, d->nt.stolen_from); } } if (flag_dialog) { ui_newtech_adjust(d); } if (d->flag_is_current) { d->flag_is_current = false; d->flag_choose_next = true; d->nt.frame = false; goto again; } } } /* -------------------------------------------------------------------------- */ void ui_newtech(struct game_s *g, int pi) { struct newtech_data_s d; bool flag_switch = false; d.g = g; d.api = pi; for (int i = 0; i < g->evn.newtech[pi].num; ++i) { d.nt = g->evn.newtech[pi].d[i]; if (!flag_switch) { flag_switch = true; ui_switch_1(g, pi); } d.flag_is_current = false; d.flag_choose_next = false; if (g->eto[pi].tech.project[d.nt.field] == d.nt.tech) { d.flag_is_current = true; } ui_newtech_do(&d); } for (tech_field_t field = 0; field < TECH_FIELD_NUM; ++field) { if (game_tech_can_choose(g, pi, field)) { if (!flag_switch) { flag_switch = true; ui_switch_1(g, pi); } d.nt.field = field; d.nt.tech = 0; d.nt.source = TECHSOURCE_CHOOSE; d.flag_choose_next = true; d.nt.frame = false; ui_newtech_do(&d); } } if (flag_switch) { ui_switch_wait(g); } g->evn.newtech[pi].num = 0; } 1oom-1.11.2/src/ui/cmdline/uiplanet.c000066400000000000000000000451201476061725400172710ustar00rootroot00000000000000#include "config.h" #include #include #include "uiplanet.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_planet.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "uidefs.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void ui_planet_print_orbit_if_visible(const struct game_s *g, player_id_t api, uint8_t planet_i, player_id_t owner) { const empiretechorbit_t *e = &(g->eto[owner]); const fleet_orbit_t *o = &(e->orbit[planet_i]); if (BOOLVEC_IS1(o->visible, api)) { bool any_ships = false; for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { if (o->ships[i] != 0) { any_ships = true; break; } } if (any_ships) { printf(" - %s fleet at orbit:", game_str_tbl_race[e->race]); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { printf(" %5i", o->ships[i]); } putchar('\n'); } } } static void ui_planet_print_visible_fleets(const struct game_s *g, player_id_t api, uint8_t planet_i) { const empiretechorbit_t *e = &(g->eto[api]); const planet_t *p = &(g->planet[planet_i]); for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); if (BOOLVEC_IS1(r->visible, api) && (r->dest == planet_i) && ((r->owner == api) || e->have_ia_scanner)) { printf(" - %s fleet ETA %i turns:", game_str_tbl_race[e->race], game_calc_eta_ship(g, r->speed, p->x, p->y, r->x, r->y)); for (int i = 0; i < NUM_SHIPDESIGNS; ++i) { printf(" %5i", r->ships[i]); } putchar('\n'); } } } static void ui_planet_print_visible_transports(const struct game_s *g, player_id_t api, uint8_t planet_i) { const empiretechorbit_t *e = &(g->eto[api]); const planet_t *p = &(g->planet[planet_i]); for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); if (BOOLVEC_IS1(r->visible, api) && (r->dest == planet_i) && ((r->owner == api) || e->have_ia_scanner)) { printf(" - %s transport %i ETA %i turns\n", game_str_tbl_race[e->race], r->pop, game_calc_eta_trans(g, r->speed, p->x, p->y, r->x, r->y)); } } } planet_slider_i_t ui_planet_slider_from_param(struct input_token_s *param) { char slchars[] = "sdiet"; char c = param->str[0]; char *p = strchr(slchars, c); if (p) { return (p - slchars); } else { return PLANET_SLIDER_NUM; } } /* -------------------------------------------------------------------------- */ const char *ui_planet_str(const struct game_s *g, int api, uint8_t planet_i, char *buf, size_t bufsize) { const planet_t *p = &(g->planet[planet_i]); if (BOOLVEC_IS1(p->explored, api)) { return p->name; } else if ((p->owner != PLAYER_NONE) && (0 || BOOLVEC_IS1(p->within_srange, api) || (p->within_frange[api] == 1) || (planet_i == g->evn.planet_orion_i) )) { return p->name; } else { lib_sprintf(buf, bufsize, "#%c%i", game_str_tbl_sm_stinfo[p->star_type][0]/*HACK*/, planet_i); return buf; } } uint8_t ui_planet_from_param(struct game_s *g, int api, struct input_token_s *param) { int n = PLANET_NONE; if (param->type == INPUT_TOKEN_NUMBER) { n = param->data.num; if ((n < 0) || (n >= g->galaxy_stars)) { n = PLANET_NONE; } } if (param->type == INPUT_TOKEN_RELNUMBER) { int dir, num = param->data.num; n = g->planet_focus_i[api]; if (num < 0) { dir = -1; num = -num; } else { dir = 1; } while (num) { do { n += dir; if (n < 0) { n = g->galaxy_stars - 1; } else if (n >= g->galaxy_stars) { n = 0; } } while (g->planet[n].owner != api); --num; } } else if ((param->str[0] == '#') && (param->str[1] != '\0') && (param->str[2] != '\0')) { if (0 || (!util_parse_signed_number(¶m->str[2], &n)) || (n < 0) || (n >= g->galaxy_stars) || (param->str[1] != game_str_tbl_sm_stinfo[g->planet[n].star_type][0]/*HACK*/) ) { n = PLANET_NONE; } } if (n == PLANET_NONE) { for (n = 0; n < g->galaxy_stars; ++n) { const planet_t *p = &(g->planet[n]); if (BOOLVEC_IS1(p->explored, api) && (strcasecmp(p->name, param->str) == 0)) { break; } } } if ((n >= 0) && (n < g->galaxy_stars)) { return n; } return PLANET_NONE; } void ui_planet_look(const struct game_s *g, int api, uint8_t planet_i, bool show_full) { const planet_t *p = &(g->planet[planet_i]); const empiretechorbit_t *e = &(g->eto[api]); int dist = game_get_min_dist(g, api, planet_i); { char buf[16]; printf("[%i] (%i,%i) %s: ", planet_i, p->x, p->y, ui_planet_str(g, api, planet_i, buf, sizeof(buf))); if (game_xy_is_in_nebula(g, p->x, p->y)) { printf("(In nebula)\n"); } } if (BOOLVEC_IS1(p->explored, api)) { if (p->type == PLANET_TYPE_NOT_HABITABLE) { printf("%s %s\n", game_str_sm_nohabit, game_str_sm__planets); } else { player_id_t owner = p->owner; const char *str = NULL; printf("%s, %s %i %s", game_str_tbl_sm_pltype[p->type], game_str_sm_pop, p->max_pop3, game_str_sm_max); if (p->special != PLANET_SPECIAL_NORMAL) { printf(", %s", game_str_tbl_sm_pspecial[p->special]); } if (p->growth != PLANET_GROWTH_NORMAL) { printf(", %s", game_str_tbl_sm_pgrowth[p->growth]); } if (g->evn.have_plague && (g->evn.plague_planet_i == planet_i)) { str = game_str_sm_plague; } else if (g->evn.have_nova && (g->evn.nova_planet_i == planet_i)) { str = game_str_sm_nova; } else if (g->evn.have_comet && (g->evn.comet_planet_i == planet_i)) { str = game_str_sm_comet; } else if (g->evn.have_pirates && (g->evn.pirates_planet_i == planet_i)) { str = game_str_sm_pirates; } else if (p->unrest == PLANET_UNREST_REBELLION) { str = game_str_sm_rebellion; } else if (p->unrest == PLANET_UNREST_UNREST) { str = game_str_sm_unrest; } else if (g->evn.have_accident && (g->evn.accident_planet_i == planet_i)) { str = game_str_sm_accident; } if (str) { printf(", %s", str); } if (BOOLVEC_IS0(p->within_srange, api) && ((owner == PLAYER_NONE) || BOOLVEC_IS0(e->contact, owner))) { owner = g->seen[api][planet_i].owner; } if (owner == PLAYER_NONE) { printf(". No colony. %s %i %s\n", game_str_sm_range, dist, (dist == 1) ? game_str_sm_parsec : game_str_sm_parsecs); } else if ((owner != api) || (p->unrest == PLANET_UNREST_REBELLION)) { int pop, bases; if (BOOLVEC_IS0(p->within_srange, api)) { printf("%s ", game_str_sm_lastrep); pop = g->seen[api][planet_i].pop; bases = g->seen[api][planet_i].bases; } else { pop = p->pop; bases = p->missile_bases; } printf(". %s %s. Pop %i, bases %i. %s %i %s\n", game_str_tbl_race[g->eto[owner].race], game_str_sm_colony, pop, bases, game_str_sm_range, dist, (dist == 1) ? game_str_sm_parsec : game_str_sm_parsecs); } else { printf(", pop %i, bases %i, factories %i, prod %i (%i), waste %i\n", p->pop, p->missile_bases, p->factories, p->prod_after_maint, p->total_prod, p->waste); if (show_full) { char buf[10]; int v; v = game_planet_get_slider_text(g, p, PLANET_SLIDER_SHIP, buf, sizeof(buf)); printf(" - Build "); if (p->buildship == BUILDSHIP_STARGATE) { printf("%s\n", game_str_sm_stargate); } else { printf("%i %s\n", v, g->srd[api].design[p->buildship].name); } printf(" - Slider %cSHIP %3i %s\n", p->slider_lock[PLANET_SLIDER_SHIP] ? '*' : ' ', p->slider[PLANET_SLIDER_SHIP], buf); game_planet_get_slider_text(g, p, PLANET_SLIDER_DEF, buf, sizeof(buf)); printf(" - Slider %c DEF %3i %s\n", p->slider_lock[PLANET_SLIDER_DEF] ? '*' : ' ', p->slider[PLANET_SLIDER_DEF], buf); game_planet_get_slider_text(g, p, PLANET_SLIDER_IND, buf, sizeof(buf)); printf(" - Slider %c IND %3i %s\n", p->slider_lock[PLANET_SLIDER_IND] ? '*' : ' ', p->slider[PLANET_SLIDER_IND], buf); v = game_planet_get_slider_text_eco(g, p, true, buf, sizeof(buf)); printf(" - Slider %c ECO %3i ", p->slider_lock[PLANET_SLIDER_ECO] ? '*' : ' ', p->slider[PLANET_SLIDER_ECO]); if (v >= 0) { if (v < 100) { printf("+%i.%i ", v / 10, v % 10); } else { printf("+%i ", v / 10); } } printf("%s\n", buf); game_planet_get_slider_text(g, p, PLANET_SLIDER_TECH, buf, sizeof(buf)); printf(" - Slider %cTECH %3i %s RP\n", p->slider_lock[PLANET_SLIDER_TECH] ? '*' : ' ', p->slider[PLANET_SLIDER_TECH], buf); if (p->reloc != planet_i) { printf(" - Reloc to %s\n", g->planet[p->reloc].name); } if ((p->trans_num != 0) && (p->trans_dest != PLANET_NONE)) { const planet_t *pt = &(g->planet[p->trans_dest]); printf(" - Transport %i to %s", p->trans_num, pt->name); if (p->have_stargate && pt->have_stargate && (p->owner == pt->owner)) { printf(" via %s.\n", game_str_sm_stargate); } else { int eta, engine = e->have_engine; eta = game_calc_eta_trans(g, engine, p->x, p->y, pt->x, pt->y); printf(". %s %i %s.\n", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } } } } } } else { printf("%s. %s %i %s.", game_str_sm_unexplored, game_str_sm_range, dist, (dist == 1) ? game_str_sm_parsec : game_str_sm_parsecs); if ((p->owner != PLAYER_NONE) && (0 || BOOLVEC_IS1(p->within_srange, api) || (p->within_frange[api] == 1) || (planet_i == g->evn.planet_orion_i) )) { printf(" %s %s", game_str_tbl_race[g->eto[p->owner].race], game_str_sm_colony); } putchar('\n'); } ui_planet_print_orbit_if_visible(g, api, planet_i, api); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (pi != api) { ui_planet_print_orbit_if_visible(g, api, planet_i, pi); } } ui_planet_print_visible_fleets(g, api, planet_i); ui_planet_print_visible_transports(g, api, planet_i); } int ui_cmd_planet_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint8_t pi; if (num_param == 0) { pi = g->planet_focus_i[api]; } else { pi = ui_planet_from_param(g, api, param); if (pi == PLANET_NONE) { if (param->str[0] == '*') { if (param->str[1] == '\0') { for (pi = 0; pi < g->galaxy_stars; ++pi) { ui_planet_look(g, api, pi, true); } return 0; } } } } if (pi != PLANET_NONE) { ui_planet_look(g, api, pi, true); return 0; } else { return -1; } } int ui_cmd_planet_go(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint8_t planet_i = ui_planet_from_param(g, api, param); if (planet_i != PLANET_NONE) { g->planet_focus_i[api] = planet_i; return 0; } else { return -1; } } int ui_cmd_planet_slider(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { planet_t *p = &(g->planet[g->planet_focus_i[api]]); planet_slider_i_t si = ui_planet_slider_from_param(param); int v; if (si == PLANET_SLIDER_NUM) { return -1; } if (p->owner != api) { return -1; } if (param[1].type == INPUT_TOKEN_NUMBER) { v = param[1].data.num; } else if (param[1].type == INPUT_TOKEN_RELNUMBER) { v = p->slider[si] + param[1].data.num; } else { return -1; } SETRANGE(v, 0, 100); if (p->slider_lock[si] == 0) { p->slider[si] = v; game_adjust_slider_group(p->slider, si, p->slider[si], PLANET_SLIDER_NUM, p->slider_lock); } return 0; } int ui_cmd_planet_slider_lock(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { planet_t *p = &(g->planet[g->planet_focus_i[api]]); planet_slider_i_t si = ui_planet_slider_from_param(param); if (p->owner != api) { return -1; } p->slider_lock[si] = !p->slider_lock[si]; return 0; } int ui_cmd_planet_build(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { planet_t *p = &(g->planet[g->planet_focus_i[api]]); const empiretechorbit_t *e = &(g->eto[api]); if (p->owner != api) { return -1; } if (num_param == 0) { int n; n = p->buildship + 1; if (n >= e->shipdesigns_num) { if (n >= (NUM_SHIPDESIGNS + 1)) { n = 0; } else if (e->have_stargates && !p->have_stargate) { n = BUILDSHIP_STARGATE; } else { n = 0; } } p->buildship = n; } else { /* TODO handle param */ return -1; } if (p->buildship == BUILDSHIP_STARGATE) { printf("Building %s\n", game_str_sm_stargate); } else { printf("Building %s\n", g->srd[api].design[p->buildship].name); } return 0; } int ui_cmd_planet_reloc(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint8_t pfi, pti; planet_t *pf; pfi = g->planet_focus_i[api]; pf = &(g->planet[pfi]); if (pf->owner != api) { return -1; } if (num_param == 0) { pti = pfi; } else { pti = ui_planet_from_param(g, api, param); if ((pti == PLANET_NONE) || !game_reloc_dest_ok(g, pti, api)) { return -1; } } pf->reloc = pti; return 0; } int ui_cmd_planet_trans(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint8_t pfi, pti; planet_t *pf; char buf[0x80]; int v = 0; pfi = g->planet_focus_i[api]; pf = &(g->planet[pfi]); if (pf->owner != api) { return -1; } if (num_param == 0) { pti = pfi; } else if (num_param == 1) { return -1; } else { const planet_t *pt; const empiretechorbit_t *e = &(g->eto[api]); int trans_max = pf->pop / 2; pti = ui_planet_from_param(g, api, param); if (pti == PLANET_NONE) { return -1; } pt = &(g->planet[pti]); if (param[1].type != INPUT_TOKEN_NUMBER) { return -1; } v = param[1].data.num; if (v > trans_max) { printf("Can transport at most %i from %s.\n", trans_max, pf->name); return -1; } if (pt->within_frange[api] != 1) { int mindist = game_get_min_dist(g, api, pti); printf("%s %i %s %i %s\n", game_str_sm_notrange1, mindist, game_str_sm_notrange2, e->fuel_range, game_str_sm_notrange3); return -1; } else if (BOOLVEC_IS0(pt->explored, api)) { puts(game_str_sm_trfirste); return -1; } else if (pt->type < e->have_colony_for) { int pos; pos = lib_sprintf(buf, sizeof(buf), "%s ", game_str_sm_trcontr1); lib_sprintf(&buf[pos], sizeof(buf) - pos, "%s ", game_str_tbl_sm_pltype[pt->type]); util_str_tolower(&buf[pos], sizeof(buf)); printf("%s %s\n", buf, game_str_sm_trcontr2); return -1; } else if (pt->owner == PLAYER_NONE) { puts(game_str_sm_trfirstc); return -1; } else { if (pf->have_stargate && pt->have_stargate && (pf->owner == pt->owner)) { lib_strcpy(buf, game_str_sm_stargate, sizeof(buf)); } else { int eta, engine = e->have_engine; eta = game_calc_eta_trans(g, engine, pf->x, pf->y, pt->x, pt->y); lib_sprintf(buf, sizeof(buf), "%s %i %s", game_str_sm_eta, eta, (eta == 1) ? game_str_sm_turn : game_str_sm_turns); } puts(buf); } } pf->trans_dest = pti; pf->trans_num = v; return 0; } int ui_cmd_planet_reserve(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { planet_t *p = &(g->planet[g->planet_focus_i[api]]); empiretechorbit_t *e = &(g->eto[api]); int v; if (p->owner != api) { return -1; } if (num_param == 0) { int prod = p->prod_after_maint - p->reserve; SETMAX(prod, 0); v = e->reserve_bc; SETMIN(v, prod); } else if (param[0].type == INPUT_TOKEN_NUMBER) { v = param[0].data.num; if (v > e->reserve_bc) { return -1; } } else { return -1; } p->reserve += v; e->reserve_bc -= v; game_update_production(g); return 0; } int ui_cmd_planet_scrap_bases(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { planet_t *p = &(g->planet[g->planet_focus_i[api]]); int v; if (p->owner != api) { return -1; } if (param[0].type == INPUT_TOKEN_NUMBER) { v = param[0].data.num; if (v > p->missile_bases) { return -1; } } else { return -1; } p->missile_bases -= v; g->eto[api].reserve_bc += (v * game_get_base_cost(g, api)) / 4; return 0; } 1oom-1.11.2/src/ui/cmdline/uiplanet.h000066400000000000000000000026651476061725400173050ustar00rootroot00000000000000#ifndef INC_1OOM_UIPLANET_H #define INC_1OOM_UIPLANET_H #include "types.h" struct game_s; struct input_token_s; extern const char *ui_planet_str(const struct game_s *g, int api, uint8_t planet_i, char *buf, size_t bufsize); extern uint8_t ui_planet_from_param(struct game_s *g, int api, struct input_token_s *param); extern void ui_planet_look(const struct game_s *g, int api, uint8_t planet_i, bool show_full); extern int ui_cmd_planet_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_go(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_slider(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_slider_lock(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_build(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_reloc(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_trans(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_reserve(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_planet_scrap_bases(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiraces.c000066400000000000000000000166631476061725400171150ustar00rootroot00000000000000#include "config.h" #include #include #include #include "uiraces.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_audience.h" #include "game_diplo.h" #include "game_str.h" #include "lib.h" #include "uidefs.h" #include "uiinput.h" #include "util.h" /* -------------------------------------------------------------------------- */ /* -------------------------------------------------------------------------- */ player_id_t ui_player_from_param(const struct game_s *g, const struct input_token_s *param) { char *shortcuts[PLAYER_NUM * 2]; player_id_t player = PLAYER_NONE; for (int i = 0; i < g->players; ++i) { const char *s; char *p; char c; s = game_str_tbl_race[g->eto[i].race]; p = shortcuts[i * 2 + 0] = lib_stralloc(s); while ((c = *p) != '\0') { *p++ = tolower(c); } s = g->emperor_names[i]; p = shortcuts[i * 2 + 1] = lib_stralloc(s); while ((c = *p) != '\0') { *p++ = tolower(c); } } for (int i = 0; i < (g->players * 2); ++i) { int len; bool is_unique; is_unique = false; len = 0; while (!is_unique && shortcuts[i][++len]) { is_unique = true; for (int j = 0; j < (g->players * 2); ++j) { if ((i != j) && (strncmp(shortcuts[i], shortcuts[j], len) == 0)) { is_unique = false; break; } } } shortcuts[i][len] = '\0'; } /* TODO check if over 1 len shortcuts point to same player, for example Klackon Klaquan */ for (int i = 0; i < (g->players * 2); ++i) { if (ui_input_match_input(param->str, NULL, shortcuts[i])) { player = i / 2; break; } } for (int i = 0; i < (g->players * 2); ++i) { lib_free(shortcuts[i]); } return player; } int ui_cmd_audience(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct input_list_s rl_in[] = { { -1, "1", NULL, NULL }, { -1, "2", NULL, NULL }, { -1, "3", NULL, NULL }, { -1, "4", NULL, NULL }, { -1, "5", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; const empiretechorbit_t *e = &(g->eto[api]); int num = 0; if (g->end != GAME_END_NONE) { return 0; } for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != api) && BOOLVEC_IS1(e->contact, pi) && IS_ALIVE(g, pi)) { if (!game_diplo_is_gone(g, api, pi)) { rl_in[num].value = pi; rl_in[num].display = game_str_tbl_race[g->eto[pi].race]; ++num; } } } if (num > 0) { int v; rl_in[num].value = -1; rl_in[num].key = "Q"; rl_in[num].str = "q"; rl_in[num].display = "(quit)"; ++num; rl_in[num].value = 0; rl_in[num].key = NULL; rl_in[num].str = NULL; rl_in[num].display = NULL; v = ui_input_list("Choose race to have an audience with", "> ", rl_in); if (v >= 0) { game_audience(g, api, v); } } else { printf("No one to have an audience with\n"); } return 0; } int ui_cmd_races(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const empiretechorbit_t *e = &(g->eto[api]); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if ((pi != api) && BOOLVEC_IS1(e->contact, pi) && IS_ALIVE(g, pi)) { const empiretechorbit_t *eo = &(g->eto[pi]); printf("- %s, %s", game_str_tbl_race[eo->race], g->emperor_names[pi]); { int rel, reltxti; rel = e->relation1[pi]; reltxti = rel / 12 + 8; SETRANGE(reltxti, 0, 16); SETRANGE(rel, -100, 100); printf(", %+3i %s, %s, ", rel, game_str_tbl_ra_relat[reltxti], game_str_tbl_ra_treaty[e->treaty[pi]]); } if (e->trade_bc[pi] != 0) { printf("%s: %i %s/%s", game_str_ra_trade, e->trade_bc[pi], game_str_bc, game_str_year); } else { fputs(game_str_ra_notrade, stdout); } if (game_diplo_is_gone(g, api, pi)) { printf(", %s %s", game_str_ra_diplo, game_str_ra_gone); } { int spying, spyprod, spyspend, spies, spycost; spies = e->spies[pi]; if (spies == 0) { printf(", %s", game_str_ra_nospies); } else { printf(", %i %s", spies, (spies == 1) ? game_str_ra_spy : game_str_ra_spies); } spying = e->spying[pi]; printf(", %i.%i%%, ", spying / 10, spying % 10); spyprod = (e->total_production_bc * spying) / 1000; spyspend = spyprod + e->spyfund[pi]; spycost = e->tech.percent[TECH_FIELD_COMPUTER] * 2 + 25; if (e->race == RACE_DARLOK) { spycost /= 2; } if (spycost <= spyspend) { spies = 0; while (spycost <= spyspend) { ++spies; spyspend -= spycost; spycost *= 2; } printf("%i%c%s", spies, (spies == 1) ? ' ' : '/', game_str_y); } else { if (spyprod == 0) { fputs(game_str_st_none, stdout); } else { int left, years; left = spycost - spyspend; years = left / spyprod; if (left % spyprod) { ++years; } printf("%i %s", years, game_str_y); } } } switch (e->spymode[pi]) { case SPYMODE_HIDE: puts(", hide."); break; case SPYMODE_ESPIONAGE: puts(", espionage."); break; case SPYMODE_SABOTAGE: puts(", sabotage."); break; } } } return 0; } int ui_cmd_spy(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { empiretechorbit_t *e = &(g->eto[api]); player_id_t pi = ui_player_from_param(g, param); if (pi == PLAYER_NONE) { printf("Unknown player\n"); return -1; } if (pi == api) { printf("Will not spy self\n"); return -1; } if (param[1].type == INPUT_TOKEN_NUMBER) { int v = param[1].data.num; SETRANGE(v, 0, 100); e->spying[pi] = v; } else if (param[1].type == INPUT_TOKEN_RELNUMBER) { int v = param[1].data.num; v += e->spying[pi]; SETRANGE(v, 0, 100); e->spying[pi] = v; } else { char c; c = tolower(param[1].str[0]); if (c == 'h') { e->spymode[pi] = SPYMODE_HIDE; } else if (c == 'e') { e->spymode[pi] = SPYMODE_ESPIONAGE; } else if (c == 's') { e->spymode[pi] = SPYMODE_SABOTAGE; } else { printf("Invalid spy mode\n"); return -1; } } return 0; } 1oom-1.11.2/src/ui/cmdline/uiraces.h000066400000000000000000000010701476061725400171040ustar00rootroot00000000000000#ifndef INC_1OOM_UIRACES_H #define INC_1OOM_UIRACES_H #include "game_types.h" #include "types.h" struct game_s; struct input_token_s; extern player_id_t ui_player_from_param(const struct game_s *g, const struct input_token_s *param); extern int ui_cmd_audience(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_races(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_spy(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uisave.c000066400000000000000000000043431476061725400167460ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game_save.h" #include "types.h" #include "uidefs.h" #include "uiinput.h" #include "util.h" /* -------------------------------------------------------------------------- */ static int ui_save_game(const struct game_s *g) { struct input_list_s lg_in[] = { { 0, "1", NULL, NULL }, { 1, "2", NULL, NULL }, { 2, "3", NULL, NULL }, { 3, "4", NULL, NULL }, { 4, "5", NULL, NULL }, { 5, "6", NULL, NULL }, { 7, "7", NULL, NULL }, { 8, "8", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; int v, num = 0; for (int i = 0; i < NUM_ALL_SAVES; ++i) { if (game_save_tbl_have_save[i]) { lg_in[num].value = i; lg_in[num].display = game_save_tbl_name[i]; ++num; } } if (num == 0) { return -1; } lg_in[num].value = -1; lg_in[num].key = "Q"; lg_in[num].str = "q"; lg_in[num].display = "(quit)"; ++num; lg_in[num].value = -1; lg_in[num].key = NULL; lg_in[num].str = NULL; lg_in[num].display = NULL; v = ui_input_list("Save game", "> ", lg_in); if ((v >= 0) && (v < NUM_ALL_SAVES)) { const char *savename; savename = ui_input_line("Save name > "); if ((!savename) || (savename[0] == '\0')) { savename = game_save_tbl_have_save[v] ? game_save_tbl_name[v] : "(unnamed)"; } return game_save_do_save_i(v, savename, g); } return 0; } /* -------------------------------------------------------------------------- */ int ui_cmd_save(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { if (num_param == 0) { return ui_save_game(g); } else { int v; if (util_parse_signed_number(param->str, &v) && (v >= 1) && (v <= NUM_ALL_SAVES)) { const char *savename; --v; if (num_param == 2) { savename = param[1].str; } else { savename = game_save_tbl_have_save[v] ? game_save_tbl_name[v] : "(unnamed)"; } return game_save_do_save_i(v, savename, g); } } return -1; } 1oom-1.11.2/src/ui/cmdline/uisave.h000066400000000000000000000002761476061725400167540ustar00rootroot00000000000000#ifndef INC_1OOM_UISAVE_H #define INC_1OOM_UISAVE_H struct input_token_s; extern int ui_cmd_save(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uispecs.c000066400000000000000000000040701476061725400171220ustar00rootroot00000000000000#include "config.h" #include #include #include "uifleet.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_parsed.h" #include "game_shiptech.h" #include "game_str.h" #include "uidefs.h" #include "util.h" /* -------------------------------------------------------------------------- */ static void ui_specs_print(const shipparsed_t *sp, uint32_t shipcount, int cost) { printf("- %s, %i, %s", sp->name, shipcount, game_str_tbl_st_hull[sp->hull]); if (cost >= 0) { printf(", %s %i %s", game_str_sp_cost, cost, game_str_bc); } putchar('\n'); printf(" bdef %i, mdef %i, att %i, hits %i, shield %i, warp %i, speed %i\n", sp->defense, sp->misdefense, sp->complevel, sp->hp, sp->absorb, sp->engine + 1, sp->man); for (int wi = 0; wi < WEAPON_SLOT_NUM; ++wi) { int wn; wn = sp->wpnn[wi]; if (wn != 0) { weapon_t wt; int ns; wt = sp->wpnt[wi]; printf(" %2i %s", wn, *tbl_shiptech_weap[wt].nameptr); /* FIXME make plural form somehow modifiable */ if ((wn != 1) && (wt != WEAPON_DEATH_SPORES)) { putchar('S'); } ns = tbl_shiptech_weap[wt].numshots; if (ns > 0) { printf(" x%i", ns); } putchar('\n'); } } for (int i = 0; i < SPECIAL_SLOT_NUM; ++i) { if (sp->special[i] != 0) { printf(" %s\n", game_str_tbl_st_specsh[sp->special[i]]); } } } /* -------------------------------------------------------------------------- */ int ui_cmd_fleet_specs(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { const empiretechorbit_t *e = &(g->eto[api]); const shipresearch_t *srd = &(g->srd[api]); for (int si = 0; si < e->shipdesigns_num; ++si) { shipparsed_t sp; const shipdesign_t *sd; sd = &(srd->design[si]); game_parsed_from_design(&sp, sd, 1); ui_specs_print(&sp, srd->shipcount[si], sd->cost); } return 0; } 1oom-1.11.2/src/ui/cmdline/uispecs.h000066400000000000000000000003521476061725400171260ustar00rootroot00000000000000#ifndef INC_1OOM_UISPECS_H #define INC_1OOM_UISPECS_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_fleet_specs(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uispy_esp.c000066400000000000000000000044521476061725400174730ustar00rootroot00000000000000#include "config.h" #include #include #include "ui.h" #include "game.h" #include "game_str.h" #include "game_tech.h" #include "lib.h" #include "uiinput.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ int ui_spy_steal(struct game_s *g, int spy, int target, uint8_t flags_field) { struct input_list_s rl_in[] = { { -1, "1", NULL, NULL }, { -1, "2", NULL, NULL }, { -1, "3", NULL, NULL }, { -1, "4", NULL, NULL }, { -1, "5", NULL, NULL }, { -1, "6", NULL, NULL }, { 0, NULL, NULL, NULL }, { 0, NULL, NULL, NULL } }; int num = 0, v = -1; ui_switch_1(g, spy); { char rbuf[0x20], *p, c; const empiretechorbit_t *e = &(g->eto[target]); bool usean = false; lib_strcpy(rbuf, game_str_tbl_race[e->race], sizeof(rbuf)); p = rbuf; while ((c = *p) != 0) { if (islower(c)) { c = toupper(c); *p = c; } if ((c == 'A') || (c == 'E') || (c == 'I') || (c == 'O') || (c == 'U')) { usean = true; } ++p; } printf("%s%s %s %s. ", game_str_es_youresp1, usean ? "N" : "", rbuf, game_str_es_youresp2); } for (int i = 0; i < TECH_FIELD_NUM; ++i) { if (flags_field & (1 << i)) { rl_in[num].value = i; rl_in[num].display = game_str_tbl_te_field[i]; ++num; } } if (num > 0) { rl_in[num].value = -1; rl_in[num].key = "Q"; rl_in[num].str = "q"; rl_in[num].display = "(quit)"; ++num; rl_in[num].value = 0; rl_in[num].key = NULL; rl_in[num].str = NULL; rl_in[num].display = NULL; v = ui_input_list(game_str_es_youresp3, "> ", rl_in); } return v; } void ui_spy_stolen(struct game_s *g, int pi, int spy, int field, uint8_t tech) { const char *s; char buf[0x80]; if (spy != PLAYER_NONE) { s = game_str_tbl_race[g->eto[spy].race]; } else { s = game_str_es_unkn; } ui_switch_1(g, pi); printf("%s %s | %s %s %s\n", s, game_str_es_thesp1, s, game_str_es_thesp2, game_tech_get_name(g->gaux, field, tech, buf, sizeof(buf))); ui_switch_wait(g); } 1oom-1.11.2/src/ui/cmdline/uispy_sab.c000066400000000000000000000142061476061725400174470ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "game.h" #include "game_str.h" #include "uidefs.h" #include "uihelp.h" #include "uiinput.h" #include "uiplanet.h" #include "uiswitch.h" /* -------------------------------------------------------------------------- */ struct ui_sab_data_s { player_id_t target; ui_sabotage_t act; }; #define UI_SPY_SAB_MAKE(_act_, _planet_) (((_act_) << 8) | (_planet_)) #define UI_SPY_SAB_ACT(_v_) ((((uint32_t)(_v_)) >> 8) & 0xf) #define UI_SPY_SAB_PLANET(_v_) ((_v_) & 0xff) static int cmd_look_sab(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct ui_sab_data_s *sabdata = var; for (uint8_t i = 0; i < g->galaxy_stars; ++i) { const planet_t *p = &(g->planet[i]); if (p->owner == sabdata->target) { ui_planet_look(g, api, i, true); } } return 0; } static int cmd_sab(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { struct ui_sab_data_s *sabdata = var; uint8_t planet = 0; ui_sabotage_t act = sabdata->act; player_id_t target = sabdata->target; if (act != UI_SABOTAGE_NONE) { const planet_t *p; planet = ui_planet_from_param(g, api, param); if (planet == PLANET_NONE) { return -1; } p = &(g->planet[planet]); if (p->owner != target) { printf("The planet does not belong to the %s\n", game_str_tbl_race[g->eto[target].race]); return -1; } } return UI_SPY_SAB_MAKE(act, planet); } static const struct input_cmd_s * const cmdsptr_sab[2]; static const struct input_cmd_s cmds_sab[] = { { "?", NULL, "Help", 0, 0, 0, ui_cmd_help, (void *)cmdsptr_sab }, { "l", NULL, "List target planets", 0, 0, 0, cmd_look_sab, 0 }, { "b", "PLANET", "Sabotage missile bases", 1, 1, 0, cmd_sab, (void *)UI_SABOTAGE_BASES }, { "f", "PLANET", "Sabotage factories", 1, 1, 0, cmd_sab, (void *)UI_SABOTAGE_FACT }, { "r", "PLANET", "Incite revolt", 1, 1, 0, cmd_sab, (void *)UI_SABOTAGE_REVOLT }, { "n", NULL, "Do nothing", 0, 0, 0, cmd_sab, (void *)UI_SABOTAGE_NONE }, { NULL, NULL, NULL, 0, 0, 0, NULL, 0 } }; static const struct input_cmd_s * const cmdsptr_sab[2] = { cmds_sab, 0 }; /* -------------------------------------------------------------------------- */ ui_sabotage_t ui_spy_sabotage_ask(struct game_s *g, int spy, int target, uint8_t *planetptr) { struct ui_sab_data_s sabdata; sabdata.target = target; ui_switch_1(g, spy); printf("Sabotage | %s | %s\n", game_str_tbl_race[g->eto[target].race], game_str_sb_choose); while (1) { char *input; input = ui_input_line("> "); if ((ui_input_tokenize(input, cmdsptr_sab) == 0) && (ui_data.input.num > 0)) { if (ui_data.input.tok[0].type == INPUT_TOKEN_COMMAND) { const struct input_cmd_s *cmd; void *var; int v; cmd = ui_data.input.tok[0].data.cmd; if (cmd->handle == ui_cmd_help) { var = cmd->var; } else { sabdata.act = (ui_sabotage_t)cmd->var; var = &sabdata; } v = cmd->handle(g, spy, &ui_data.input.tok[1], ui_data.input.num - 1, var); if ((v >= 0) && (cmd->handle == cmd_sab)) { uint8_t planet = UI_SPY_SAB_PLANET(v); ui_sabotage_t act = UI_SPY_SAB_ACT(v); *planetptr = planet; return act; } } } } return UI_SABOTAGE_NONE; } int ui_spy_sabotage_done(struct game_s *g, int pi, int spy, int target, ui_sabotage_t act, int other1, int other2, uint8_t planet, int snum) { const planet_t *p = &(g->planet[planet]); ui_switch_1(g, pi); printf("Sabotage | %s | ", p->name); if (spy == PLAYER_NONE) { printf("%s ", game_str_sb_unkn); } else { printf("%s %s ", (spy == pi) ? game_str_sb_your : game_str_tbl_race[g->eto[spy].race], game_str_sb_spies); } if (snum > 0) { switch (act) { default: case UI_SABOTAGE_FACT: /*0*/ printf("%s %i %s", game_str_sb_destr, snum, (snum == 1) ? game_str_sb_fact2 : game_str_sb_facts); break; case UI_SABOTAGE_BASES: /*1*/ printf("%s %i %s", game_str_sb_destr, snum, (snum == 1) ? game_str_sb_mbase : game_str_sb_mbases); break; case UI_SABOTAGE_REVOLT: /*2*/ if (p->unrest == PLANET_UNREST_REBELLION) { printf("%s", game_str_sb_increv); } else { int v = (p->pop == 0) ? 0 : ((p->rebels * 100) / p->pop); printf("%s %i %s %i%%.", game_str_sb_inc1, snum, game_str_sb_inc2, v); } break; } } else { printf("%s ", game_str_sb_failed); switch (act) { default: case UI_SABOTAGE_FACT: /*0*/ if (p->factories == 0) { fputs(game_str_sb_nofact, stdout); } break; case UI_SABOTAGE_BASES: /*1*/ if (p->missile_bases == 0) { fputs(game_str_sb_nobases, stdout); } break; case UI_SABOTAGE_REVOLT: /*2*/ fputs(game_str_sb_noinc, stdout); /* FIXME never happens? */ break; } } putchar('\n'); if (other2 == PLAYER_NONE) { ui_switch_wait(g); return PLAYER_NONE; } else { struct input_list_s rl_in[] = { { 0, "1", NULL, 0 }, { 1, "2", NULL, 0 }, { PLAYER_NONE, "Q", NULL, game_str_mm_quit }, { 0, NULL, NULL, NULL }, }; rl_in[0].value = other1; rl_in[0].display = game_str_tbl_races[g->eto[other1].race]; rl_in[0].value = other2; rl_in[0].display = game_str_tbl_races[g->eto[other2].race]; printf("Sabotage | %s | %s\n", p->name, game_str_sb_frame); return ui_input_list(game_str_nt_victim, "> ", rl_in); } } 1oom-1.11.2/src/ui/cmdline/uiswitch.c000066400000000000000000000065051476061725400173130ustar00rootroot00000000000000#include "config.h" #include #include "uiswitch.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_str.h" #include "uicmds.h" #include "uidefs.h" #include "uiinput.h" /* -------------------------------------------------------------------------- */ #define UI_SWITCH_BLANK_LINES 80 /* -------------------------------------------------------------------------- */ static bool ui_switch(const struct game_s *g, player_id_t *tbl_pi, int num_pi, bool allow_opts) { for (int i = 0; i < UI_SWITCH_BLANK_LINES; ++i) { putchar('\n'); } printf("*** %i\n", g->year + YEAR_BASE); for (int i = 0; i < num_pi; ++i) { player_id_t pi; pi = tbl_pi[i]; printf("* %s %i: %s\n", game_str_player, pi + 1, g->emperor_names[pi]); } /* TODO if (allow_opts) { save, load, quit ... } */ ui_input_wait_enter(); return false; } /* -------------------------------------------------------------------------- */ bool ui_switch_1_opts(const struct game_s *g, player_id_t pi) { BOOLVEC_DECLARE(viewing, PLAYER_NUM); if ((g->gaux->local_players <= 1) || IS_AI(g, pi)) { return false; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); BOOLVEC_SET1(viewing, pi); if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); return ui_switch(g, &pi, 1, true); } return false; } void ui_switch_1(const struct game_s *g, player_id_t pi) { BOOLVEC_DECLARE(viewing, PLAYER_NUM); if ((g->gaux->local_players <= 1) || IS_AI(g, pi)) { return; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); BOOLVEC_SET1(viewing, pi); if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, &pi, 1, false); } } bool ui_switch_2(const struct game_s *g, player_id_t pi1, player_id_t pi2) { player_id_t tbl[2]; int n = 0; BOOLVEC_DECLARE(viewing, PLAYER_NUM); if (g->gaux->local_players <= 1) { return false; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); if (IS_HUMAN(g, pi1) && IS_ALIVE(g, pi1)) { BOOLVEC_SET1(viewing, pi1); tbl[n++] = pi1; } if (IS_HUMAN(g, pi2) && IS_ALIVE(g, pi2)) { BOOLVEC_SET1(viewing, pi2); tbl[n++] = pi2; } if ((n == 2) && (pi1 > pi2)) { tbl[0] = pi2; tbl[1] = pi1; } if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, tbl, n, false); return true; } return false; } void ui_switch_all(const struct game_s *g) { player_id_t tbl[PLAYER_NUM]; int n = 0; BOOLVEC_DECLARE(viewing, PLAYER_NUM); if (g->gaux->local_players <= 1) { return; } BOOLVEC_CLEAR(viewing, PLAYER_NUM); for (player_id_t pi = PLAYER_0; pi < g->players; ++pi) { if (IS_HUMAN(g, pi) && IS_ALIVE(g, pi)) { tbl[n++] = pi; } } if (!BOOLVEC_COMP(ui_data.players_viewing, viewing, PLAYER_NUM)) { BOOLVEC_COPY(ui_data.players_viewing, viewing, PLAYER_NUM); ui_switch(g, tbl, n, false); } } void ui_switch_wait(const struct game_s *g) { if (g->gaux->local_players > 1) { ui_input_wait_enter(); } } 1oom-1.11.2/src/ui/cmdline/uiswitch.h000066400000000000000000000006761476061725400173230ustar00rootroot00000000000000#ifndef INC_1OOM_UISWITCH_H #define INC_1OOM_UISWITCH_H #include "game_types.h" #include "types.h" struct game_s; extern bool ui_switch_1_opts(const struct game_s *g, player_id_t pi); extern void ui_switch_1(const struct game_s *g, player_id_t pi); extern bool ui_switch_2(const struct game_s *g, player_id_t pi1, player_id_t pi2); extern void ui_switch_all(const struct game_s *g); extern void ui_switch_wait(const struct game_s *g); #endif 1oom-1.11.2/src/ui/cmdline/uitech.c000066400000000000000000000112151476061725400167270ustar00rootroot00000000000000#include "config.h" #include #include #include "uitech.h" #include "comp.h" #include "game.h" #include "game_misc.h" #include "game_str.h" #include "game_tech.h" #include "uidefs.h" /* -------------------------------------------------------------------------- */ static const char slchars[] = "cofprw"; static tech_field_t ui_tech_slider_from_param(struct input_token_s *param) { char c = param->str[0]; char *p = strchr(slchars, c); if (p) { return (p - slchars); } else { return TECH_FIELD_NUM; } } static void ui_tech_look_sliders(const struct game_s *g, int api) { const empiretechorbit_t *e = &(g->eto[api]); const techdata_t *t = &(e->tech); for (tech_field_t f = 0; f < TECH_FIELD_NUM; ++f) { printf("%c%c %12s: %3i ", t->slider_lock[f] ? '*' : ' ', slchars[f], game_str_tbl_te_field[f], t->slider[f]); if ((t->percent[f] < 99) || (t->project[f] != 0)) { int complpercent; complpercent = game_tech_current_research_percent2(g, api, f); if (complpercent > 0) { if (complpercent < 10) { putchar(' '); } printf("%i%%", complpercent); } else { #define LIGHTBULB_CHARS 8 const char lightbulb[LIGHTBULB_CHARS] = { ' ', '.', ',', '_', 'o', 'O', '?', '!' }; int pos; complpercent = game_tech_current_research_percent1(g, api, f); pos = (complpercent * LIGHTBULB_CHARS) / 100; putchar(' '); putchar(lightbulb[pos]); putchar(' '); } putchar(' '); putchar(game_tech_current_research_has_max_bonus(g, api, f) ? 'X' : ' '); } else { fputs(game_str_te_max, stdout); } if (t->project[f]) { putchar(' '); putchar(' '); game_tech_get_name(g->gaux, f, t->project[f], ui_data.strbuf, UI_STRBUF_SIZE); fputs(ui_data.strbuf, stdout); } putchar('\n'); } } static void ui_tech_look_field(const struct game_s *g, int api, tech_field_t f) { const techdata_t *t = &(g->eto[api].tech); const uint8_t *q = g->srd[api].researchcompleted[f]; int8_t completed[TECH_PER_FIELD + 3]; int num = t->completed[f]; int8_t *p = completed; if (f == TECH_FIELD_WEAPON) { *p++ = -2; *p++ = -1; } for (int i = 0; i < num; ++i) { *p++ = *q++; } if (f == TECH_FIELD_WEAPON) { num += 2; } if (t->project[f]) { *p++ = t->project[f]; ++num; } puts(game_str_tbl_te_field[f]); for (int i = 0; i < num; ++i) { game_tech_get_name(g->gaux, f, completed[i], ui_data.strbuf, UI_STRBUF_SIZE); printf("- "); fputs(ui_data.strbuf, stdout); printf(": "); game_tech_get_descr(g->gaux, f, completed[i], ui_data.strbuf, UI_STRBUF_SIZE); puts(ui_data.strbuf); } } /* -------------------------------------------------------------------------- */ int ui_cmd_tech_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { if (num_param == 0) { ui_tech_look_sliders(g, api); } else { tech_field_t f = ui_tech_slider_from_param(param); if (f == TECH_FIELD_NUM) { return -1; } ui_tech_look_field(g, api, f); } return 0; } int ui_cmd_tech_slider(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { techdata_t *t = &(g->eto[api].tech); tech_field_t f = ui_tech_slider_from_param(param); int v; if (f == TECH_FIELD_NUM) { return -1; } if (param[1].type == INPUT_TOKEN_NUMBER) { v = param[1].data.num; } else if (param[1].type == INPUT_TOKEN_RELNUMBER) { v = t->slider[f] + param[1].data.num; } else { return -1; } SETRANGE(v, 0, 100); if (!t->slider_lock[f]) { t->slider[f] = v; game_adjust_slider_group(t->slider, f, t->slider[f], TECH_FIELD_NUM, t->slider_lock); } return 0; } int ui_cmd_tech_slider_lock(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { techdata_t *t = &(g->eto[api].tech); tech_field_t f = ui_tech_slider_from_param(param); if (f == TECH_FIELD_NUM) { return -1; } t->slider_lock[f] = !t->slider_lock[f]; return 0; } int ui_cmd_tech_equals(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { techdata_t *t = &(g->eto[api].tech); game_equalize_slider_group(t->slider, TECH_FIELD_NUM, t->slider_lock); return 0; } 1oom-1.11.2/src/ui/cmdline/uitech.h000066400000000000000000000010761476061725400167400ustar00rootroot00000000000000#ifndef INC_1OOM_UITECH_H #define INC_1OOM_UITECH_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_tech_look(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_tech_slider(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_tech_slider_lock(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); extern int ui_cmd_tech_equals(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/cmdline/uiview.c000066400000000000000000000232241476061725400167610ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include "uiview.h" #include "boolvec.h" #include "comp.h" #include "game.h" #include "game_aux.h" #include "game_misc.h" #include "game_str.h" #include "uidefs.h" #include "uifleet.h" #include "uiplanet.h" #include "util.h" #include "util_math.h" /* -------------------------------------------------------------------------- */ #define UI_VIEW_FILTER_PLANET (1 << 0) #define UI_VIEW_FILTER_FLEET (1 << 1) #define UI_VIEW_FILTER_TRANS (1 << 2) #define UI_VIEW_FILTER_MY (1 << 3) #define UI_VIEW_FILTER_OPP (1 << 4) #define UI_VIEW_FILTER_UNEX (1 << 5) #define UI_VIEW_FILTER_EX (1 << 6) #define UI_VIEW_FILTER_UNCOLON (1 << 7) #define UI_VIEW_FILTER_COLON (1 << 8) #define UI_VIEW_FILTER_ALL ((1 << 9) - 1) static struct ui_filter_s { char c; uint32_t m1; uint32_t m0; } ui_view_filter[] = { { 'p', UI_VIEW_FILTER_PLANET, 0 }, { 'f', UI_VIEW_FILTER_FLEET, 0 }, { 't', UI_VIEW_FILTER_TRANS, 0 }, { 'y', UI_VIEW_FILTER_MY | UI_VIEW_FILTER_COLON | UI_VIEW_FILTER_EX, UI_VIEW_FILTER_OPP | UI_VIEW_FILTER_UNCOLON | UI_VIEW_FILTER_UNEX }, { 'o', UI_VIEW_FILTER_OPP | UI_VIEW_FILTER_COLON | UI_VIEW_FILTER_EX, UI_VIEW_FILTER_MY | UI_VIEW_FILTER_UNCOLON | UI_VIEW_FILTER_UNEX }, { 'u', UI_VIEW_FILTER_UNEX | UI_VIEW_FILTER_PLANET, UI_VIEW_FILTER_EX }, { 'x', UI_VIEW_FILTER_EX | UI_VIEW_FILTER_PLANET, UI_VIEW_FILTER_UNEX }, { 'n', UI_VIEW_FILTER_UNCOLON | UI_VIEW_FILTER_PLANET, UI_VIEW_FILTER_COLON }, { 'c', UI_VIEW_FILTER_COLON | UI_VIEW_FILTER_PLANET, UI_VIEW_FILTER_UNCOLON }, { 0, 0, 0 } }; /* -------------------------------------------------------------------------- */ static int ui_cmd_view_add(int range, int dist, int i, int type, int num) { uint32_t v; v = (dist << 24) | (type << 22) | i; ui_data.view.item[num] = v; return ++num; } static int ui_cmd_view_item_compare(const void *p0, const void *p1) { uint32_t v0 = *((uint32_t const *)p0); uint32_t v1 = *((uint32_t const *)p1); return v0 < v1; } static void ui_cmd_view_display(const struct game_s *g, player_id_t api, uint32_t item, uint32_t filter) { int dist = item >> 24; int type = (item >> 22) & 3; int i = item & 0xfff; printf("Dist %2i: ", dist); switch (type) { case 0/*transport*/: ui_fleet_print_transport_enroute(g, api, &g->transport[i]); break; case 1/*fleet*/: ui_fleet_print_fleet_enroute(g, api, &g->enroute[i], PLANET_NONE); break; case 2/*planet*/: ui_planet_look(g, api, i, false); break; case 3/*orbit*/: ui_fleet_print_fleets_orbit(g, api, i, (filter & UI_VIEW_FILTER_MY) != 0, (filter & UI_VIEW_FILTER_OPP) != 0); break; default: break; } } static void ui_cmd_view_do(const struct game_s *g, player_id_t api, uint32_t filter, int rangemax, int distmax) { uint8_t planet_i = g->planet_focus_i[api]; const planet_t *p = &(g->planet[planet_i]); int num = 0, cx = p->x, cy = p->y; if (filter & UI_VIEW_FILTER_PLANET) { for (int i = 0; i < g->galaxy_stars; ++i) { int dist, range; p = &(g->planet[i]); if (BOOLVEC_IS0(p->explored, api)) { if (!(filter & UI_VIEW_FILTER_UNEX)) { continue; } } else { if (!(filter & UI_VIEW_FILTER_EX)) { continue; } } { player_id_t owner; owner = p->owner; if (BOOLVEC_IS0(p->within_srange, api) && ((owner == PLAYER_NONE) || BOOLVEC_IS0(g->eto[api].contact, owner))) { owner = g->seen[api][i].owner; } if (owner == PLAYER_NONE) { if (!(filter & UI_VIEW_FILTER_UNCOLON)) { continue; } } else { if (!(filter & UI_VIEW_FILTER_COLON)) { continue; } if (p->owner == api) { if (!(filter & UI_VIEW_FILTER_MY)) { continue; } } else { if (!(filter & UI_VIEW_FILTER_OPP)) { continue; } } } } dist = g->gaux->star_dist[planet_i][i]; if ((distmax >= 0) && (dist > distmax)) { continue; } range = game_get_min_dist(g, api, i); if ((rangemax >= 0) && (range > rangemax)) { continue; } num = ui_cmd_view_add(range, dist, i, 2/*planet*/, num); } } if (filter & UI_VIEW_FILTER_FLEET) { for (int i = 0; i < g->enroute_num; ++i) { const fleet_enroute_t *r = &(g->enroute[i]); int dist; if (BOOLVEC_IS0(r->visible, api)) { continue; } if (r->owner == api) { if (!(filter & UI_VIEW_FILTER_MY)) { continue; } } else { if (!(filter & UI_VIEW_FILTER_OPP)) { continue; } } dist = util_math_dist_steps(cx, cy, r->x, r->y); if ((distmax >= 0) && (dist > distmax)) { continue; } num = ui_cmd_view_add(0, dist, i, 1/*fleet*/, num); } } if ((filter & (UI_VIEW_FILTER_FLEET | UI_VIEW_FILTER_PLANET)) == UI_VIEW_FILTER_FLEET) { for (int i = 0; i < g->galaxy_stars; ++i) { bool got_fleet; int dist, range; dist = g->gaux->star_dist[planet_i][i]; if ((distmax >= 0) && (dist > distmax)) { continue; } got_fleet = false; for (int j = 0; j < g->players; ++j) { const fleet_orbit_t *r = &(g->eto[j].orbit[i]); if (BOOLVEC_IS0(r->visible, api)) { continue; } if (j == api) { if (filter & UI_VIEW_FILTER_MY) { got_fleet = true; break; } } else { if (filter & UI_VIEW_FILTER_OPP) { got_fleet = true; break; } } } if (!got_fleet) { continue; } range = game_get_min_dist(g, api, planet_i); if ((rangemax >= 0) && (range > rangemax)) { continue; } num = ui_cmd_view_add(range, dist, i, 3/*orbit*/, num); } } if (filter & UI_VIEW_FILTER_TRANS) { for (int i = 0; i < g->transport_num; ++i) { const transport_t *r = &(g->transport[i]); int dist; if (BOOLVEC_IS0(r->visible, api)) { continue; } if (r->owner == api) { if (!(filter & UI_VIEW_FILTER_MY)) { continue; } } else { if (!(filter & UI_VIEW_FILTER_OPP)) { continue; } } dist = util_math_dist_steps(cx, cy, r->x, r->y); if ((distmax >= 0) && (dist > distmax)) { continue; } num = ui_cmd_view_add(0, dist, i, 0/*transport*/, num); } } qsort(ui_data.view.item, num, sizeof(ui_data.view.item[0]), ui_cmd_view_item_compare); for (int i = 0; i < num; ++i) { ui_cmd_view_display(g, api, ui_data.view.item[i], filter); } } /* -------------------------------------------------------------------------- */ int ui_cmd_view(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var) { uint32_t filter = UI_VIEW_FILTER_ALL; int range = -1; int dist = -1; for (int i = 0; i < num_param; ++i) { if (param[i].type == INPUT_TOKEN_NUMBER) { range = param[i].data.num; } else if (param[i].type == INPUT_TOKEN_RELNUMBER) { dist = param[i].data.num; } else { const char *str; char c; filter = 0; str = param[i].str; while ((c = *str++) != '\0') { struct ui_filter_s *f; f = &ui_view_filter[0]; c = tolower(c); while (f->c && (f->c != c)) { ++f; } if (!f->c) { printf("Invalid filter '%c'\n", c); return -1; } filter |= f->m1; if (f->m0) { filter &= ~(f->m0); } } if ((filter & (UI_VIEW_FILTER_PLANET | UI_VIEW_FILTER_FLEET | UI_VIEW_FILTER_TRANS)) == 0) { filter |= UI_VIEW_FILTER_PLANET | UI_VIEW_FILTER_FLEET | UI_VIEW_FILTER_TRANS; } if ((filter & (UI_VIEW_FILTER_MY | UI_VIEW_FILTER_OPP)) == 0) { filter |= UI_VIEW_FILTER_MY | UI_VIEW_FILTER_OPP; } if ((filter & (UI_VIEW_FILTER_EX | UI_VIEW_FILTER_UNEX)) == 0) { filter |= UI_VIEW_FILTER_EX | UI_VIEW_FILTER_UNEX; } if ((filter & (UI_VIEW_FILTER_COLON | UI_VIEW_FILTER_UNCOLON)) == 0) { filter |= UI_VIEW_FILTER_COLON | UI_VIEW_FILTER_UNCOLON; } } } ui_cmd_view_do(g, api, filter, range, dist); return 0; } 1oom-1.11.2/src/ui/cmdline/uiview.h000066400000000000000000000003411476061725400167610ustar00rootroot00000000000000#ifndef INC_1OOM_UIVIEW_H #define INC_1OOM_UIVIEW_H #include "types.h" struct game_s; struct input_token_s; extern int ui_cmd_view(struct game_s *g, int api, struct input_token_s *param, int num_param, void *var); #endif 1oom-1.11.2/src/ui/nop/000077500000000000000000000000001476061725400144635ustar00rootroot000000000000001oom-1.11.2/src/ui/nop/Makefile.am000066400000000000000000000001451476061725400165170ustar00rootroot00000000000000AM_CPPFLAGS = \ -I$(top_srcdir)/src noinst_LIBRARIES = libuinop.a libuinop_a_SOURCES = uinop.c 1oom-1.11.2/src/ui/nop/uinop.c000066400000000000000000000013171476061725400157630ustar00rootroot00000000000000#include "config.h" #include #include "ui.h" #include "cfg.h" #include "options.h" #include "types.h" /* -------------------------------------------------------------------------- */ const struct cfg_items_s ui_cfg_items[] = { CFG_ITEM_END }; const struct cmdline_options_s ui_cmdline_options[] = { { NULL, 0, NULL, NULL, NULL, NULL } }; /* -------------------------------------------------------------------------- */ const char *idstr_ui = "nop"; /* bool ui_use_audio intentionally left undeclared */ /* -------------------------------------------------------------------------- */ int ui_early_init(void) { return 0; } int ui_init(void) { return 0; } void ui_shutdown(void) { } 1oom-1.11.2/src/util.c000066400000000000000000000210601476061725400143720ustar00rootroot00000000000000#include "config.h" #include #include #include #include #include #include "util.h" #include "lib.h" #include "os.h" #include "types.h" /* -------------------------------------------------------------------------- */ char *util_concat(const char *s, ...) { #define UTIL_CONCAT_MAX_ARGS 128 const char *arg; char *newp, *ptr; int num_args; size_t arg_len[UTIL_CONCAT_MAX_ARGS], tot_len; int i; va_list ap; arg_len[0] = tot_len = strlen(s); va_start(ap, s); for (i = 1; i < UTIL_CONCAT_MAX_ARGS && (arg = va_arg(ap, const char *)) != NULL; ++i) { arg_len[i] = strlen(arg); tot_len += arg_len[i]; } num_args = i; va_end(ap); newp = lib_malloc(tot_len + 1); if (arg_len[0] > 0) { memcpy(newp, s, arg_len[0]); } ptr = newp + arg_len[0]; va_start(ap, s); for (i = 1; i < num_args; ++i) { memcpy(ptr, va_arg(ap, const char *), arg_len[i]); ptr += arg_len[i]; } *ptr = '\0'; va_end(ap); return newp; } int util_concat_buf(char *buf, int buflen, ...) { const char *arg; char *ptr; int num_args; size_t arg_len[UTIL_CONCAT_MAX_ARGS], tot_len = 0, len = 0; int i; va_list ap; va_start(ap, buflen); for (i = 0; i < UTIL_CONCAT_MAX_ARGS && (arg = va_arg(ap, const char *)) != NULL; ++i) { arg_len[i] = strlen(arg); tot_len += arg_len[i]; } num_args = i; va_end(ap); ptr = buf; --buflen; /* reserve space for terminating '\0' */ va_start(ap, buflen); for (i = 0; (i < num_args) && (buflen > 0); ++i) { int l; l = arg_len[i]; if (l > buflen) { l = buflen; } memcpy(ptr, va_arg(ap, const char *), l); ptr += l; len += l; buflen -= l; } va_end(ap); *ptr = '\0'; --buflen; return (len == tot_len) ? len : (len - tot_len); } /* Input one line from the file descriptor `f'. FIXME: we need something better, like GNU `getline()'. */ int util_get_line(char *buf, int bufsize, FILE *f) { char *r; size_t len; r = fgets(buf, bufsize, f); if (r == NULL) { return -1; } len = strlen(buf); if (len > 0) { char *p; /* Remove trailing newline characters. */ /* Remove both 0x0a and 0x0d characters, this solution makes it */ /* work on all target platforms: Unixes, Win32, DOS, and even for MAC */ while ((len > 0) && ((*(buf + len - 1) == 0x0d) || (*(buf + len - 1) == 0x0a))) { len--; } /* Remove useless spaces. */ while ((len > 0) && (*(buf + len - 1) == ' ')) { len--; } for (p = buf; *p == ' '; p++, len--); memmove(buf, p, len + 1); *(buf + len) = '\0'; } return (int)len; } /* Split `path' into a file name and a directory component. Unlike the MS-DOS `fnsplit', the directory does not have a trailing '/'. */ void util_fname_split(const char *path, char **dir_out, char **name_out) { const char *p; if (path == NULL) { *dir_out = *name_out = NULL; return; } p = strrchr(path, FSDEV_DIR_SEP_CHR); #ifdef FSDEV_DIR_SEP_ALT { const char *p1; p1 = strrchr(path, FSDEV_DIR_SEP_ALT); if ((p == NULL) || (p < p1)) { p = p1; } } #endif if (p == NULL) { if (dir_out != NULL) { *dir_out = NULL; } if (name_out != NULL) { *name_out = lib_stralloc(path); } return; } if (dir_out != NULL) { *dir_out = lib_malloc((size_t)(p - path + 1)); memcpy(*dir_out, path, p - path); (*dir_out)[p - path] = '\0'; } if (name_out != NULL) { *name_out = lib_stralloc(p + 1); } } /* Write the first `size' bytes of `src' into a newly created file `name'. If `name' already exists, it is replaced by the new one. Returns 0 on success, -1 on failure. */ int util_file_save(const char *name, const uint8_t *src, int size) { FILE *fd; size_t r; fd = fopen(name, "wb"); if (fd == NULL) { return -1; } r = fwrite((char *)src, size, 1, fd); fclose(fd); return (r < 1) ? -1 : 0; } uint8_t *util_file_load(const char *filename, uint32_t *len_out) { FILE *fd = NULL; uint8_t *data = NULL; uint32_t len = 0; if ((fd = fopen(filename, "rb")) == NULL) { perror(filename); goto fail; } if (fseek(fd, 0, SEEK_END) != 0) { perror(filename); goto fail; } len = ftell(fd); rewind(fd); data = lib_malloc(len + 1); if (fread(data, len, 1, fd) < 1) { goto fail; } data[len] = '\0'; *len_out = len; fclose(fd); fd = NULL; return data; fail: *len_out = 0; if (fd) { fclose(fd); fd = NULL; } if (data) { lib_free(data); data = NULL; } return NULL; } void util_trim_whitespace(char *buf, size_t bufsize) { int i; for (i = 0; ((buf[i] == ' ') || (buf[i] == '\t')); ++i); if (i > 0) { lib_strcpy(buf, &buf[i], bufsize); } for (i = 0; i < bufsize && buf[i] != '\0'; ++i); --i; for (; (i >= 0) && (((buf[i] == ' ') || (buf[i] == '\t'))); --i) { buf[i] = '\0'; } } void util_str_tolower(char *buf, size_t bufsize) { char c; char *buf_end = buf + bufsize; while (buf != buf_end && (c = *buf) != '\0') { /* tolower leaves characters that aren't upper-case letters unchanged. */ *buf++ = tolower(c); } } bool util_parse_number(const char *str, uint32_t *val_ptr) { char *strend = NULL; uint32_t v = strtoul(str, &strend, 0); *val_ptr = v; return (*strend == '\0'); } bool util_parse_signed_number(const char *str, int *val_ptr) { char *strend = NULL; int v = strtol(str, &strend, 10); *val_ptr = v; return (*strend == '\0'); } int32_t *util_parse_numbers(const char *str, char sep, int *numptr) { char *strend = NULL; int32_t *nums = NULL; int numnum = 0; char c; do { int32_t v; v = strtol(str, &strend, 0); do { c = *strend++; } while ((c == ' ') || (c == '\t')); if ((c == sep) || (c == '\n') || (c == '\r') || (c == '\0')) { nums = lib_realloc(nums, (numnum + 1) * sizeof(int32_t)); nums[numnum++] = v; if (c == sep) { str = strend; } else { c = '\0'; } } else { lib_free(nums); nums = NULL; numnum = 0; c = '\0'; } } while (c != '\0'); if (numptr) { *numptr = numnum; } return nums; } void util_table_remove_item_keep_order(int itemi, void *tbl, int itemsz, int itemnum) { if ((itemi < 0) || (itemi >= (itemnum - 1))) { return; } memmove(((uint8_t *)tbl) + itemi * itemsz, ((uint8_t *)tbl) + (itemi + 1) * itemsz, (itemnum - 1 - itemi) * itemsz); } void util_table_remove_item_keep_order_zero(int itemi, void *tbl, int itemsz, int itemnum) { if ((itemi < 0) || (itemi >= itemnum)) { return; } if (itemi < (itemnum - 1)) { memmove(((uint8_t *)tbl) + itemi * itemsz, ((uint8_t *)tbl) + (itemi + 1) * itemsz, (itemnum - 1 - itemi) * itemsz); } memset(((uint8_t *)tbl) + (itemnum - 1) * itemsz, 0, itemsz); } void util_table_remove_item_any_order(int itemi, void *tbl, int itemsz, int itemnum) { if ((itemi < 0) || (itemi >= (itemnum - 1))) { return; } memcpy(((uint8_t *)tbl) + itemi * itemsz, ((uint8_t *)tbl) + (itemnum - 1) * itemsz, itemsz); } /* -------------------------------------------------------------------------- */ /* The following `strcasecmp()' implementation is taken from: GLIB - Library of useful routines for C programming Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald. The source is available from http://www.gtk.org/. */ #if !defined HAVE_STRCASECMP int strcasecmp(const char *s1, const char *s2) { int c1, c2; if (s1 == NULL || s2 == NULL) { return 0; } while (*s1 && *s2) { /* According to A. Cox, some platforms have islower's that don't work right on non-uppercase. */ c1 = isupper((unsigned int)*s1) ? tolower((unsigned int)*s1) : *s1; c2 = isupper((unsigned int)*s2) ? tolower((unsigned int)*s2) : *s2; if (c1 != c2) { return (c1 - c2); } s1++; s2++; } return (((int)(unsigned char)*s1) - ((int)(unsigned char)*s2)); } #endif 1oom-1.11.2/src/util.h000066400000000000000000000023331476061725400144010ustar00rootroot00000000000000#ifndef INC_1OOM_UTIL_H #define INC_1OOM_UTIL_H #include "config.h" #include #include #include "types.h" extern char *util_concat(const char *s, ...); extern int util_concat_buf(char *buf, int buflen, ...); extern int util_get_line(char *buf, int bufsize, FILE *f); extern void util_fname_split(const char *path, char **directory_out, char **name_out); extern int util_file_save(const char *name, const uint8_t *src, int size); extern uint8_t *util_file_load(const char *filename, uint32_t *len_out); extern void util_trim_whitespace(char *buf, size_t bufsize); extern void util_str_tolower(char *buf, size_t bufsize); extern bool util_parse_number(const char *str, uint32_t *val_ptr); extern bool util_parse_signed_number(const char *str, int *val_ptr); extern int32_t *util_parse_numbers(const char *str, char sep, int *numptr); extern void util_table_remove_item_keep_order(int itemi, void *tbl, int itemsz, int itemnum); extern void util_table_remove_item_keep_order_zero(int itemi, void *tbl, int itemsz, int itemnum); extern void util_table_remove_item_any_order(int itemi, void *tbl, int itemsz, int itemnum); #if !defined HAVE_STRCASECMP extern int strcasecmp(const char *s1, const char *s2); #endif #endif 1oom-1.11.2/src/util_cstr.c000066400000000000000000000061701476061725400154320ustar00rootroot00000000000000#include "config.h" #include #include #include #include "util_cstr.h" #include "lib.h" #include "log.h" /* -------------------------------------------------------------------------- */ static inline int parse_hex_char(char c) { int val; if ((c >= '0') && (c <= '9')) { val = c - '0'; } else if ((c >= 'A') && (c <= 'F')) { val = c - 'A' + 10; } else if ((c >= 'a') && (c <= 'f')) { val = c - 'a' + 10; } else { val = -1; } return val; } static inline int parse_hex_2char(const char *p) { uint8_t val; int t; t = parse_hex_char(p[0]); if (t < 0) { return t; } val = t << 4; t = parse_hex_char(p[1]); if (t < 0) { return t; } val |= t; return val; } /* -------------------------------------------------------------------------- */ int util_cstr_parse(const char *str, char *dst, uint32_t *len_out) { uint32_t len = 0; const char *p = str; char c; ++p; while ((c = *p++) != '"') { if (c == '\\') { c = *p++; switch (c) { case '"': case '\\': break; case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 'x': { int val; val = parse_hex_2char(p); if (val < 0) { log_error("invalid hex escape\n"); return false; } c = val; p += 2; } break; default: log_error("unhandled escape char 0x%02x\n", c); return -1; } } else if ((c < 0x20) || (c > 0x7e)) { log_error("invalid char 0x%02x\n", c); return -1; } *dst++ = c; ++len; } *dst = '\0'; if (len_out) { *len_out = len; } return p - str; } int util_cstr_out(FILE *fd, const char *str) { char c; while ((c = *str++) != 0) { if ((c == '\\') || (c == '"')) { if (fputc('\\', fd) == EOF) { return -1; } } if (fputc(c, fd) == EOF) { return -1; } } return 0; } int util_cstr_parse_in_place(char *str) { char *p = str; char c; while ((c = *str++) != 0) { if (c == '"') { break; } if (c == '\\') { c = *str++; switch (c) { case '\\': case '"': break; case 'n': c = '\n'; break; case 't': c = '\t'; break; default: log_error("%s: unhandled escape 0x%02x\n", __func__, c); return -1; } } *p++ = c; } *p = 0; return 0; } 1oom-1.11.2/src/util_cstr.h000066400000000000000000000004321476061725400154320ustar00rootroot00000000000000#ifndef INC_1OOM_UTIL_CSTR_H #define INC_1OOM_UTIL_CSTR_H #include #include "types.h" extern int util_cstr_parse(const char *str, char *dst, uint32_t *len_out); extern int util_cstr_out(FILE *fd, const char *str); extern int util_cstr_parse_in_place(char *str); #endif 1oom-1.11.2/src/util_math.c000066400000000000000000000214111476061725400154030ustar00rootroot00000000000000#include "config.h" #include #include "util_math.h" #include "log.h" #include "types.h" /* ------------------------------------------------------------------------- */ /* floor(0x100 * tan((2 * PI * (i + FIRST)) / 360)) */ static const uint8_t tbl_math_tan_0[] = { 0x00,0x04,0x08,0x0d,0x11,0x16,0x1a,0x1f,0x23,0x28,0x2d,0x31,0x36,0x3b,0x3f,0x44,0x49,0x4e,0x53,0x58,0x5d,0x62 }; static const uint8_t tbl_math_tan_22[] = { 0x67,0x6c,0x71,0x77,0x7c,0x82,0x88,0x8d,0x93,0x99,0x9f,0xa6,0xac,0xb3,0xb9,0xc0,0xc8,0xcf,0xd6,0xde,0xe6,0xee,0xf7 }; static const uint16_t tbl_math_tan_45[] = { 0x0100,0x0109,0x0112,0x011c,0x0126,0x0131,0x013c,0x0147,0x0153,0x0160,0x016d,0x017b,0x018a,0x0199,0x01aa,0x01bb, 0x01cd,0x01e1,0x01f6,0x020c,0x0224,0x023e }; static const uint16_t tbl_math_tan_67[] = { 0x025b,0x0279,0x029a,0x02bf,0x02e7,0x0313,0x0345,0x037c,0x03bb,0x0402,0x0454,0x04b4,0x0525,0x05ab,0x0650,0x071d, 0x0825,0x0983,0x0b6e,0x0e4d,0x1315,0x1ca3,0x394d }; /* The values of these two differ slightly, probably not important */ static const uint16_t tbl_math_sin[] = { 0x0000,0x0477,0x08ef,0x0d65,0x11db,0x164f,0x1ac2,0x1f32,0x23a0,0x280c,0x2c74,0x30d8,0x3539,0x3996,0x3dee,0x4242, 0x4690,0x4ad8,0x4f1b,0x5358,0x578e,0x5bbe,0x5fe6,0x6407,0x681f,0x6c30,0x7039,0x7438,0x782f,0x7c1c,0x8000,0x83d9, 0x87a8,0x8b6d,0x8f27,0x92d5,0x9679,0x9a10,0x9d9c,0xa11b,0xa48d,0xa7f3,0xab4c,0xae97,0xb1d5,0xb505,0xb826,0xbb3a, 0xbe3e,0xc134,0xc41b,0xc6f3,0xc9bb,0xcc73,0xcf1b,0xd1b4,0xd43b,0xd6b3,0xd919,0xdb6f,0xddb3,0xdfe7,0xe208,0xe419, 0xe617,0xe803,0xe9de,0xeba6,0xed5b,0xeeff,0xf08f,0xf20d,0xf378,0xf4d0,0xf615,0xf746,0xf865,0xf970,0xfa67,0xfb4b, 0xfc1c,0xfcd9,0xfd82,0xfe17,0xfe99,0xff06,0xff60,0xffa6,0xffd8,0xfff6 }; static const uint16_t tbl_math_cos[] = { 0xfff6,0xffd8,0xffa6,0xff60,0xff06,0xfe98,0xfe17,0xfd82,0xfcd9,0xfc1c,0xfb4b,0xfa67,0xf970,0xf865,0xf746,0xf615, 0xf4d0,0xf378,0xf20d,0xf08f,0xeeff,0xed5b,0xeba6,0xe9de,0xe803,0xe617,0xe418,0xe208,0xdfe7,0xddb3,0xdb6f,0xd919, 0xd6b3,0xd43b,0xd1b3,0xcf1b,0xcc73,0xc9bb,0xc6f2,0xc41b,0xc134,0xbe3e,0xbb39,0xb826,0xb504,0xb1d5,0xae97,0xab4c, 0xa7f3,0xa48d,0xa11b,0x9d9b,0x9a10,0x9678,0x92d5,0x8f27,0x8b6d,0x87a8,0x83d9,0x7fff,0x7c1c,0x782f,0x7438,0x7038, 0x6c30,0x681f,0x6406,0x5fe6,0x5bbd,0x578e,0x5358,0x4f1b,0x4ad8,0x468f,0x4241,0x3dee,0x3996,0x3539,0x30d8,0x2c73, 0x280b,0x23a0,0x1f32,0x1ac2,0x164f,0x11db,0x0d65,0x08ee,0x0477,0x0000 }; /* ------------------------------------------------------------------------- */ static int calc_angle_do(unsigned int dx, unsigned int dy) { unsigned int slope; int angle; if (dx == 0) { return 90; } slope = (dy << 8) / dx; if (slope < 0x100) { if (slope >= 0x67) { angle = 22; for (int i = 0; i < 0x17; ++i) { if (slope < tbl_math_tan_22[i]) { goto out2; } ++angle; } angle = 44; out2: --angle; } else { angle = 0; for (int i = 0; i < 0x16; ++i) { if (slope < tbl_math_tan_0[i]) { goto out1; } ++angle; } angle = 22; out1: --angle; } } else { if (slope >= 0x258) { angle = 0; for (int i = 0; i < 0x17; ++i) { if (slope < tbl_math_tan_67[i]) { goto out4; } ++angle; } return 90; out4: --angle; angle += 67; } else { angle = 0; for (int i = 0; i < 0x16; ++i) { if (slope < tbl_math_tan_45[i]) { goto out3; } ++angle; } return 66; out3: --angle; angle += 45; } } #ifdef FEATURE_MODEBUG if ((angle < 0) || (angle >= 180)) { LOG_DEBUG((3, "%s: dx:%i dy:%i -> slope:%i angle:%i\n", dx, dy, slope, angle)); } #endif return angle; } static inline int util_math_route_step_len(int adx, int ady) { int v = adx + ady; return v ? (v + 1) : 3; } /* ------------------------------------------------------------------------- */ int util_math_calc_angle(int dx, int dy) { if (dx >= 0) { if (dy >= 0) { return calc_angle_do(dx, dy); } else { return 360 - calc_angle_do(dx, -dy); } } else { if (dy >= 0) { return 180 - calc_angle_do(-dx, dy); } else { return 180 + calc_angle_do(-dx, -dy); } } } int util_math_angle_dist_cos(int angle, int dist) { int res = 0; bool negate = false; if (angle < 91) { /* nop */ } else if (angle < 181) { angle = 180 - angle; negate = true; } else if (angle < 271) { angle -= 180; negate = true; } else { angle = 360 - angle; } if (angle == 0) { res = dist; } else { res = (dist * tbl_math_cos[angle - 1]) / 0x10000; } if (negate) { res = -res; } return res; } int util_math_angle_dist_sin(int angle, int dist) { int res = 0; bool negate = false; if (angle < 91) { /* nop */ } else if (angle < 181) { angle = 180 - angle; } else if (angle < 271) { angle -= 180; negate = true; } else { angle = 360 - angle; negate = true; } if (angle == 90) { res = dist; } else { res = (dist * tbl_math_sin[angle]) / 0x10000; } if (negate) { res = -res; } return res; } void util_math_go_line_dist(int *x0ptr, int *y0ptr, int x1, int y1, int dist) { int x, y, dx, dy, angle; if (dist <= 0) { return; } x = *x0ptr; y = *y0ptr; if ((x == x1) && (y == y1)) { return; } dx = x1 - x; dy = y1 - y; if ((abs(dx) > 0xff) || (abs(dy) > 0xff)) { dx /= 2; dy /= 2; } angle = util_math_calc_angle(dx, dy); x += util_math_angle_dist_cos(angle, dist); if (dx >= 0) { if (x > x1) { x = x1; } } else { if (x < x1) { x = x1; } } y += util_math_angle_dist_sin(angle, dist); if (dy >= 0) { if (y > y1) { y = y1; } } else { if (y < y1) { y = y1; } } *x0ptr = x; *y0ptr = y; } int util_math_dist_steps(int x0, int y0, int x1, int y1) { int x, y, num = 0; x = x0; y = y0; while ((x != x1) || (y != y1)) { util_math_go_line_dist(&x, &y, x1, y1, 5); if ((x != x1) || (y != y1)) { util_math_go_line_dist(&x, &y, x1, y1, 6); } ++num; } return num; } int util_math_dist_fast(int x0, int y0, int x1, int y1) { int dx, dy; dx = x1 - x0; if (dx < 0) { dx = -dx; } dy = y1 - y0; if (dy < 0) { dy = -dy; } return (dx > dy) ? (dx + dy / 2) : (dy + dx / 2); } int util_math_dist_maxabs(int x0, int y0, int x1, int y1) { int dx, dy; dx = x1 - x0; if (dx < 0) { dx = -dx; } dy = y1 - y0; if (dy < 0) { dy = -dy; } return (dx > dy) ? dx : dy; } int util_math_line_plot(int x0, int y0, int x1, int y1, int *tblx, int *tbly) { int len = 0, dx, dy, dirx, diry, slope, zerr = 0x8000; dx = x1 - x0; if (dx < 0) { dx = -dx; dirx = -1; } else { dirx = 1; } dy = y1 - y0; if (dy < 0) { dy = -dy; diry = -1; } else { diry = 1; } if (dx < dy) { slope = (dx << 16) / dy; while (len < dy) { y0 += diry; zerr += slope; if (zerr >= 0x10000) { x0 += dirx; } zerr &= 0xffff; tblx[len] = x0; tbly[len] = y0; ++len; } } else if (dy < dx) { slope = (dy << 16) / dx; while (len < dx) { x0 += dirx; zerr += slope; if (zerr >= 0x10000) { y0 += diry; } zerr &= 0xffff; tblx[len] = x0; tbly[len] = y0; ++len; } } else { while (len < dy) { x0 += dirx; y0 += diry; tblx[len] = x0; tbly[len] = y0; ++len; } } return len; } int util_math_get_route_len(int x0, int y0, const int *tblx, const int *tbly, int len) { int l; l = util_math_route_step_len(abs(x0 - tblx[0]), abs(y0 - tbly[0])); for (int i = 1; i < len; ++i) { l += util_math_route_step_len(abs(tblx[i - 1] - tblx[i]), abs(tbly[i - 1] - tbly[i])); } return l; } 1oom-1.11.2/src/util_math.h000066400000000000000000000012661476061725400154160ustar00rootroot00000000000000#ifndef INC_1OOM_UTIL_MATH_H #define INC_1OOM_UTIL_MATH_H extern int util_math_calc_angle(int dx, int dy); extern int util_math_angle_dist_cos(int angle, int dist); extern int util_math_angle_dist_sin(int angle, int dist); extern void util_math_go_line_dist(int *x0ptr, int *y0ptr, int x1, int y1, int dist); extern int util_math_dist_steps(int x0, int y0, int x1, int y1); extern int util_math_dist_fast(int x0, int y0, int x1, int y1); extern int util_math_dist_maxabs(int x0, int y0, int x1, int y1); extern int util_math_line_plot(int x0, int y0, int x1, int y1, int *tblx, int *tbly); extern int util_math_get_route_len(int x0, int y0, const int *tblx, const int *tbly, int len); #endif 1oom-1.11.2/src/version.h000066400000000000000000000001231476061725400151040ustar00rootroot00000000000000#ifndef INC_1OOM_VERSION_H #define INC_1OOM_VERSION_H #include "version.inc" #endif1oom-1.11.2/src/version.sh000066400000000000000000000006421476061725400152750ustar00rootroot00000000000000#!/bin/sh TOPSRCDIR=$1 OUTFILE=$2 GIT=$3 VERSION1OOM=$4 if test x$GIT != "xno" && test -d $TOPSRCDIR/.git then VERSIONSTR=`$GIT -C $TOPSRCDIR describe --tags` else VERSIONSTR=$VERSION1OOM fi OUTSTR="#define VERSION_STR \"$VERSIONSTR\"" if test ! -e $OUTFILE then echo $OUTSTR > $OUTFILE exit fi CURSTR=`cat $OUTFILE` if test "$OUTSTR" != "$CURSTR" then echo $OUTSTR > $OUTFILE fi